今天的内容主要是学习inode的基础知识。
inode
材料中总结了inode的一些基本要点:
- inode代表了一个文件及其metadata(时间戳,文件类型,文件大小等),但是不包括文件名;
- inode可以表示普通文件,目录文件,符号链接以及特殊文件;
- 通过完成VFS中inode_operations和file_operations的成员函数来完成inode的相关操作;
- 同时也需要完成inode中metadata的内容(uid,gid,owner,mode,timestamps等)。
/** Keep mostly read-only and often accessed (especially for* the RCU path lookup and 'stat' data) fields at the beginning* of the 'struct inode'*/
struct inode {umode_t i_mode;unsigned short i_opflags;kuid_t i_uid;kgid_t i_gid;unsigned int i_flags;[--skipped--]const struct inode_operations *i_op;struct super_block *i_sb;struct address_space *i_mapping;[--skipped--]/* Stat data, not accessed from path walking */unsigned long i_ino;union {const unsigned int i_nlink;unsigned int __i_nlink;};dev_t i_rdev;loff_t i_size;struct timespec64 i_atime;struct timespec64 i_mtime;struct timespec64 i_ctime;spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */unsigned short i_bytes;u8 i_blkbits;u8 i_write_hint;blkcnt_t i_blocks;[--skipped--]atomic_t i_count;atomic_t i_dio_count;atomic_t i_writecount;
#ifdef CONFIG_IMAatomic_t i_readcount; /* struct files open RO */
#endifconst struct file_operations *i_fop; /* former ->i_op->default_file_ops */struct file_lock_context *i_flctx;struct address_space i_data;struct list_head i_devices;union {struct pipe_inode_info *i_pipe;struct block_device *i_bdev;struct cdev *i_cdev;char *i_link;unsigned i_dir_seq;};__u32 i_generation;[--skipped--]
} __randomize_layout;
inode 的结构较为复杂,所以我们在这里进行一些简化。需要注意的是,上面提到的inode指的是内存中的inode,所以有些部分并不存在于外部存储中,这些信息由内核自身从底层文件系统读入信息时生成或动态建立。
- i_atime、i_mtime、i_ctime:
分别表示最后访问时间,数据段最后修改时间,最后修改inode的时间。 - i_size:
文件大小(字节)。 - i_blocks:
文件块数量,i_blocks = i_size / 块大小
。 - i_ino:
每个 VFS inode 都由一个唯一的编号标识,保存在i_ino中。 - i_count:
使用计数器,表示访问该inode的进程数目。 - i_mode,i_uid,i_gid:
文件访问权限和所有权。 - i_rdev:
一个数字,其中包含找到相关目标设备的信息。 - i_devices:
链表元素,使得字符设备或者块设备可以维护一个inode链表,其中每个inode代表一个设备文件,通过设备文件来访问对应的设备。 - i_op,i_fop:
i_op用于管理结构性的操作(例如删除文件)和文件相关的元数据(例如属性等);i_fop用于操作文件中包含的数据。
内核提供了大量函数对inode进行操作,为此定义了一个函数集合抽象这些操作,这些操作接口保持不变,但是实际的操作根据文件系统的不同有所差异。所有的inode操作都由一个inode_operations抽象起来:
struct inode_operations {struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);int (*permission) (struct inode *, int);struct posix_acl * (*get_acl)(struct inode *, int);int (*readlink) (struct dentry *, char __user *,int);int (*create) (struct inode *,struct dentry *, umode_t, bool);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 *,umode_t);int (*rmdir) (struct inode *,struct dentry *);int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);int (*rename) (struct inode *, struct dentry *,struct inode *, struct dentry *, unsigned int);int (*setattr) (struct dentry *, struct iattr *);int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);ssize_t (*listxattr) (struct dentry *, char *, size_t);int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,u64 len);int (*update_time)(struct inode *, struct timespec64 *, int);int (*atomic_open)(struct inode *, struct dentry *,struct file *, unsigned open_flag,umode_t create_mode);int (*tmpfile) (struct inode *, struct dentry *, umode_t);int (*set_acl)(struct inode *, struct posix_acl *, int);
} ____cacheline_aligned;
day4 源码分析
我们先来看day4的代码中新增的部分:
#include <linux/ktime.h>
#include <linux/timekeeping.h>
struct inode *samplefs_get_inode(struct super_block *sb, int mode, dev_t dev)
{struct inode * inode = new_inode(sb);struct timespec64 ts;if (inode) {// 设置inode的一些成员inode->i_mode = mode;// inode->i_uid = current->fsuid;inode->uid = current->cred->fsuid;// inode->i_gid = current->fsgid;inode->gid = current->cred->fsgid;inode->i_blocks = 0;ktime_get_ts64(&ts);inode->i_atime = inode->i_mtime = inode->i_ctime = ts;switch (mode & S_IFMT) {default:init_special_inode(inode, mode, dev);break;
/* We are not ready to handle files yet */
/* case S_IFREG:inode->i_op = &sfs_file_inode_operations;break; */// 目前仅支持获取根目录的inode,并不支持常规文件。case S_IFDIR:inode->i_op = &simple_dir_inode_operations;/* link == 2 (for initial ".." and "." entries) */inode->__i_nlink++;break;}}return inode;
}
这个函数的逻辑比较简单,主要是创建,填充并返回一个inode。
init_special_inode
函数主要是为了填充i_mode,i_fop以及i_rdev。这三个成员上面已经解释过。
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{inode->i_mode = mode;if (S_ISCHR(mode)) {inode->i_fop = &def_chr_fops;inode->i_rdev = rdev;} else if (S_ISBLK(mode)) {inode->i_fop = &def_blk_fops;inode->i_rdev = rdev;} else if (S_ISFIFO(mode))inode->i_fop = &pipefifo_fops;else if (S_ISSOCK(mode)); /* leave it no_open_fops */elseprintk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"" inode %s:%lu\n", mode, inode->i_sb->s_id,inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);
而这个samplefs_get_inode
函数在samplefs_fill_super
中被调用,因为此时mode=S_ISDIR|0755,所以此时并不会设置i_fop和i_rdev。
至此可以编译成功。
参考资料
sturct stat 结构体中 st_mode 的含义Linux 操作系统:进程数据结构(task_struct)inode的i_nlink