在文件系统中,在当前进程中,由fd获取struct file对象,进而获得struct inode对象。
current->files->fdt->fd[fd]->f_inode
其中涉及到主要数据结构如下图所示:
struct task_structcurrent-> struct files_struct *files -> struct fdtable fdtab -> struct file __rcu *fd[fd] -> struct file -> struct inode *f_inode
这些数据结构相互嵌套,共同构成了文件系统对文件的描述。
一、mount时建ocfs2根目录和系统目录:
static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
|-struct inode *new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
|-osb->root_inode = new;
|-new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
|-osb->sys_root_inode = new;
|-if (osb->root_inode)
inode = igrab(osb->root_inode);
|-struct dentry *root = d_make_root(inode);
|-if (root_inode) {
res = d_alloc_anon(root_inode->i_sb);//申请目录项dentry,并初始化,返回。
|-struct dentry *dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
|-dentry初始化
|-return dentry;
if (res)
d_instantiate(res, root_inode);//为目录项dentry添加inode信息
else
iput(root_inode);
|-}
主要流程:
1、新申请一个inode,并初始化,将其记录到全局inode哈希表inode_hashtable和superblock上&inode->i_sb->s_inodes
2、初始化锁资源ip_inode_lockres、ip_open_lockres
2、初始化ocfs2 inode信息,根据文件类型S_IFREG://普通文件,关联file ops;S_IFDIR://目录文件,关联inode->i_op = &ocfs2_dir_iops,初始化日志journal
3、申请目录项dentry,并初始化,为目录项dentry添加inode信息。
其中ocfs2_iget()是重点:
struct inode *new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0);
|-struct inode *inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor, ocfs2_init_locked_inode, &args);//新申请一个inode,加锁并初始化,将其记录到全局inode哈希表inode_hashtable和superblock上&inode->i_sb->s_inodes
|-struct inode *new = alloc_inode(sb);
|-inode = inode_insert5(new, hashval, test, set, data);
|-inode->i_state |= I_NEW;
|-将inode记录到全局变量inode_hashtable和superblock上&inode->i_sb->s_inodes
|-if (inode->i_state & I_NEW) {
|-rc = ocfs2_read_locked_inode(inode, &args);
|-ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres, OCFS2_LOCK_TYPE_META,
generation, inode);//初始化meta锁资源
|-ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres, OCFS2_LOCK_TYPE_OPEN, 0, inode);
|-status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
|-submit_bh(REQ_OP_READ, 0, bh);//读磁盘操作
|-status = ocfs2_xxx_validate_inode_block(osb->sb, bh);//根据flags设置调用函数校验block块
|-struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;
|-ocfs2_populate_inode(inode, fe, 0);//初始化ocfs2 inode
|-unlock_new_inode(inode);
|-}
|-if (journal) {初始化日志journal
|-transaction_t *transaction;
|-tid_t tid;
|-struct ocfs2_inode_info *oi = OCFS2_I(inode);
|-read_lock(&journal->j_state_lock);
|-if (journal->j_running_transaction)
transaction = journal->j_running_transaction;
|-else
transaction = journal->j_committing_transaction;
|-if (transaction)
tid = transaction->t_tid;
|-else
tid = journal->j_commit_sequence;
|-read_unlock(&journal->j_state_lock);
|-oi->i_sync_tid = tid;
|-oi->i_datasync_tid = tid;
|-}
|-return inode;
初始化一个inode,关联地址空间操作ocfs2_aops,根据文件类型S_IFREG://普通文件,关联file ops;S_IFDIR://目录文件,关联inode->i_op = &ocfs2_dir_iops,
void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, int create_ino)
|-初始化ocfs2 inode信息
|-inode->i_mapping->a_ops = &ocfs2_aops;
|-switch (inode->i_mode & S_IFMT) {
|-case S_IFREG://普通文件
|-if (use_plocks)
inode->i_fop = &ocfs2_fops;
|-else
inode->i_fop = &ocfs2_fops_no_plocks;
|-inode->i_op = &ocfs2_file_iops;
|-i_size_write(inode, le64_to_cpu(fe->i_size));
|-break;
|-case S_IFDIR://目录文件
|-inode->i_op = &ocfs2_dir_iops;
|-if (use_plocks)
inode->i_fop = &ocfs2_dops;
|-else
inode->i_fop = &ocfs2_dops_no_plocks;
|-i_size_write(inode, le64_to_cpu(fe->i_size));
|-OCFS2_I(inode)->ip_dir_lock_gen = 1;
|-break;
|-case S_IFLNK://链接文件
|-inode->i_op = &ocfs2_symlink_inode_operations;
|-inode_nohighmem(inode);
|-i_size_write(inode, le64_to_cpu(fe->i_size));
|-break;
|-default:
|-inode->i_op = &ocfs2_special_file_iops;
|-init_special_inode(inode, inode->i_mode, inode->i_rdev);
|-break;
|-}
|-ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres, //初始化读写RW锁资源
OCFS2_LOCK_TYPE_RW, inode->i_generation, inode);
这样根目录便从磁盘上读到内存,初始化并挂接了ocfs2_dir_iops,如下所示:
const struct inode_operations ocfs2_dir_iops = {
.create = ocfs2_create,
.lookup = ocfs2_lookup,
.link = ocfs2_link,
.unlink = ocfs2_unlink,
.rmdir = ocfs2_unlink,
.symlink = ocfs2_symlink,
.mkdir = ocfs2_mkdir,
.mknod = ocfs2_mknod,
.rename = ocfs2_rename,
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
.listxattr = ocfs2_listxattr,
.fiemap = ocfs2_fiemap,
.get_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
};
二、在用户态调用open打开文件:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode)
{
int flags = O_CREAT | O_WRONLY | O_TRUNC;
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, pathname, flags, mode);
}
主要流程:
1、获取一个未使用的fd;
2、申请一个未使用的 struct file对象,关联文件inode:f->f_inode = inode及操作f->f_op = fops_get(inode->i_fop),调vfs_open() -> 具体文件系统提供的open()函数;
3、报文件已打开事件;
4、将fd记录到fdt数组中,把fd与file关联起来;
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_how how = build_open_how(flags, mode);
return do_sys_openat2(dfd, filename, &how);
|-int fd = get_unused_fd_flags(how->flags);//获取一个未使用的fd
|-struct file *f = do_filp_open(dfd, tmp, &op);//申请一个未使用的file struct,调vfs_open() -> 具体文件系统提供的open()函数
|-set_nameidata(&nd, dfd, pathname);
|-struct file *filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|-struct file *file = alloc_empty_file(op->open_flag, current_cred());//申请一个未使用的file struct,并返回指针。
|-struct file *f = __alloc_file(flags, cred);
|-const char *s = path_init(nd, flags);
|-error = do_open(nd, file, op);
|-if (!error && !(file->f_mode & FMODE_OPENED))
|-error = vfs_open(&nd->path, file); //call vfs_open - open the file at the given path
|-file->f_path = *path;
|-return do_dentry_open(file, d_backing_inode(path->dentry), NULL);
|-f->f_op = fops_get(inode->i_fop);
|-open = f->f_op->open;
|-error = open(inode, f); //这里就调打开文件open函数
|-return filp;
|-fsnotify_open(f); //file was opened
|-fd_install(fd, f); //Install a file pointer in the fd array.
|-struct files_struct *files = current->files;
|-struct fdtable *fdt = files_fdtable(files);
|-smp_rmb();
|-fdt = rcu_dereference_sched(files->fdt);
|-BUG_ON(fdt->fd[fd] != NULL);
|-rcu_assign_pointer(fdt->fd[fd], file);//把fd与file关联起来。
|-return fd;
}
ocfs2内核open:初始化文件私有数据:初始化flock锁资源。
static int ocfs2_file_open(struct inode *inode, struct file *file)
|-struct ocfs2_inode_info *oi = OCFS2_I(inode);
|-if (file->f_mode & FMODE_WRITE) {
status = dquot_initialize(inode);
|-if (mode & O_DIRECT)
oi->ip_flags |= OCFS2_INODE_OPEN_DIRECT;
|-oi->ip_open_count++;
|-status = ocfs2_init_file_private(inode, file);
|-struct ocfs2_file_private *fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
|-ocfs2_file_lock_res_init(&fp->fp_flock, fp);//初始化flock锁资源
|-ocfs2_lock_res_init_once(lockres);
|-ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno, inode->i_generation, lockres->l_name);
|-ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres, OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops, fp);
|-lockres->l_flags |= OCFS2_LOCK_NOCACHE;
|-file->private_data = fp; //记录到文件file私有数据
|-file->f_mode |= FMODE_NOWAIT;
文件打开成功。
三、通过mknod创建文件、块设备
SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
{
return do_mknodat(AT_FDCWD, filename, mode, dev);
}
static long do_mknodat(int dfd, const char __user *filename, umode_t mode, unsigned int dev)
|-struct dentry *dentry = user_path_create(dfd, filename, &path, lookup_flags);
|-error = security_path_mknod(&path, dentry, mode, dev);
switch (mode & S_IFMT) {
case 0: case S_IFREG: //普通文件
error = vfs_create(path.dentry->d_inode,dentry,mode,true);
|-error = dir->i_op->create(dir, dentry, mode, want_excl); //调用目录dir inode的create方法
break;
case S_IFCHR: case S_IFBLK: //字符设备文件/块设备文件
error = vfs_mknod(path.dentry->d_inode,dentry,mode, new_decode_dev(dev));
|-error = dir->i_op->mknod(dir, dentry, mode, dev); //调用目录dir inode的mknod方法
break;
case S_IFIFO: case S_IFSOCK:
error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
break;
}
|-done_path_create(&path, dentry);
ocfs2_create/ocfs2_mkdir均调用了ocfs2_mknod
.create = ocfs2_create,
static int ocfs2_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
|-ret = ocfs2_mknod(dir, dentry, mode | S_IFREG, 0);
.mkdir = ocfs2_mkdir,
static int ocfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|-ret = ocfs2_mknod(dir, dentry, mode | S_IFDIR, 0);
OCFS2内核mknode处理:
.mknod = ocfs2_mknod,
static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|-struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);//获取ocfs2 super block
|-status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);//对ip_inode_lockres锁资源加EX锁
|-status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh, dentry->d_name.name, dentry->d_name.len, &lookup);//get a spot inside the dir.
|-status = ocfs2_reserve_new_inode(osb, &inode_ac); //reserve an inode spot, 获取分配inode alloc context上下文
|-struct inode *inode = ocfs2_get_init_inode(dir, mode);
|-status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac); //预留meta
|-status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); //预留data
|-handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), xattr_credits));//启动日志journal:jbd2
|-status = ocfs2_mknod_locked(osb, dir, inode, dev, &new_fe_bh, parent_fe_bh, handle, inode_ac);//do the real work now.
|-status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, inode_ac, &suballoc_loc, &suballoc_bit, &fe_blkno);
|-status = __ocfs2_mknod_locked(dir, inode, dev, new_fe_bh, parent_fe_bh, handle, inode_ac, fe_blkno, suballoc_loc, suballoc_bit);
|-初始化ocfs2_dinode *fe
|-ocfs2_populate_inode(inode, fe, 0);
|-ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres, //初始化读写RW锁资源
OCFS2_LOCK_TYPE_RW, inode->i_generation, inode);
|-status = ocfs2_create_new_inode_locks(inode);
|-ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_rw_lockres, 1, 1);
|-ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0);
|-ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_open_lockres, 0, 0);
|-status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, meta_ac, data_ac);
|-status = ocfs2_add_entry(handle, dentry, inode, OCFS2_I(inode)->ip_blkno, parent_fe_bh, &lookup);
|-insert_inode_hash(inode);//插入inode哈希表inode_hashtable
|-d_instantiate(dentry, inode);
一个文件inode就创建完成。