Linux内核API之文件系统 ========================= vfs_fstat ------------ ``vfs_fstat`` 根据第一个参数fd查找相应的文件,获取文件的属性信息,然后将属性信息保存在函数的第二个参数stat中 :: #include //内核源码kernel/stat.c int vfs_fstat(unsigned int fd, struct kstat *stat) - fd: 文件描述符,与用户态下open打开文件返回值意义相同 - stat: 用于保存文件的基本信息 ``vfs_getattr`` 获取当前虚拟文件系统的属性 :: #include //kernel源码fs/stat.c int vfs_getattr(struct path *path, struct kstat *stat) - path: 虚拟文件系统路径 - stat: 用于保存文件系统信息 :: struct path { struct vfsmount *mnt; struct dentry *dentry; } ``vfs_statfs`` 根据第一个参数dentry获取整个文件系统的一些基本信息,将其保存在第二个参数buf中,此基本信息包括当前文件系统的类型, 文件系统的块数目,文件系统的块大小,文件系统的文件数目,文件系统的文件名长度等信息 :: #include //kenel源码fs/statfs.c int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) struct kstatfs { long f_type; //文件系统的类型 long f_bszie; //文件系统的块大小 u64 f_blocks; //文件系统块的数目 u64 f_bfree; u64 f_avail; //文件系统中可用的块数目 u64 f_files; //文件系统中文件的数目 u64 f_ffree; __kernel_fsid_t f_fsid; long f_namelen; long f_frsize; long f_flags; long f_spare[4]; }; **测试代码** :: #include #include #include #include #include #include static int vfs_statfs_init(void) { struct path path; struct dentry *dentry = NULL; static struct kstatfs buf; struct inode *inode; dentry = current->fs->pwd.dentry; path.dentry = dentry; path.mnt = current->fs->pwd.mnt; inode = dentry->d_inode; vfs_statfs(&path, &buf); printk("f_bsize is :%ld\n", buf.f_bsize); printk("f_frsize is :%ld\n", buf.f_frsize); printk("f_type is :%ld\n", buf.f_type); printk("f_blocks is :%lld\n", buf.f_blocks); printk("f_bfree is :%lld\n", buf.f_bfree); printk("f_bavail is :%lld\n", buf.f_bavail); printk("f_files is :%lld\n", buf.f_files); printk("f_ffree is :%lld\n", buf.f_ffree); printk("f_fsid is :%ld\n", buf.f_fsid); printk("f_namelen is :%ld\n", buf.f_namelen); printk("inode->i_sb->s_dev = %d\n", inode->i_sb->s_dev); printk("inode->i_ino = %d\n", inode->i_ino); printk("inode->i_mode = %d\n", inode->i_mode); printk("inode->i_nlink = %d\n", inode->i_nlink); printk("inode->i_uid = %d\n", inode->i_uid); printk("inode->i_gid = %d\n", inode->i_gid); vfs_getattr(&path, &stat); printk("stat.dev = %d\n", stat.dev); printk("stat.ino = %d\n", stat.ino); printk("stat.mode = %d\n", stat.mode); printk("stat.nlink = %d\n", stat.nlink); printk("stat.uid = %d\n", stat.uid); printk("stat.gid = %d\n", stat.gid); } static void vfs_statfs_exit(void) { return; } module_init(vfs_statfs_init); module_exit(vfs_statfs_exit); current_umask ---------------- ``current_umask`` 用来返回当前文件的权限值掩码 =============================== ============================================================= 掩码  描述 ------------------------------- ------------------------------------------------------------- S_IRWXU 文件所有者具有读写执行权限 S_IRUSR 文件所有者具有读权限 S_IWUSR 文件所有者具有写权限 S_IXUSR 文件所有者具有执行权限 S_IRWXG 用户组具有读写执行权限 S_IRGRP 用户组具有读权限 S_IWGRP 用户组具有写权限 S_IXGRP 用户组具有执行权限 S_IRWXO 其他用户具有读写执行权限 S_IROTH 其他所有用户具有读权限 S_IWOTH 其他所有用户具有写权限 S_IXOTH 其他所有用户具有执行权限 =============================== ============================================================= :: #include //kernel源码fs/fs_struct.c int current_umask(void) ``get_fs_type`` 用于根据输入参数的名字*name, 获取对应文件系统类型的描述符信息 :: #include //kernel源码fs/__filesystems.c struct file_system_type *get_fs_type(const char *name) struct file_system_type { const char *name; //文件系统名 int fs_flags; //文件系统类型标志 #define FS_REQUIRES_DEV 1 #define FS_BINARY_MOUNTDATA 2 #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 #define FS_USERNS_DEV_MOUNT 16 #define FS_RENAME_DOES_D_MOVE 32768 //挂载文件系统的方法 struct dentry *(*mount)(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; //具有相同文件系统类型的超级块对象链表的头 }; ``get_max_files`` 返回在文件系统中可以同时打开的最大文件数目 :: #include //kernel源码fs/file_table.c int get_max_files(void) ``get_super`` 由参数*dev所指定的块设备获取超级块 :: #include //kernel源码fs/super.c struct super_block *get_super(struct block_device *bdev) - bdev: 用来指定所获取的是哪个设备上的超级块 :: struct block_device { dev_t bd_dev; //block_device的搜索编号 int bd_openers; //打开该设备计数器 struct inode *bd_inode; struct super_block *bd_super; //块设备文件系统超级块结构体,用来操作块文件系统 struct mutex bd_mutex; //打开/关闭互斥量 struct list_head bd_inodes; //设备节点链表 void *bd_claiming; void *bd_holder; bool bd_write_holder; #ifdef CONFIG_SYSFS struct list_head bd_holder_list; #endif struct block_device *bd_contains; //含有非分区块结构体 unsigned bd_block_size; //用来描述块大小,在申请队列中进行设置 struct hd_struct *bd_part; //硬件分区结构 unsigned bd_part_count; //被打开设备的分区次数及统计信息 int bd_invalidated; struct gendisk *bd_disk; //虚拟块设备下层的通用磁盘结构 struct request_queue *bd_queue; struct list_head bd_list; unsigned long bd_private; int bd_fsfreeze_count; struct mutex bd_fsfreeze_mutex; }; struct super_block { struct list_head s_list; //指向超级块链表的指针 dev_t s_dev; //设备标识符 unsigned char s_blocksize_bits; //以位为单位的块大小 unsigned long s_blocksize; //以字节为单位的块大小 unsigned long long s_maxbytes; //文件的最大字节数 struct file_system_type *s_type; //文件系统类型 const struct super_operations *s_ops; //超级块方法 struct dquot_operations *s_qcop; //磁盘限额处理的方法 const struct export_operations *s_export_op;//网络文件系统使用的输出操作 unsigned long s_flags; //安装标志 unsigned long s_magic; //文件系统的魔数 struct dentry *s_root; //文件系统根目录的目录项对象 struct rw_semaphore s_umount; //卸载所用的信号量 int s_count; //引用计数器 atomic_t s_active; //次级引用计数器 #ifdef CONFIG_SECURITY void *s_security; //指向超级块安全数据结构的指针 #endif struct xattr_handler **s_xattr; //指向超级块扩展属性结构的指针 struct list_head s_inodes; //所有索引节点的链表 struct hlist_head s_anon; //用于处理网络文件系统的匿名目录项的链表 struct list_head s_mounts; // struct block_device *s_bdev; struct backing_dev_info *s_bdi; struct mtd_info *s_mtd; struct hlist_head s_instance; //用于给定文件系统类型的超级块对象链表的指针 unsigned int s_quota_types; struct quota_info s_dpuot; //磁盘限额的描述符 struct sb_writers s_writers; char s_id[32]; //包含超级块的块设备名称 u8 s_uuid[16]; //UUID void *s_fs_info; //指向特定文件系统的超级块信息的指针 unsigned int s_max_links; fmode_t s_mode; u32 s_time_gran; //时间戳的最小单位 struct mutex s_vfs_rename_mutex; char *s_subtype; char *s_options; }; ``have_submounts`` 用来检查在parent所指定的目录及其子目录上是否有挂载点 :: #include //kernel源码fs/dcache.c int have_submounts(struct dentry *parent) **测试代码** :: #include #include #include #include #include #include int get_fs_type_init(void) { const char *name = "ext4"; struct file_system_type fs = get_fs_type(name); printk("the filesystem's name is: %s\n", fs->name); int data = get_max_files(); //获取系统中文件数目 printk("get max files is = %d\n", data); struct super_block *sb; struct block_device *bdev = current->fs->pwd.dentry->d_sb->s_bdev; //获取当前文件对应的block_device描述符信息 sb = get_super(bdev); //获取bdev所对应的超级块 printk("the superblock dev number is %d\n", sb->s_dev); struct dentry *dentry_parent = current->fs->pwd.dentry->d_parrent; data = have_submounts(dentry_parent); if(data == 0) printk("current dentry has not submount.\n"); else printk("current dentry has submount.\n"); return 0; } void get_fs_type_exit(void) { return; } module_init(get_fs_type_init); module_exit(get_fs_type_exit); inode_add_bytes ------------------ ``inode_add_bytes`` 增加inode节点的字节数 :: #include //kernel源码fs/stat.c void inode_add_bytes(struct inode *inode, loff_t bytes) typedef __kernel_loff_t loff_t; typedef long long __kernel_loff_t; - inode: 要被增加字节的inode结构体 - bytes: 要增加的字节数 :: struct inode { umode_t i_mode; //改变节点的模式 unsigned short i_opflags; kuid_t i_uid; //所有者标识符 kgid_t i_gid; //组标识符 unsigned int i_flags; //文件系统的安装标志 #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif const struct inode_operations *i_op; //节点的操作函数 struct super_block *i_sb; //指向超级块的指针 struct address_space *i_mapping; //指向address_space对象的指针 #ifdef CONFIG_SECURITY void *i_security; //指向索引节点安全结构的指针 #endif unsigned long i_ino; //索引节点号 unioc { const unsigned int i_nlink; //硬链接的数目 unsigned int __i_nlink; }; dev_t i_rdev; //实设备标识符 loff_t i_size; //文件的字节数 struct timespec i_atime; //上次访问文件的时间 struct timespec i_mtime; //上次写文件的时间 struct timespec i_ctime; //上次修改索引节点的时间 spinlock_t i_lock; //保护索引节点一些字段的自旋锁 unsigned short i_bytes; //文件中最后一个块的字节数 unsigned int i_blkbits; //块的位数 blkcnt_t i_blocks; //文件的块数 #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif unsigned long i_state; struct mutex i_mutex; //节点的信号量 unsigned long dirtie_when; struct hlist_node i_hash; //用于散列表的指针 struct list_head i_wb_list; //dev IO备份列表指针 struct list_head i_lru; //节点的LRU链表 struct list_head i_sb_list; //用于超级块的索引节点链表的指针 union { struct hlist_head i_dentry; //引用索引节点的目录项对象链表的头 struct rcu_head i_rcu; //rcu链表的头指针 }; u64 i_version; //版本号 atomic_t i_count; //引用计数器 atomic_t i_dio_count;//dio的计数器 atomic_t i_writecount; //用于写进程的引用计数器 #ifdef CONFIG_IMA atomic_t i_readcount; //读计数器 #endif const struct file_operations *i_fops; struct file_lock *i_flock; //指向文件锁链表的指针 struct address_space i_data; //文件的address_space对象 struct list_head i_devices; //用于具体的字符和块设备索引节点链表 union { struct pipe_inode_info *i_pipe; //如果文件是一个管道,则使用它 struct block_device *i_bdev; //指向块设备驱动程序的指针 struct cdev *i_cdev; //指向字符设备驱动程序的指针 }; __u32 i_generation; #ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; //目录通知事件的位掩码 struct hlist_head i_fsnotify_marks; //位掩码链表头指针 #endif void *i_private; //文件或设备的私有指针 }; ``inode_get_bytes`` 用于获取整个inode节点的总字节数 :: #include //kernel源码fs/stat.c loff_t inode_get_bytes(struct inode *inode) void inode_set_bytes(struct inode *inode, loff_t bytes) void inode_sub_bytes(struct inode *inode, loff_t bytes) ``is_bad_inode`` 用于判断传入参数inode是否被标记为坏节点 :: #include //kernel源码fs/bad_inode.c int is_bad_inode(struct inode *inode) void make_bad_inode(struct inode *inode) //将inode节点标记为坏节点 **测试代码** :: #include #include #include #include #include #include int inode_test_init(void) { struct dentry *dentry = current->fs->pwd.dentry; struct inode *inode = dentry->d_inode; int is_bad = is_bad_inode(inode); if(!is_bad) { unsigned long inode_len = inode_get_bytes(inode); //获取inode节点的字节数 printk("the current inode bytes is %d\n", inode_len); inode_add_bytes(inode, 1024); //给inode节点增加1k } else { printk("it is a bad inode!\n"); } return 0; } void inode_test_exit(void) { return; } module_init(inode_test_init); module_exit(inode_test_exit); ``may_umount`` 用于检查挂载点mnt是否处于忙的状态, 忙的定义为在挂载点上有打开的文件,pwd结构体,或者vfsmount结构体 :: #include //kernel源码fs/namespace.c int may_umount(struct vfsmount *mnt) int may_umount_tree(struct vfsmount *mnt)