Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

Adaptation of the system V/386 Filesystem for Linux

Paul b.Monday

Документ написан в далеком 1993 году

В документе описывается базовые понятия юниксовой VFS - виртуальной файловой системы и ее реализация в Линукс.

Любая ось предоставляет обычно несколько вариантов для выбора файловой системы. В линуксе файловая система имеет набор высокоуровневых и низкоуровневых функций. Каждая файловая система имеет похожий набор функций . Добавление новой файловой системы в линуксе упрощено. Мы рассмотрим , как это реализовано с помощью VFS.

Рассмотрим , как организован диск.
1. Сектор 1 : bootblock.
2. Сектор 2 : superblock.
3. Сектора с 3 по х: Испорченые блоки - bad blocks
4. Сектора с x+1 по y : ноды
5. Сектора с y+1 по z : блоки данных

Суперблок - сектор размером в 512 байт. Его содержание динамически меняется. Его структура :
offset 0(isize) : число блоков в списке нод
offset 2(fsize) : число блоков
offset 6(nfree) : число свободных адресов в кеше
offset 8(free) : кеш свободных блоков
offset 208(ninode) : число нод в кеше
offset 210(inode) : нодовый кеш
offset 410 : блокировочный бит (для манипуляций с блоковым кешем)
offset 411 : блокировочный бит (для манипуляций с нодовым кешем)
offset 412 : флаг модификации
offset 413 : флаг на чтение
offset 414(time) : время последней модификации супер-блока
offset 418 : информация о монтировании
offset 426 : общее число свободных блоков
offset 430 : общее число свободных нод
offset 432 : имя файловой системы
offset 438 : имя файловой системы
offset 444 : размер файловой системы
offset 492 : state
offset 496 : magic number
offset 500 : тип файловой системы

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

При создании файловой системы, свободные блоки организуются в связанную структуру. В блоковом кеше хранится 50 адресов. Алгоритм выделения блоков следующий :

 	if tfree=0 then return false
 	if nfree=0 and tfree=1 then
 		address = free[0]
 		чтение блока по адресу address
 		перевод массива free[0-49] в массив block[0-49]
 	else
 		address = free[nfree]
 		nfree   = nfree - 1
 	return address
 
Алгоритм освобождения блоков :
 	if nfree = 50 then
 		читаем блок по адресу address
 		пишем 50 адресов из free в block
 		nfree=1
 		free[0] = address
 	else
 		free[nfree] = address
 		nfree = nfree + 1
 	tfree = tfree + 1
 	return
 
Здесь возникает проблема со скоростью доступа к диску. Периодически происходит доступ на запись к суперблоку между выделением блоков. Другой сценарий : перезагружать кеш для каждого выделение блоков , что не является красивым и правильным решением.

Список свободных нод очень похож на список свободных блоков. Ноды сами по себе отличаются от блоков данных. Свободные ноды не связаны между собой так , как блоки данных. Когда приходит время перезагрузки нодового кеша , он заполняется 100 свободныит нодами. В ноде есть поле nlink=0 , что говорит о том , что нода готова к использованию и свободна.

Ключ в понимании файловой системы лежит в понимании внутренней структуры ноды. Многие поля нодовой структуры VFS аналогичны линуксовой ноде. Юниксовая файловая система имеет несколько уровней абстрации для того , чтобы оперировать различными типами файловых систем. Например , если поле ноды имеет значение 0x4000 , это означает каталог , и это справедливо для любой юниксовой файловой системы. Рассмотрим подробнее линуксовую ноду :

  offset 0(mode): режим и тип файла (*)
  offset 2(nlink): число линков на файл (*)
  offset 4(uid): File owner's userid (*)
  offset 6(gid): File's group id (*)
  offset 8(size): Size, in bytes, of the file (*)
  offset 12(addr): Disk block addresses
  offset 51(gen): File's generation number (*)
  offset 52(atime): Last time file accessed (*)
  offset 56(mtime): Last time fle modified (*)
  offset 60(ctime): File creation time (*)
 
Адрес файла хранится в 3-байтовом формате , что позволяет иметь размер файла до 34646 КБ. Этот формат может иметь и другой вариант - 4-х байтовый , в этом случае нода будет указывать на дисковое пространство размером в 16777216 КБ.

Следующий рисунок показывает , как организована адресация блоков внутри ноды.
Direct-блоки контролируются байтами с 0 по 26-й в поле addr. Показано , как различные уровни адресации связаны с блоками. Каждый indirect-блок дает дополнительно по 32 блока для файла. Double-блоки расширяют размер файла на 1024 блока и triple indirect блоки дают дополнительно по 32768 блоков. Адреса хранятся как long integers в inderect-блоках.

Блоки каталогов - directory blocks - похожи во многих файловых юниксовых системах. Эти блоки заполнены номером ноды и именем файла. Запись ссылается на ноду , которая может включать любой тип файла - каталог , данные , симлинк и т.д. Имя файла может состоять из 14 символов. На предыдущей картинке видно , как directory block работает с нодой. Отличие директории от файла - в том , что хранится в поле mode.

Linux

Исходники VFS лежат в каталоге /fs. Для каждого типа файловой системы тут есть свой подкаталог, например , fs/ext2/ В следующей таблице представлен список некоторых исходников этого каталога. Средний столбик - system - означает следующее : EXE - используется для загрузки исполняемых файлов , DEV - поддерживает драйвер , BUF - кеш буфера , VFS - базовй код для всех файловых систем.
FilenamesystemPurpose
binfmt_aout.cEXERecognize and execute old-style a.out executables.
binfmt_elf.cEXERecognize and execute new ELF executables
binfmt_java.cEXERecognize and execute Java apps and applets
binfmt_script.cEXERecognize and execute #!-style scripts
block_dev.cDEVGeneric read(), write(), and fsync() functions for block devices.
buffer.cBUFThe buffer cache, which caches blocks read from block devices.
dcache.cVFSThe directory cache, which caches directory name lookups.
devices.cDEVGeneric device support functions, such as registries.
dquot.cVFSGeneric disk quota support.
exec.cVFSgGeneric executable support. Calls functions in the binfmt_* files.
fcntl.cVFSgfcntl() handling.
fifo.cVFSgfifo handling.
file_table.cVFSgDynamically-extensible list of open files on the system.
filesystems.cVFSAll compiled-in filesystems are initialized from here by calling init_name_fs().
inode.cVFSgDynamically-extensible list of open inodes on the system.
ioctl.cVFSFirst-stage handling for ioctl's; passes handling to the filesystem or device driver if necessary.
locks.cVFSgSupport for fcntl() locking, flock() locking, and manadatory locking.
namei.cVFSFills in the inode, given a pathname. Implements several name-related system calls.
noquot.cVFSNo quotas: optimization to avoid #ifdef's in dquot.c
open.cVFSLots of system calls including (surprise) open(), close(), and vhangup().
pipe.cVFSgPipes.
read_write.cVFSread(), write(), readv(), writev(), lseek().
readdir.cVFSSeveral different interfaces for reading directories.
select.cVFSThe guts of the select() system call
stat.cVFSstat() and readlink() support.
super.cVFSSuperblock support, filesystem registry, mount()/umount().
Загрузка файловой системы происходит следующим образом : в каждом под-каталоге для каждой файловой системы есть шаблон вызова типа init_name_fs(), например для ext2 :

   int init_ext2_fs(void)
    {
            return register_filesystem(&ext2_fs_type);
    }
 
Зарегистрировать файловую систему можно так :
 	static struct file_system_type ext2_fs_type = 
    {
            ext2_read_super, "ext2", 1, NULL
    };
 
Можно зарегистрировать более чем одну файловую систему :
    static struct file_system_type sysv_fs_type[3] = {
            {sysv_read_super, "xenix", 1, NULL},
            {sysv_read_super, "sysv", 1, NULL},
            {sysv_read_super, "coherent", 1, NULL}
    };
 
    int init_sysv_fs(void)
    {
            int i;
            int ouch;
    
            for (i = 0; i < 3; i++) {
                    if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0)
                            return ouch;
            }
            return ouch;
    }
 
Связь между файловой системой и ядром осуществляется через device. Когда монтируется драйер , включающий в себя например ext2 , вызывается ext2_read_super(). Если супер-блок прочитан , происходит инициализации структуры super_block , в которую добавляется указатель на новую структуру super_operations, уже в которой находятся указатели на функции.

Суперблок - это блок , в котором находится стартовая точка файловой системы. В структуре super_operations находятся указатели на функции , которые манипулируют нодами , самим суперблоком .

Вариант того , как может выглядеть super_operations :

  struct super_operations {
            void (*read_inode) (struct inode *);
            int (*notify_change) (struct inode *, struct iattr *);
            void (*write_inode) (struct inode *);
            void (*put_inode) (struct inode *);
            void (*put_super) (struct super_block *);
            void (*write_super) (struct super_block *);
            void (*statfs) (struct super_block *, struct statfs *, int);
            int (*remount_fs) (struct super_block *, int *, char *);
    };
 
А вот как может выглядеть инстанс этой структуры для ext2 :
   static struct super_operations ext2_sops = {
            ext2_read_inode,
            NULL,
            ext2_write_inode,
            ext2_put_inode,
            ext2_put_super,
            ext2_write_super,
            ext2_statfs,
            ext2_remount
    };
 
Обратите внимание , что некоторые поля структуры могут быть NULL. Для линукса это в порядке вещей :-)

Функция , которая инит суперблок в Линуксе , называется sysv_read_super. Каждая файловая система имеет соответствующую функцию. Эта функция сканирует суперблок и грузит его в память. Наиболее важные поля линуксового супер-блока :

 1. offset 0(dev): точка отсчета супер-блока
 2. offset 2(blocksize): Blocksize of blocks on device
 3. offset 6(lock): бит блокировке , когда суперблок используется
 4. offset 7(rdonly): бит - только на чтение 
 5. offset 8(dirt): бит устанавливается в1 при изменении супер-блока
 6. offset 9(superop): указатель на структуру ,указывающую на типы операций с файловой системой
 7. offset 13(ags): флаги fs , устанавливаемые при монтировании
 8. offset 17(magic): Magic number for flesystem
 9. offset 23(time): время монтирования
 10. offset 27(covered): Pointer to inode of flesystem which was written over
 11. offset 31(mounted): Pointer to root directory inode
 12. offset 35(wait): Pointer to wait queue for superblock operations
 13. offset 39(u): указатель на супер-блоки других примонтированных ФС
 
Заметим , что линуксовый супер-блок является одновременно контейнером для других суперблоков. Структуры данных различных ФС в суперблоке заполняются в момент инициализации этих файловых систем.

После загрузки супер-блока мы имеем указатель на него в процедуре read_super. При этом суперблок сразу блокируется.При этом :
1. read_super напрямую читает диск , сканирует 0-й блок и грузит его в память
2. Инится указатель на суперблок (смещение 512)
3. Проверка magic number
4. Читается корневая нода с диска и сохраняется в суперблоке в памяти.
5. В суперблок пишутся ряд параметров - время и т.д.

После возвращения из read_super суперблок хранит в себе размер блока , magic number , и указатели на функции файловой системы,рутовую ноду ,

При монтировании файловой системы , вызывается функция ext2_read_super() , которая читает супер-блок. Структура super_block заполняется указателями на функции , специфичные для ext2.

В каком месте происходит монтирование файловой системы ? Взгляните на fs/super.c , функцию do_umount() , в которой в свою очередь вызывается read_super(), которая в свою очередь вызывает ext2_read_super(),которая возвращает супер-блок.

После монтирования мы имеем возможность получить доступ к файлу. Для этого сначала нужно найти нужную ноду , а потом получить доступ к ней. При поиске VFS оперирует путем , включающим слеши. Это может быть как файл , так и директория. В случае успеха , вернется inode number - уникальный номер ноды .

Следующий рисунок показывает структуру ноды ext2:

Далее вызывается namei() для трансформации номера в реальный путь. Далее с помощью iget() можно получить содержимое самой этой ноды. Функция iput() может модифицировать ноду. Она хранит reference count , который говорит о том , занята нода или нет.

В супер-блоке есть указатель s_mounted на особую ноду , которая указывает на рутовый каталог файловой системы. Все остальные ноды ищутся и пляшут именно от нее.

Каждая нода , являясь сама структурой , включает вложенную структуру inode_operations, которая заполнена указателями на функции.Например , функция lookup() ищет другую ноду.

Линуксовые файловые системы имеют модульную структуру. Линукс поддерживает фат,миникс,несколько типов ext и много чего еще. После монтирования файловая система работает с помощью буферов данных. Линуксовая VFS - это гибрид традиционной юниксовой VFS , основанный на буферизации.

Следующий рисунок показывает , что происходит при чтении супер-блока.
Периодически возникает необходимость сохранения супер-блока на диск. Это делает процедура sysv_write_sb.При этом :
1. Читаем 0-й блок суперблока в памяти
2. Находим смещение 512
3. Копируем время в буфер
4. Изменяем поля , отвечающие за кеш - free,inode,nfree,ninode
5. Делаем апдэйт для total free inodes , total free blocks
6. Маркируем буффер как dirty
7. Пишем буфер на диск
8. Отменяем атрибут dirty

Для добавления новой файловой системы в ядре при конфигурировании нужно модифицировать как минимум следующее :
1. Файл fs/filesystems.c - структура file_systems хранится в хидере fs.h. Когда запускается read_super , в нее передается список монтируемых систем
2. include/linux/fs.h - во все структуры должны быть добавлены указатели на структуры добавляемой файловой системы
3. fs/Makefile

VFS :

Монтирование файловой системы :

Buffer cache :

Файловые системы в Линукс :

Базовые файловые структуры данных в Линукс :

Устройство ноды :

Устройство ноды :

Состояния ноды :

Яковлев С : Ниже я взял базовые структуры из своего текущего ядра 2.6.16.


 include/linux/fs.h
 
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
 	struct list_head	i_sb_list;
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
 	umode_t			i_mode;
 	unsigned int		i_nlink;
 	uid_t			i_uid;
 	gid_t			i_gid;
 	dev_t			i_rdev;
 	loff_t			i_size;
 	struct timespec		i_atime;
 	struct timespec		i_mtime;
 	struct timespec		i_ctime;
 	unsigned int		i_blkbits;
 	unsigned long		i_blksize;
 	unsigned long		i_version;
 	unsigned long		i_blocks;
 	unsigned short          i_bytes;
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	struct mutex		i_mutex;
 	struct rw_semaphore	i_alloc_sem;
 	struct inode_operations	*i_op;
 	struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
 	struct super_block	*i_sb;
 	struct file_lock	*i_flock;
 	struct address_space	*i_mapping;
 	struct address_space	i_data;
 #ifdef CONFIG_QUOTA
 	struct dquot		*i_dquot[MAXQUOTAS];
 #endif
 	/* These three should probably be a union */
 	struct list_head	i_devices;
 	struct pipe_inode_info	*i_pipe;
 	struct block_device	*i_bdev;
 	struct cdev		*i_cdev;
 	int			i_cindex;
 
 	__u32			i_generation;
 
 #ifdef CONFIG_DNOTIFY
 	unsigned long		i_dnotify_mask; /* Directory notify events */
 	struct dnotify_struct	*i_dnotify; /* for directory notifications */
 #endif
 
 #ifdef CONFIG_INOTIFY
 	struct list_head	inotify_watches; /* watches on this inode */
 	struct semaphore	inotify_sem;	/* protects the watches list */
 #endif
 
 	unsigned long		i_state;
 	unsigned long		dirtied_when;	/* jiffies of first dirtying */
 
 	unsigned int		i_flags;
 
 	atomic_t		i_writecount;
 	void			*i_security;
 	union {
 		void		*generic_ip;
 	} u;
 #ifdef __NEED_I_SIZE_ORDERED
 	seqcount_t		i_size_seqcount;
 #endif
 };
 
 
 
 
 struct file {
 	/*
 	 * fu_list becomes invalid after file_free is called and queued via
 	 * fu_rcuhead for RCU freeing
 	 */
 	union {
 		struct list_head	fu_list;
 		struct rcu_head 	fu_rcuhead;
 	} f_u;
 	struct dentry		*f_dentry;
 	struct vfsmount         *f_vfsmnt;
 	struct file_operations	*f_op;
 	atomic_t		f_count;
 	unsigned int 		f_flags;
 	mode_t			f_mode;
 	loff_t			f_pos;
 	struct fown_struct	f_owner;
 	unsigned int		f_uid, f_gid;
 	struct file_ra_state	f_ra;
 
 	unsigned long		f_version;
 	void			*f_security;
 
 	/* needed for tty driver, and maybe others */
 	void			*private_data;
 
 #ifdef CONFIG_EPOLL
 	/* Used by fs/eventpoll.c to link all the hooks to this file */
 	struct list_head	f_ep_links;
 	spinlock_t		f_ep_lock;
 #endif /* #ifdef CONFIG_EPOLL */
 	struct address_space	*f_mapping;
 };
 
 
 
 
 struct super_block {
 	struct list_head	s_list;		/* Keep this first */
 	dev_t			s_dev;		/* search index; _not_ kdev_t */
 	unsigned long		s_blocksize;
 	unsigned char		s_blocksize_bits;
 	unsigned char		s_dirt;
 	unsigned long long	s_maxbytes;	/* Max file size */
 	struct file_system_type	*s_type;
 	struct super_operations	*s_op;
 	struct dquot_operations	*dq_op;
  	struct quotactl_ops	*s_qcop;
 	struct export_operations *s_export_op;
 	unsigned long		s_flags;
 	unsigned long		s_magic;
 	struct dentry		*s_root;
 	struct rw_semaphore	s_umount;
 	struct mutex		s_lock;
 	int			s_count;
 	int			s_syncing;
 	int			s_need_sync_fs;
 	atomic_t		s_active;
 	void                    *s_security;
 	struct xattr_handler	**s_xattr;
 
 	struct list_head	s_inodes;	/* all inodes */
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
 	struct list_head	s_files;
 
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
 	struct quota_info	s_dquot;	/* Diskquota specific options */
 
 	unsigned int		s_prunes;	/* protected by dcache_lock */
 	wait_queue_head_t	s_wait_prunes;
 
 	int			s_frozen;
 	wait_queue_head_t	s_wait_unfrozen;
 
 	char s_id[32];				/* Informational name */
 
 	void 			*s_fs_info;	/* Filesystem private info */
 
 	/*
 	 * The next field is for VFS *only*. No filesystems have any business
 	 * even looking at it. You had been warned.
 	 */
 	struct semaphore s_vfs_rename_sem;	/* Kludge */
 
 	/* Granuality of c/m/atime in ns.
 	   Cannot be worse than a second */
 	u32		   s_time_gran;
 };
 
 
 
 
 
 
 struct file_system_type {
 	const char *name;
 	int fs_flags;
 	struct super_block *(*get_sb) (struct file_system_type *, int,
 				       const char *, void *);
 	void (*kill_sb) (struct super_block *);
 	struct module *owner;
 	struct file_system_type * next;
 	struct list_head fs_supers;
 };
 
 
 
 
 
 struct file_operations {
 	struct module *owner;
 	loff_t (*llseek) (struct file *, loff_t, int);
 	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 	ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
 	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 	ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
 	int (*readdir) (struct file *, void *, filldir_t);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
 	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
 	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
 	int (*mmap) (struct file *, struct vm_area_struct *);
 	int (*open) (struct inode *, struct file *);
 	int (*flush) (struct file *);
 	int (*release) (struct inode *, struct file *);
 	int (*fsync) (struct file *, struct dentry *, int datasync);
 	int (*aio_fsync) (struct kiocb *, int datasync);
 	int (*fasync) (int, struct file *, int);
 	int (*lock) (struct file *, int, struct file_lock *);
 	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
 	ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
 	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 	int (*check_flags)(int);
 	int (*dir_notify)(struct file *filp, unsigned long arg);
 	int (*flock) (struct file *, int, struct file_lock *);
 #define HAVE_FOP_OPEN_EXEC
 	int (*open_exec) (struct inode *);
 };
 
 
 
 
 
 
 
 struct inode_operations {
 	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
 	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
 	int (*mkdir) (struct inode *,struct dentry *,int);
 	int (*rmdir) (struct inode *,struct dentry *);
 	int (*mknod) (struct inode *,struct dentry *,int,dev_t);
 	int (*rename) (struct inode *, struct dentry *,
 			struct inode *, struct dentry *);
 	int (*readlink) (struct dentry *, char __user *,int);
 	void * (*follow_link) (struct dentry *, struct nameidata *);
 	void (*put_link) (struct dentry *, struct nameidata *, void *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, struct nameidata *);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
 	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
 	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
 	ssize_t (*listxattr) (struct dentry *, char *, size_t);
 	int (*removexattr) (struct dentry *, const char *);
 	void (*truncate_range)(struct inode *, loff_t, loff_t);
 };
 
 
 
 
 
 
 struct super_operations {
    	struct inode *(*alloc_inode)(struct super_block *sb);
 	void (*destroy_inode)(struct inode *);
 
 	void (*read_inode) (struct inode *);
   
    	void (*dirty_inode) (struct inode *);
 	int (*write_inode) (struct inode *, int);
 	void (*put_inode) (struct inode *);
 	void (*drop_inode) (struct inode *);
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
 	int (*sync_fs)(struct super_block *sb, int wait);
 	void (*write_super_lockfs) (struct super_block *);
 	void (*unlockfs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct kstatfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
 	void (*umount_begin) (struct super_block *);
 
 	int (*show_options)(struct seq_file *, struct vfsmount *);
 
 	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
 	ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 };
 
 
 
Файл fs / filesystems.c ;

 /**
  *	register_filesystem - register a new filesystem
  *	@fs: the file system structure
  *
  *	Adds the file system passed to the list of file systems the kernel
  *	is aware of for mount and other syscalls. Returns 0 on success,
  *	or a negative errno code on an error.
  *
  *	The &struct file_system_type that is passed is linked into the kernel 
  *	structures and must not be freed until the file system has been
  *	unregistered.
  */
  
 int register_filesystem(struct file_system_type * fs)
 {
 	int res = 0;
 	struct file_system_type ** p;
 
 	if (!fs)
 		return -EINVAL;
 	if (fs->next)
 		return -EBUSY;
 	INIT_LIST_HEAD(&fs->fs_supers);
 	write_lock(&file_systems_lock);
 	p = find_filesystem(fs->name);
 	if (*p)
 		res = -EBUSY;
 	else
 		*p = fs;
 	write_unlock(&file_systems_lock);
 	return res;
 }
 
 
 
 
 
 int get_filesystem_list(char * buf)
 {
 	int len = 0;
 	struct file_system_type * tmp;
 
 	read_lock(&file_systems_lock);
 	tmp = file_systems;
 	while (tmp && len < PAGE_SIZE - 80) {
 		len += sprintf(buf+len, "%s\t%s\n",
 			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
 			tmp->name);
 		tmp = tmp->next;
 	}
 	read_unlock(&file_systems_lock);
 	return len;
 }
 
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье