8 .8 Linux2.4文件系统的移植问题
Linux 内核源代码2.2.x版本及2.4.x版本之间有一定的变化,我们把 2.2.x版本叫旧版,把2.4.x叫新版。下面给出文件系统的变化:
1.模块处理方式发生了变化
模块的初始化方式有所变化,在旧版本中的初始化方式如下(我们把某个文件系统叫做myfs):
static struct file_system_type myfs_fs_type =
{ "myfs", FS_REQUIRES_DEV, myfs_read_super, NULL };
__initfunc(int init_myfs_fs(void)) {
return register_filesystem(&myfs_fs_type);
}
#ifdef MODULE
EXPORT_NO_SYMBOLS;
int init_module(void) {
return init_myfs_fs();
}
void cleanup_module(void) {
unregister_filesystem(&myfs_fs_type);
}
#endif
另外,MOD_INC_USE_COUN宏在文件系统的read_super()中被调用,而MOD_DEC_USE_COUNT宏在put_super()中被调用。新版中的初始化方法如下:
static DECLARE_FSTYPE_DEV(myfs_fs_type, "myfs", myfs_read_super);
static int __init init_myfs_fs(void) {
return register_filesystem(&myfs_fs_type);
}
static void __exit exit_myfs_fs(void) {
unregister_filesystem(&myfs_fs_type);
}
EXPORT_NO_SYMBOLS;
module_init(init_myfs_fs);
module_exit(exit_myfs_fs);
MOD_XXX_USE_COUNT现在由VFS文件系统在注册时进行处理。从代码可以看出,新版本的处理方式更具可读性,而本质上并没有多大变化。
2 大文件的支持(Large File Support,LFS)
VFS现在支持64位文件(仅适用于x86 和 Sparc平台):
· 使用64位类型loff_t
· 但内核还不支持64位的getrlimit()和setrlimit()系统调用。
· glibc库支持getrlimit64() 和setrlimit64()
3.新的错误处理方式
旧版中错误处理如下:
if (!dir || !dir->i_nlink) {
*err = -EPERM;
return NULL;
}
在新版中,对错误的处理调用了ERR_PTR(), PTR_ERR() 和IS_ERR()函数:
if (!dir || !dir->i_nlink)
return ERR_PTR(-EPERM);
这几个错误处理函数定义于include/linux/fs.h中:
static inline void *ERR_PTR(long error)
{
return (void *) error;
}
static inline long PTR_ERR(const void *ptr)
{
return (long) ptr;
}
static inline long IS_ERR(const void *ptr)
{
return (unsigned long)ptr > (unsigned long)
}
4.inode结构
在旧版中,file_operations在inode_operations结构中定义,而在新版中已移到inode结构中,即:
struct file_operations *i_fop;
其引用形式为:inode->i_fop。
另外,inode中count类型的定义也有所改变:
旧版: int i_count;
新版: atomic_t i_count;
这种类型的定义是与体系结构独立的,因此,对这些变量的访问就是原子操作,例如对变量v的读和设置函数为:
atomic_read(v);
atomic_set(v, value);
这种形式也应用于file 结构 和dentry 结构。
5. dentry 高速缓存
在旧版中,删除一个dentry 的函数形式为:
void (*d_delete)(struct dentry *);
在新版中,删除一个dentry 的函数形式为:
int (*d_delete)(struct dentry *);
返回一个整数表示删除的成功与否。
在旧版中,分配一个根目录项的函数形式为:
struct dentry *d_alloc_root(struct inode *, struct dentry *);
在新版中,分配一个根目录项的函数形式为:
struct dentry *d_alloc_root(struct inode *);
6.VFS 操作
在旧版中,filldir帮助函数的形式为:
typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
在新版中,filldir帮助函数的形式为:
typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t, unsigned);
新增加的参数表示文件类型,其定义于fs.h中
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
7.各种操作结构的指定方式发生变化
所有操作结构的指定方式发生了变化,旧版中的形式为:
struct file_operations myfs_file_operations = {
myfs_file_lseek,
generic_file_read,
generic_file_write,
NULL,
NULL,
myfs_ioctl,
NULL,
};
新版中的形式为:
struct file_operations myfs_file_operations = {
llseek: myfs_file_lseek,
read: generic_file_read,
write: generic_file_write,
ioctl: myfs_ioctl,
};
这种形式使用了GNU C语言的扩展形式,符合ISO C99标准,C99标准指定的初始化者的形式为:
struct foo {
int foo;
long bar;
};
struct foo x = { .bar = 3, .foo = 4 };
8.VFS的file_operations
在fsync()函数中增加了一个新的参数;如果这个参数被设置,则不干预对时间标记的刷新:
旧版: int (*fsync) (struct file *, struct dentry *);
新版: int (*fsync) (struct file *, struct dentry *, int);
另外,原来file_operations中的两个操作:
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
被移到一个新的结构block_device_operations:
struct block_device_operations {
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*ioctl)(struct inode *, struct file *, unsigned, unsigned long);
int (*check_media_change)(kdev_t);
int (*revalidate) (kdev_t);
};
这个新的结构成为inode结构中一个新的域:
新版: struct block_device *i_bdev;
于是在block_device中有一个指向这个操作结构的指针:
struct block_device {
struct list_head bd_hash;
atomic_t bd_count;
dev_t bd_dev;
atomic_t bd_openers;
const struct
block_device_operations *bd_op;
struct semaphore bd_sem;
};
另外,file_operations()中还增加了以下两个函数。在不用保持大内核锁的情况下,所有文件系统都可以调用这两个函数。这两个函数还实现了readv() 和 writev()系统调用。
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
9.VFS的inode_operations
file_operations指针从inode_operations结构移到inode结构。
inode_operations 结构中,follow_link()函数的形式也发生了变化:
旧版中: struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
新版中: int (*follow_link) (struct dentry *, struct nameidata *);
从调用形式可以看出,第一个参数仍然相同,新版参数的nameidata结构中包含了旧版中的最后两个参数:
struct nameidata {
struct dentry *dentry;
struct vfsmount *mnt;
struct qstr last;
unsigned int flags;
int last_type;
};
inode_operations结构中还增加了以下两个函数:
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct dentry *, struct iattr *);
这两个函数(实际上仅仅是setattr())取代了旧版中superblock操作中的notify_change()函数。另外,下列五个函数已经全部被取消:
int (*readpage) (struct file *, struct page *);
int (*writepage) (struct file *, struct page *);
int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int, int);
int (*bmap) (struct inode *,int);
int (*smap) (struct inode *,int);
10.VFS的super_operations
在super_operations结构中,write_inode()函数的形式有所变化:
旧版中: void (*write_inode) (struct inode *);
新版中: void (*write_inode) (struct inode *, int);
新增加的参数是一个布尔标志,用来决定是否把inode同步地写到磁盘。
相反, statfs() 函数中少一个参数,因为statfs 结构的大小是没有必要的。
旧版中: int (*statfs) (struct super_block *, struct statfs *, int);
新版中: int (*statfs) (struct super_block *, struct statfs *);
最后,notify_change()函数被以getattr()和setattr()函数取代。