linux vfs open函数,Linux VFS 之 open系统调用(kernel 3.4)

linux version: 3.4.67

kernel 代码

fs/open.c

fs/namei.c

open命令调用关系

mount- > /fs/open.c/SYSCALL_DEFINE3(open, ....); -> do_sys_open->get_unused_fd_flags->

->do_filp_open->fd_install

根据调用关系对各函数注解

1、do_sys_open

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)

{

struct open_flags op;

int lookup = build_open_flags(flags, mode, &op);

char *tmp = getname(filename);

int fd = PTR_ERR(tmp);

if (!IS_ERR(tmp)) {

fd = get_unused_fd_flags(flags);   //获取一个未使用的文件描述符,参考fs/file.c文件alloc_fd() ,后续仔细研究file.c文件。

if (fd >= 0) {

struct file *f = do_filp_open(dfd, tmp, &op, lookup);  //直接调用path_openat打开文件,返回file文件对象。

if (IS_ERR(f)) {

put_unused_fd(fd);

fd = PTR_ERR(f);

} else {

fsnotify_open(f);

fd_install(fd, f);  //file文件对象与当前进程current关联。fd作为file对象的索引,这样file与fd也一一对应。

}

}

putname(tmp);

}

return fd;  //返回文件描述符

}

2、path_openat

static struct file *path_openat(int dfd, const char *pathname,

struct nameidata *nd, const struct open_flags *op, int flags)

{

struct file *base = NULL;

struct file *filp;

struct path path;

int error;

//申请文件对象file结构体内存批针

filp = get_empty_filp();

if (!filp)

return ERR_PTR(-ENFILE);

filp->f_flags = op->open_flag;     //保存open flag

nd->intent.open.file = filp;       //将文件对象到nd->intent.open.file,后面就直接从这儿拿文件对象指针

nd->intent.open.flags = open_to_namei_flags(op->open_flag);

nd->intent.open.create_mode = op->mode;

error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);   //初始化nd

if (unlikely(error))

goto out_filp;

current->total_link_count = 0;

error = link_path_walk(pathname, nd)

;//查找到打开文件所在目录的目录项对象dentry和vfsmount,保存到nd。

后面仔细研研path lookup的方法namei.c

filp = do_last(nd, &path, op, pathname);   //  调用do_last继续做其它工作

........

return filp;

}

3、do_last

static struct file *do_last(struct nameidata *nd, struct path *path,

const struct open_flags *op, const char *pathname)

{

struct dentry *dir = nd->path.dentry;  //所在目录的目录项对象dentry

struct dentry *dentry;

int open_flag = op->open_flag;

int will_truncate = open_flag & O_TRUNC;

int want_write = 0;

int acc_mode = op->acc_mode;

struct file *filp;

int error;

nd->flags &= ~LOOKUP_PARENT;

nd->flags |= op->intent;

..........

dentry = lookup_hash(nd); //基于文件所在目录的nd,从目录项缓存中查找要打开文件的目录项对象dentry。

//如果缓存查找不到,放心会新创建一个新的目录项对项

path->dentry = dentry;

path->mnt = nd->path.mnt;

/* Negative dentry, just create the file */

if (!dentry->d_inode) {  //如果文件dentry对应的inode为空,则需要为它创建inode

umode_t mode = op->mode;

。。。。。。。

error = vfs_create(dir->d_inode, dentry, mode, nd);  //利用所在目录的目录项对象的inode operation为相关文件创建新inode。注:这里dentry与inode就关联起来了。

nd->path.dentry = dentry;  //建文件的目录项对象保存到nd->path->dentry

goto common;  // 跑到common 继续~~

}

common:

filp = nameidata_to_filp(nd);  //将nameidata相关项赋值给struct file对象。

return filp;

4、nameidata_to_filp

struct file *nameidata_to_filp(struct nameidata *nd)

{

const struct cred *cred = current_cred();

struct file *filp;

/* Pick up the filp from the open intent */

filp = nd->intent.open.file;     //获取函数path_openat申请并保存到nameidata的file对象

nd->intent.open.file = NULL;

// 文件对象是在path_openat函数申请及一些简单初始化,这儿先判断filp->f_path.dentry是否为空

//注:虽然前面do_last函数将file对象相关的dentry和inode已经创建好了,但并未与file对象关联起来。

//file对象的很多其它重要成员也都没有初始化!

//接下来__dentry_open就要做这些事情了!

/* Has the filesystem initialised the file for us? */

if (filp->f_path.dentry == NULL) {

path_get(&nd->path);

filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,  // file对象初始化,包括file与dentry关联工作

NULL, cred);

}

return filp;

}

6、

__dentry_open

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,

struct file *f,

int (*open)(struct inode *, struct file *),

const struct cred *cred)

{

static const struct file_operations empty_fops = {};

struct inode *inode;

int error;

f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |        //初始化打开mode

FMODE_PREAD | FMODE_PWRITE;

if (unlikely(f->f_flags & O_PATH))

f->f_mode = FMODE_PATH;    //打开的是目录

。。。。。。。

inode = dentry->d_inode;      //从dentry中获取inode。 dentry和inode在前面的do_last函数已经关联过的。

f->f_mapping = inode->i_mapping;   //地址空间map

f->f_path.dentry = dentry;             // 注: 就在这儿file对象与目录象对象关联起来啦!!

f->f_path.mnt = mnt;                   // file对象与挂载点对象关联起来啦。

f->f_pos = 0;                                //初始文件批针位置为0.

file_sb_list_add(f, inode->i_sb);             // add a file to the sb's file list

if (unlikely(f->f_mode & FMODE_PATH)) {

f->f_op = &empty_fops;          //打开目录的话,file operation为空了,直接返回了。

return f;

}

//注: 在这儿file对象的file_operations初始化好了。

f->f_op = fops_get(inode->i_fop);  //inode节点在初始化的时候已经赋值了i_fop,现在将文件操作赋值给f_op

// 通过file对象的file_operations->open指针,调用到特定文件系统的open函数,打开特定的设备或文件啦!

if (!open && f->f_op)

open = f->f_op->open;

if (open) {

error = open(inode, f);

if (error)

goto cleanup_all;

}

。。。。。。。。

/* NB: we're sure to have correct a_ops only after f_op->open */

if (f->f_flags & O_DIRECT) {

if (!f->f_mapping->a_ops ||

((!f->f_mapping->a_ops->direct_IO) &&

(!f->f_mapping->a_ops->get_xip_mem))) {

fput(f);

f = ERR_PTR(-EINVAL);

}

}

return f;     //至此file对象已经初始化完成、并且调用特定文件系统的open方法

}

7、fd_install

将进程的current->files对象与file文件对象进行

void fd_install(unsigned int fd, struct file *file)

{

struct files_struct *files = current->files;   //获取当前进程打开的文件表批针

struct fdtable *fdt;

spin_lock(&files->file_lock);

fdt = files_fdtable(files);        //获取当前进程的文件描述符表指针

BUG_ON(fdt->fd[fd] != NULL);

rcu_assign_pointer(fdt->fd[fd], file);    //将fdt->fd[fd]指向file对象,这样文件对象与进程关联上了。 fd作为file对象的索引。这样file与fd也一一对应

spin_unlock(&files->file_lock);

}

fs/open.c 提供的内核常用方法

//面向kernel的文件open相关操作接口。注:返回值都是file对象,而非fd文件描述符。

filp_open

file_open_root

filp_close

dentry_open

参考:

http://blog.csdn.net/chenjin_zhong/article/details/8452453

http://blog.csdn.net/chenjin_zhong/article/details/8452487

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值