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
- nfs笔记:open
- ubuntu nfs service open
- NFS笔记
- nfs 笔记
- NFS简易配置笔记
- 嵌入式NFS配置笔记
- NFS 服务学习笔记
- NFS学习笔记
- nfs 挂载 笔记1
- linux服务器nfs笔记
- NFS服务器配置 笔记
- ubuntu14笔记: 安装NFS
- nfs挂载根文件系统笔记
- NFS安装笔记
- busybox nfs 学习笔记
- NFS服务学习笔记
- linux笔记-nfs
- LInux学习笔记 --NFS
- (Robotium)写了个滑动屏幕的方法,分享给大家
- 去酒店做全套可吹可做
- 兼職酒店開房聯系
- 大神求帮忙啊 我用tq2440 移植rtl8192cu
- Windows C编程操作鼠标键盘
- nfs笔记:open
- 找全套保健哪里有
- [学习opencv]高斯、中值、均值、双边滤波
- 去酒店做全套可吹可做
- 兼職酒店開房聯系
- 找全套保健哪里有
- Basic operations with opencv 3.0
- tinyxml demo
- .net tostring format格式说明