1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/rcore-os-rCore-Tutorial

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
part-4.md 6.7 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 29.11.2024 21:14 7f8a4fd

Файловая система

Ранее мы загружали QEMU и при этом использовали образ диска, который был упакован с помощью инструмента rcore-fs-fuse. Этот инструмент позволяет упаковывать файлы из каталога в файловую систему и затем упаковывает эту файловую систему в образ диска. Затем этот образ диска монтируется как устройство в QEMU, где он эмулируется как блочное устройство.

Simple File System

Поскольку файловая система сама по себе довольно обширна, мы используем модуль rcore-fs, который предоставляет множество форматов файловых систем. Мы выбираем самую простую файловую систему — Simple File System (именно поэтому идентификатор устройства в QEMU называется «sfs»). Подробности о файловой системе здесь не раскрываются, можно обратиться к анализу предыдущих разработчиков (../files/rcore-fs-analysis.pdf).

Однако для использования этого модуля необходимо получить доступ к корневому каталогу INode (INode представляет собой абстракцию местоположения файла, а каталог также является разновидностью файла). Все последующие операции с файловой системой могут быть выполнены через корневой каталог.

Реализация

Здесь мы используем наш старый друг lazy_static, который будет инициализирован при первом использовании ROOT_INODE. Инициализация заключается в поиске первого блочного устройства среди всех устройств драйверов.

lazy_static! {
    /// Корневой каталог INode файловой системы
    pub static ref ROOT_INODE: Arc<dyn INode> = {
        // Выбираем первое блочное устройство
        for driver in DRIVERS.read().iter() {
            if driver.device_type() == DeviceType::Block {
                let device = BlockDevice(driver.clone());
                // Динамически выделяем память для устройства Cache
                let device_with_cache = Arc::new(BlockCache::new(device, BLOCK_CACHE_CAPACITY));
                return SimpleFileSystem::open(device_with_cache)
                    .expect("failed to open SFS")
                    .root_inode();
            }
        }
        panic!("failed to load fs")
    };
}

Также стоит отметить, что мы добавили BlockCache, модуль, предоставляемый rcore-fs. Он предоставляет абстракцию кэша для хранения данных на устройстве и может быть преобразован в устройство с кэшем с помощью вызова BlockCache::new (device, BLOCK_CACHE_CAPACITY). Наконец, мы можем открыть и вернуть корневой узел с помощью SimpleFileSystem::open.

Тестирование

Наконец, мы подошли к волнующему этапу тестирования! Сначала мы запускаем инициализацию ROOT_INODE, а затем пытаемся вывести содержимое корневого каталога:

/// Выводит все файлы в каталоге
pub fn ls(path: &str) {
    let mut id = 0;
    let dir = ROOT_INODE.lookup(path).unwrap();
    print!("files in {}: \n  ", path);
    while let Ok(name) = dir.get_entry(id) {
        id += 1;
        print!("{} ", name);
    }
    print!("\n");
}

/// Запускает инициализацию [`static@ROOT_INODE`] и выводит содержимое корневого каталога
pub fn init() {
    ls("/");
    println!("mod fs initialized");
}

В конце основной функции мы тестируем инициализацию, а затем тестируем создание папки в другом потоке ядра. Это делается для проверки операций, связанных с таблицами страниц, которые мы обсуждали ранее в контексте написания драйверов:

/// Функция входа в Rust
///
/// После того как `_start` выполнит ряд подготовительных действий, это первая вызываемая функция Rust
#[no_mangle]
pub extern "C" fn rust_main(_hart_id: usize, dtb_pa: PhysicalAddress) -> ! {
    memory::init();
    interrupt::init();
    drivers::init(dtb_pa);
    fs::init();

    let process = Process::new_kernel().unwrap();

    PROCESSOR
        .lock()
        .add_thread(Thread::new(process.clone(), simple as usize, Some(&[0])).unwrap());

    // Отбрасываем лишнюю ссылку на процесс
    drop(process);

    PROCESSOR.lock().run()
}

/// Тестирует возможность работы любого потока ядра с файловой системой и драйверами
fn simple(id: usize) {
    println!("hello from thread id {}", id);
    // Создаём новую папку
    fs::ROOT_INODE
        .create("tmp", rcore_fs::vfs::FileType::Dir, 0o666)
        .expect("failed to mkdir /tmp");
    // Выводим содержимое корневого файла
    fs::ls("/");

    loop {}
}

После выполнения make run вы получите аналогичный вывод:

mod memory initialized
mod interrupt initialized
mod driver initialized
files in /:
  . .. temp rust
mod fs initialized
hello from thread id 0
files in /:
  . .. temp rust tmp
100 tick
200 tick
...

Успех! Система правильно считывает файлы и корректно создаёт файлы, обеспечивая хорошую защиту для последующего размещения данных пользовательских процессов.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/rcore-os-rCore-Tutorial.git
git@api.gitlife.ru:oschina-mirror/rcore-os-rCore-Tutorial.git
oschina-mirror
rcore-os-rCore-Tutorial
rcore-os-rCore-Tutorial
master