今天的主要内容很少,昨天我们把目录的处理换成我们指定的sfs之类的操作,今天则是涉及自定义文件操作。
源码解析
新增的代码只有inode.c中的一部分:
struct inode_operations sfs_file_inode_ops = {
.getattr = simple_getattr,
};
之后在super.c中也仅仅是加上了对sfs_file_inode_ops
的声明,同时在samplefs_get_inode
中,当mode为S_IFREG
即处理常规文件时,将i_op替换为sfs_file_inode_ops
。
不妨来看一看libfs.c中的simple_getattr
函数:
int simple_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
struct inode *inode = d_inode(path->dentry);
generic_fillattr(inode, stat);
stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9);
return 0;
}
EXPORT_SYMBOL(simple_getattr);
代码很短,不妨逐行解释。
d_inode的解释是:
Get the actual inode of this dentry
很简单,就是获取某个dentry的inode,dcache.h中对d_inode
的实现为:
static inline struct inode *d_inode(const struct dentry *dentry)
{
return dentry->d_inode;
}
在fs/stat.c中,generic_fillattr
定义如下:
/**
* generic_fillattr - Fill in the basic attributes from the inode struct
* @inode: Inode to use as the source
* @stat: Where to fill in the attributes
*
* Fill in the basic attributes in the kstat structure from data that's to be
* found on the VFS inode structure. This is the default if no getattr inode
* operation is supplied.
*/
void generic_fillattr(struct inode *inode, struct kstat *stat)
{
stat->dev = inode->i_sb->s_dev;
stat->ino = inode->i_ino;
stat->mode = inode->i_mode;
stat->nlink = inode->i_nlink;
stat->uid = inode->i_uid;
stat->gid = inode->i_gid;
stat->rdev = inode->i_rdev;
stat->size = i_size_read(inode);
stat->atime = inode->i_atime;
stat->mtime = inode->i_mtime;
stat->ctime = inode->i_ctime;
stat->blksize = i_blocksize(inode);
stat->blocks = inode->i_blocks;
if (IS_NOATIME(inode))
stat->result_mask &= ~STATX_ATIME;
if (IS_AUTOMOUNT(inode))
stat->attributes |= STATX_ATTR_AUTOMOUNT;
}
EXPORT_SYMBOL(generic_fillattr);
注释写的很清楚,就是把inode中的一些属性复制到kstat中,kstat定义在stat.h中,初步看来是inode的一个小副本,包含了一些inode的基本信息。
struct kstat {
u32 result_mask; /* What fields the user got */
umode_t mode;
unsigned int nlink;
uint32_t blksize; /* Preferred I/O size */
u64 attributes;
u64 attributes_mask;
#define KSTAT_ATTR_FS_IOC_FLAGS
(STATX_ATTR_COMPRESSED |
STATX_ATTR_IMMUTABLE |
STATX_ATTR_APPEND |
STATX_ATTR_NODUMP |
STATX_ATTR_ENCRYPTED
)/* Attrs corresponding to FS_*_FL flags */
u64 ino;
dev_t dev;
dev_t rdev;
kuid_t uid;
kgid_t gid;
loff_t size;
struct timespec64 atime;
struct timespec64 mtime;
struct timespec64 ctime;
struct timespec64 btime; /* File creation time */
u64 blocks;
};
在inode中i_mapping
指向该inode相关的页缓存的地址空间,内核中用address_space
结构表示地址空间这一概念,nrpages
成员表示缓存页的总数,PAGE_SHIFT
在page.h中,页大小为4KB,PAGE_SHIFT
为12,这行代码修改了一下stat->blocks
的值,可能的意思是,stat->blocks
表示的是文件用块表示的最大长度,但是这个9具体指什么还暂时不清楚。
以上就是getattr
成员的函数解析,总体上来看就是填充了一个kstat结构,根据ppt上给出的预期结果,ls命令涉及的系统调用很可能需要getattr
和kstat
结构的支持。
结果和问题
可见,ls
命令可以正常使用。
问题:touch
命令有时会出现问题,而且与材料给出的预期结果不一致,touch
命令也可以正常使用。而且时间戳的获取还是存在问题,目前使用的是:
struct timespec64 ts;
ktime_get_ts64(&ts);
inode->i_mtime = ts;
还是不能获取正确的时间戳。