nfs笔记:open

来源:互联网 发布:淘宝定向推广智能投放 编辑:程序博客网 时间:2024/06/08 18:24

通过sysctrl调到Nfscctl.c:do_open()

核心函数1:do_open()

static struct file *do_open(char *name, int flags){struct nameidata nd;struct vfsmount *mnt;int error;        //在系统调用前先确认 nfsd被文件系统被挂载mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);if (IS_ERR(mnt))return (struct file *)mnt;        //通过文件系统的根节点以及被mount的节点中的名字找到相关的nameidata结构error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);mntput(mnt);/* drop do_kern_mount reference */if (error)return ERR_PTR(error);        //检查要求的权限是否满足需求if (flags == O_RDWR)error = may_open(&nd.path, MAY_READ|MAY_WRITE,   FMODE_READ|FMODE_WRITE);elseerror = may_open(&nd.path, MAY_WRITE, FMODE_WRITE);if (!error)return dentry_open(nd.path.dentry, nd.path.mnt, flags,   current_cred());path_put(&nd.path);return ERR_PTR(error);}

函数:do_kern_mount

函数:vfs_path_lookup

/** * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair * @dentry:  pointer to dentry of the base directory * @mnt: pointer to vfs mount of the base directory * @name: pointer to file name * @flags: lookup flags * @nd: pointer to nameidata */int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,    const char *name, unsigned int flags,    struct nameidata *nd){int retval;/* same as do_path_lookup */nd->last_type = LAST_ROOT;nd->flags = flags;nd->depth = 0;nd->path.dentry = dentry;nd->path.mnt = mnt;path_get(&nd->path);nd->root = nd->path;path_get(&nd->root);        retval = path_walk(name, nd);if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&nd->path.dentry->d_inode))audit_inode(name, nd->path.dentry);path_put(&nd->root);nd->root.mnt = NULL;return retval;}
函数:path_walk

static int path_walk(const char *name, struct nameidata *nd){current->total_link_count = 0;return link_path_walk(name, nd);}
函数: link_path_walk

/* * Wrapper to retry pathname resolution whenever the underlying * file system returns an ESTALE. * * Retry the whole path once, forcing real lookup requests * instead of relying on the dcache. */static __always_inline int link_path_walk(const char *name, struct nameidata *nd){struct path save = nd->path;int result;/* make sure the stuff we saved doesn't go away */path_get(&save);        //查找路径节点上的名称并填充nameidata如果不存在则不填充,用初始化后的值result = __link_path_walk(name, nd);if (result == -ESTALE) {/* nd->path had been dropped */nd->path = save;path_get(&nd->path);nd->flags |= LOOKUP_REVAL;result = __link_path_walk(name, nd);}path_put(&save);return result;}

函数:__link_path_walk

/* * Name resolution. * This is the basic name resolution function, turning a pathname into * the final dentry. We expect 'base' to be positive and a directory. * * Returns 0 and nd will have valid dentry and mnt on success. * Returns error and drops reference to input namei data on failure. */static int __link_path_walk(const char *name, struct nameidata *nd){struct path next;struct inode *inode;int err;unsigned int lookup_flags = nd->flags;while (*name=='/')name++;if (!*name)goto return_reval;inode = nd->path.dentry->d_inode;if (nd->depth)lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);/* At this point we know we have a real path component. */for(;;) {unsigned long hash;struct qstr this;unsigned int c;nd->flags |= LOOKUP_CONTINUE;                //根据inode文件路径的权限以及SELinux,查看有可执行权限?否则不继续往下遍历err = exec_permission_lite(inode); if (err)break;this.name = name;c = *(const unsigned char *)name;                //讲路径上的节点编hashcode 生产的是hashcode为32位hash = init_name_hash();do {name++;hash = partial_name_hash(c, hash);c = *(const unsigned char *)name;} while (c && (c != '/'));this.len = name - (const char *) this.name;this.hash = end_name_hash(hash);/* remove trailing slashes? */if (!c)goto last_component;                 //跳过多个斜线while (*++name == '/');               //最后其实还是斜线if (!*name)goto last_with_slashes;/* * "." and ".." are special - ".." especially so because it has * to be able to know about the current root directory and * parent relationships. */                //最后是当前目录或者父目录if (this.name[0] == '.') switch (this.len) {default:break;case 2:if (this.name[1] != '.')break;follow_dotdot(nd);inode = nd->path.dentry->d_inode;/* fallthrough */case 1:continue;}/* * See if the low-level filesystem might want * to use its own hash.. */                //调用当前遍历节点对应的文件系统hashcode编码检测函数if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {err = nd->path.dentry->d_op->d_hash(nd->path.dentry,    &this);if (err < 0)break;}/* This does the actual lookups.. */                //invork process:do_lookup()--+--  __do_lookup()<pr>                //                             |  通过上锁(读写锁,特定时候自旋锁,计数器必然采用原子操作)<pr>                  //                             |  从头结点eg:root往下执行遍历<pr>                   //                            +--  假如没找到则调用 real_lookup()--+--d_lookup() --+--__d_lookup()<pr>                 //                            |   这个函数是调用底层的文件系统;<pr>       |                 //                            |   通过上锁(互斥)查找<pr>                             //                            |   包装了一个自旋锁                   //                            +----__follow_mount()                //未查找到 则返回NULL 输出结果将会把NULL值转化成long 即机器位数                   err = do_lookup(nd, &this, &next);if (err)break;err = -ENOENT;inode = next.dentry->d_inode;if (!inode)goto out_dput;                //处理软硬链接遍历                //软硬连接数有限制 总链接数为40 当前节点链接数为8if (inode->i_op->follow_link) {err = do_follow_link(&next, nd);if (err)goto return_err;err = -ENOENT;inode = nd->path.dentry->d_inode;if (!inode)break;} else                        //设置 path.mnt 和 path dentrypath_to_nameidata(&next, nd);err = -ENOTDIR; if (!inode->i_op->lookup)break;continue;/* here ends the main loop */last_with_slashes:lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;last_component:/* Clear LOOKUP_CONTINUE iff it was previously unset */nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;if (lookup_flags & LOOKUP_PARENT)goto lookup_parent;if (this.name[0] == '.') switch (this.len) {default:break;case 2:if (this.name[1] != '.')break;follow_dotdot(nd);inode = nd->path.dentry->d_inode;/* fallthrough */case 1:                                //最后退出这里和上面的循环体是不一样的goto return_reval;}if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {err = nd->path.dentry->d_op->d_hash(nd->path.dentry,    &this);if (err < 0)break;}err = do_lookup(nd, &this, &next);if (err)break;inode = next.dentry->d_inode;if ((lookup_flags & LOOKUP_FOLLOW)    && inode && inode->i_op->follow_link) {err = do_follow_link(&next, nd);if (err)goto return_err;inode = nd->path.dentry->d_inode;} elsepath_to_nameidata(&next, nd);err = -ENOENT;if (!inode)break;if (lookup_flags & LOOKUP_DIRECTORY) {err = -ENOTDIR; if (!inode->i_op->lookup)break;}                //这里结束循环goto return_base;lookup_parent:nd->last = this;nd->last_type = LAST_NORM;if (this.name[0] != '.')goto return_base;if (this.len == 1)nd->last_type = LAST_DOT;else if (this.len == 2 && this.name[1] == '.')nd->last_type = LAST_DOTDOT;elsegoto return_base;return_reval:/* * We bypassed the ordinary revalidation routines. * We may need to check the cached dentry for staleness. */if (nd->path.dentry && nd->path.dentry->d_sb &&    (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {err = -ESTALE;/* Note: we do not d_invalidate() */if (!nd->path.dentry->d_op->d_revalidate(nd->path.dentry, nd))break;}return_base:return 0;out_dput:path_put_conditional(&next, nd);break;}path_put(&nd->path);return_err:return err;}</pr></pr></pr></pr></pr></pr>

函数:dentry_open

/* * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an * error. */struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, const struct cred *cred){int error;struct file *f;validate_creds(cred);/* * We must always pass in a valid mount pointer.   Historically * callers got away with not passing it, but we must enforce this at * the earliest possible point now to avoid strange problems deep in the * filesystem stack. */if (!mnt) {printk(KERN_WARNING "%s called with NULL vfsmount\n", __func__);dump_stack();return ERR_PTR(-EINVAL);}error = -ENFILE;f = get_empty_filp();if (f == NULL) {dput(dentry);mntput(mnt);return ERR_PTR(error);}return __dentry_open(dentry, mnt, flags, f, NULL, cred);}

核心函数:open.c:__dentry_open

调用inode的i_fop先尝试执行security_ops注册的打开处理,后尝试打开文件

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,int flags, struct file *f,int (*open)(struct inode *, struct file *),const struct cred *cred){struct inode *inode;int error;f->f_flags = flags;f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK |FMODE_PREAD | FMODE_PWRITE;inode = dentry->d_inode;if (f->f_mode & FMODE_WRITE) {error = __get_file_write_access(inode, mnt);if (error)goto cleanup_file;if (!special_file(inode->i_mode))file_take_write(f);}f->f_mapping = inode->i_mapping;f->f_path.dentry = dentry;f->f_path.mnt = mnt;f->f_pos = 0;//调用inode的i_fop或者操作集合f->f_op = fops_get(inode->i_fop);file_move(f, &inode->i_sb->s_files);        //执行security_ops注册的操作集合里的打开处理error = security_dentry_open(f, cred);if (error)goto cleanup_all;if (!open && f->f_op)open = f->f_op->open;if (open) {        //打开文件error = open(inode, f);if (error)goto cleanup_all;}f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);//生成 内存 file文件 并调用fput(f)读取内容        /*         * Initialise a struct file's readahead state.  Assumes that the caller has         * memset *ra to zero.        */file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);/* 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;cleanup_all:fops_put(f->f_op);if (f->f_mode & FMODE_WRITE) {put_write_access(inode);if (!special_file(inode->i_mode)) {/* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */file_reset_write(f);mnt_drop_write(mnt);}}file_kill(f);f->f_path.dentry = NULL;f->f_path.mnt = NULL;cleanup_file:put_filp(f);dput(dentry);mntput(mnt);return ERR_PTR(error);}

函数:fput()

/* __fput is called from task context when aio completion releases the last * last use of a struct file *.  Do not use otherwise. */void __fput(struct file *file){struct dentry *dentry = file->f_path.dentry;struct vfsmount *mnt = file->f_path.mnt;struct inode *inode = dentry->d_inode;might_sleep();fsnotify_close(file);/* * The function eventpoll_release() should be the first called * in the file cleanup chain. */eventpoll_release(file);locks_remove_flock(file);if (unlikely(file->f_flags & FASYNC)) {if (file->f_op && file->f_op->fasync)file->f_op->fasync(-1, file, 0);}if (file->f_op && file->f_op->release)file->f_op->release(inode, file);security_file_free(file);ima_file_free(file);if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))cdev_put(inode->i_cdev);fops_put(file->f_op);put_pid(file->f_owner.pid);file_kill(file);if (file->f_mode & FMODE_WRITE)drop_file_write_access(file);file->f_path.dentry = NULL;file->f_path.mnt = NULL;file_free(file);//对dentry处理dput(dentry);//对mnt处理mntput(mnt);}

函数:dput()

/*  * This is dput * * This is complicated by the fact that we do not want to put * dentries that are no longer on any hash chain on the unused * list: we'd much rather just get rid of them immediately. * * However, that implies that we have to traverse the dentry * tree upwards to the parents which might _also_ now be * scheduled for deletion (it may have been only waiting for * its last child to go away). * * This tail recursion is done by hand as we don't want to depend * on the compiler to always get this right (gcc generally doesn't). * Real recursion would eat up our stack space. *//* * dput - release a dentry * @dentry: dentry to release  * * Release a dentry. This will drop the usage count and if appropriate * call the dentry unlink method as well as removing it from the queues and * releasing its resources. If the parent dentries were scheduled for release * they too may now get deleted. * * no dcache lock, please. */void dput(struct dentry *dentry){if (!dentry)return;repeat:if (atomic_read(&dentry->d_count) == 1)might_sleep();if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock))return;spin_lock(&dentry->d_lock);if (atomic_read(&dentry->d_count)) {spin_unlock(&dentry->d_lock);spin_unlock(&dcache_lock);return;}/* * AV: ->d_delete() is _NOT_ allowed to block now. */if (dentry->d_op && dentry->d_op->d_delete) {if (dentry->d_op->d_delete(dentry))goto unhash_it;}/* Unreachable? Get rid of it */ if (d_unhashed(dentry))goto kill_it;  if (list_empty(&dentry->d_lru)) {  dentry->d_flags |= DCACHE_REFERENCED;dentry_lru_add(dentry);  } spin_unlock(&dentry->d_lock);spin_unlock(&dcache_lock);return;unhash_it:__d_drop(dentry);kill_it:/* if dentry was on the d_lru list delete it from there */dentry_lru_del(dentry);dentry = d_kill(dentry);if (dentry)goto repeat;}
函数:void mntput

static inline void mntput(struct vfsmount *mnt){if (mnt) {mnt->mnt_expiry_mark = 0;mntput_no_expire(mnt);}}







0 0