staticinlineintbuild_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; int acc_mode = ACC_MODE(flags);
/* * Clear out all open flags we don't know about so that we don't report * them in fcntl(F_GETFD) or similar interfaces. */ flags &= VALID_OPEN_FLAGS;
/* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC;
/* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only * check for O_DSYNC if the need any syncing at all we enforce it's * always set instead of having to deal with possibly weird behaviour * for malicious applications setting only __O_SYNC. */ if (flags & __O_SYNC) // if 判断为 0 flags |= O_DSYNC;
if (flags & __O_TMPFILE) { // if 判断为 0 if ((flags & O_TMPFILE_MASK) != O_TMPFILE) return -EINVAL; if (!(acc_mode & MAY_WRITE)) return -EINVAL; } elseif (flags & O_PATH) { /* * If we have O_PATH in the open flag. Then we * cannot have anything other than the below set of flags */ flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; acc_mode = 0; }
op->open_flag = flags;
/* O_TRUNC implies we need access checks for write permissions */ if (flags & O_TRUNC) // if 判断为 0 acc_mode |= MAY_WRITE;
/* Allow the LSM permission hook to distinguish append access from general write access. */ if (flags & O_APPEND) // if 判断为 0 acc_mode |= MAY_APPEND;
op->acc_mode = acc_mode;
op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
if (flags & O_CREAT) { // if 判断为 0 op->intent |= LOOKUP_CREATE; if (flags & O_EXCL) op->intent |= LOOKUP_EXCL; }
if (flags & O_DIRECTORY) // if 判断为 0 lookup_flags |= LOOKUP_DIRECTORY; if (!(flags & O_NOFOLLOW)) // if 判断为 1 lookup_flags |= LOOKUP_FOLLOW; op->lookup_flags = lookup_flags; return0; }
/* * 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. */ staticintlink_path_walk(constchar *name, struct nameidata *nd) { int err;
if (IS_ERR(name)) return PTR_ERR(name); while (*name=='/') name++; if (!*name) // if 判断为 0 return0;
/* At this point we know we have a real path component. */ for(;;) { u64 hash_len; int type;
err = may_lookup(nd); if (err) // if 判断为 0 return err;
hash_len = hash_name(nd->path.dentry, name);
type = LAST_NORM; if (name[0] == '.') // if 判断为 0 // ......
if (likely(type == LAST_NORM)) { // if 判断为 1 structdentry *parent = nd->path.dentry; nd->flags &= ~LOOKUP_JUMPED; if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { // if 判断为 0 // ...... } }
name += hashlen_len(hash_len); if (!*name) // 除了路径中的最后一部分('test.txt')if判断为1,其他 if 判断为 0 goto OK; /* * If it wasn't NUL, we know it was '/'. Skip that * slash, and continue until no more slashes. */ do { name++; } while (unlikely(*name == '/')); if (unlikely(!*name)) { // if 判断为 0 OK: /* pathname body, done */ if (!nd->depth) return0; // 解析到路径最后一部分时,该函数由此处返回 //...... } else { /* not the last component */ err = walk_component(nd, WALK_FOLLOW | WALK_MORE); // err == 0 } if (err < 0) // if 判断为 0 return err;
if (err) { // if 判断为 0 // ...... } if (unlikely(!d_can_lookup(nd->path.dentry))) { // if 判断为 0 //...... } } // go back to for loop }
staticintwalk_component(struct nameidata *nd, int flags) { /* 函数入口参数: flags = WALK_FOLLOW | WALK_MORE */ structpathpath; structinode *inode; unsigned seq; int err; /* * "." and ".." are special - ".." especially so because it has * to be able to know about the current root directory and * parent relationships. */ if (unlikely(nd->last_type != LAST_NORM)) { // if 判断为 0 //...... } err = lookup_fast(nd, &path, &inode, &seq); if (unlikely(err <= 0)) { // if 判断为 0,这里我们假设相应文件的dentry已经存在于系统缓存中 //...... }
staticintlookup_fast(struct nameidata *nd, struct path *path, struct inode **inode, unsigned *seqp) { structvfsmount *mnt = nd->path.mnt; structdentry *dentry, *parent = nd->path.dentry; int status = 1; int err;
/* * Rename seqlock is not required here because in the off chance * of a false negative due to a concurrent rename, the caller is * going to fall back to non-racy lookup. */ if (nd->flags & LOOKUP_RCU) { // if 判断为 1 unsigned seq; bool negative; dentry = __d_lookup_rcu(parent, &nd->last, &seq); if (unlikely(!dentry)) { // if 判断为 0 //...... }
/* * This sequence count validates that the inode matches * the dentry name information from lookup. */ *inode = d_backing_inode(dentry); negative = d_is_negative(dentry); if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) // if 判断为 0 return -ECHILD;
/* * This sequence count validates that the parent had no * changes while we did the lookup of the dentry above. * * The memory barrier in read_seqcount_begin of child is * enough, we can use __read_seqcount_retry here. */ if (unlikely(__read_seqcount_retry(&parent->d_seq, nd->seq))) // if 判断为 0 return -ECHILD;
*seqp = seq; status = d_revalidate(dentry, nd->flags); if (likely(status > 0)) { // if 判断为 1 /* * Note: do negative dentry check after revalidation in * case that drops it. */ if (unlikely(negative)) // if 判断为 0 return -ENOENT; path->mnt = mnt; path->dentry = dentry; if (likely(__follow_mount_rcu(nd, path, inode, seqp))) // if 判断为 1 return1; // 函数从这里返回 } //...... } else { //...... } //...... }
/* * Try to skip to top of mountpoint pile in rcuwalk mode. Fail if * we meet a managed dentry that would need blocking. */ staticbool __follow_mount_rcu(struct nameidata *nd, struct path *path, struct inode **inode, unsigned *seqp) { for (;;) { structmount *mounted; /* * Don't forget we might have a non-mountpoint managed dentry * that wants to block transit. */ switch (managed_dentry_rcu(path)) { // 跳转至 case 0: case -ECHILD: default: returnfalse; case -EISDIR: returntrue; case0: break; }
if (!d_mountpoint(path->dentry)) // if 判断为 0(对应'home'文件夹,则为1 return !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
/* * Do we need to follow links? We _really_ want to be able * to do this check without having to look at inode->i_op, * so we keep a cache of "no, this doesn't need follow_link" * for the common case. */ staticinlineintstep_into(struct nameidata *nd, struct path *path, int flags, struct inode *inode, unsigned seq) { if (!(flags & WALK_MORE) && nd->depth) // if 判断为 0 put_link(nd); if (likely(!d_is_symlink(path->dentry)) || !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) { // if 判断为 1 /* not a symlink or should not follow */ path_to_nameidata(path, nd); nd->inode = inode; nd->seq = seq; return0; // 函数由此处返回 } //...... }
if (nd->last_type != LAST_NORM) { // if 判断为 0 //...... }
if (!(open_flag & O_CREAT)) { // if 判断为 1 if (nd->last.name[nd->last.len]) // if 判断为 0 nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; /* we _can_ be in RCU mode here */ error = lookup_fast(nd, &path, &inode, &seq); if (likely(error > 0)) // if 判断为 1 goto finish_lookup; // 此处进行跳转
//...... } else { //...... } //...... finish_lookup: error = step_into(nd, &path, 0, inode, seq); if (unlikely(error))// if 判断为 0 return error; finish_open: /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ error = complete_walk(nd); if (error) // if 判断为 0 return error; audit_inode(nd->name, nd->path.dentry, 0); if (open_flag & O_CREAT) { // 这里之前看的资料链接不太一样,这里也是直接跳过 //...... } error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))// if 判断为 0 goto out; if (!d_is_reg(nd->path.dentry))// if 判断为 0 will_truncate = false;
if (will_truncate) {// if 判断为 0 //...... } finish_open_created: error = may_open(&nd->path, acc_mode, open_flag); if (error)// if 判断为 0 goto out; BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */ error = vfs_open(&nd->path, file); // 这里是重点,真正执行文件打开的操作 if (error)// if 判断为 0 goto out; opened: error = ima_file_check(file, op->acc_mode);// 这里 error==0 if (!error && will_truncate)// if 判断为 0,will_truncate==0 error = handle_truncate(file); out: if (unlikely(error > 0)) {// if 判断为 0 //...... } if (got_write)// if 判断为 0 mnt_drop_write(nd->path.mnt); return error; }
/** * complete_walk - successful completion of path walk * @nd: pointer nameidata * * If we had been in RCU mode, drop out of it and legitimize nd->path. * Revalidate the final result, unless we'd already done that during * the path walk or the filesystem doesn't ask for it. Return 0 on * success, -error on failure. In case of failure caller does not * need to drop nd->path. */ staticintcomplete_walk(struct nameidata *nd) { structdentry *dentry = nd->path.dentry; int status;
if (nd->flags & LOOKUP_RCU) { // if 判断为 1 if (!(nd->flags & LOOKUP_ROOT)) // if 判断为 1 nd->root.mnt = NULL; if (unlikely(unlazy_walk(nd))) // if 判断为 0 return -ECHILD; }
if (likely(!(nd->flags & LOOKUP_JUMPED))) // if 判断为 1 return0; //函数返回 //...... }
/** * unlazy_walk - try to switch to ref-walk mode. * @nd: nameidata pathwalk data * Returns: 0 on success, -ECHILD on failure * * unlazy_walk attempts to legitimize the current nd->path and nd->root * for ref-walk mode. * Must be called from rcu-walk context. * Nothing should touch nameidata between unlazy_walk() failure and * terminate_walk(). */ staticintunlazy_walk(struct nameidata *nd) { structdentry *parent = nd->path.dentry;
BUG_ON(!(nd->flags & LOOKUP_RCU));
nd->flags &= ~LOOKUP_RCU; if (unlikely(!legitimize_links(nd))) // if 判断为 0 goto out2; if (unlikely(!legitimize_path(nd, &nd->path, nd->seq))) // if 判断为 0 goto out1; if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { // if 判断为 0 //...... } rcu_read_unlock(); BUG_ON(nd->inode != parent->d_inode); return0; //...... }
/* * vfsmount lock must be held for read */ staticinlinevoidmnt_add_count(struct mount *mnt, int n) { #ifdef CONFIG_SMP this_cpu_add(mnt->mnt_pcp->mnt_count, n); // 略去多核cpu同步等问题,等价与 mnt->mnt_pcp->mnt_count += n #else //...... #endif }
/** * vfs_open - open the file at the given path * @path: path to open * @file: newly allocated file with f_flag initialized * @cred: credentials to use */ intvfs_open(conststruct path *path, struct file *file) { file->f_path = *path; return do_dentry_open(file, d_backing_inode(path->dentry), NULL); }
/* Ensure that we skip any errors that predate opening of the file */ f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
if (unlikely(f->f_flags & O_PATH)) { // if 判断为 0 //...... }
/* Any file opened for execve()/uselib() has to be a regular file. */ if (unlikely(f->f_flags & FMODE_EXEC && !S_ISREG(inode->i_mode))) {// if 判断为 0 //...... }
if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { // if 判断为 0 //...... }
/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) // if 判断为 1 f->f_mode |= FMODE_ATOMIC_POS;
f->f_op = fops_get(inode->i_fop); if (unlikely(WARN_ON(!f->f_op))) { // if 判断为 0 //...... }
error = security_file_open(f); if (error)// if 判断为 0 goto cleanup_all;
error = break_lease(locks_inode(f), f->f_flags); if (error)// if 判断为 0 goto cleanup_all;
/* normally all 3 are set; ->open() can clear them if needed */ f->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (!open) // if 判断为 1 open = f->f_op->open; if (open) { // if 判断为 1 error = open(inode, f); if (error) // if 判断为 0 goto cleanup_all; } f->f_mode |= FMODE_OPENED; if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); if ((f->f_mode & FMODE_READ) && likely(f->f_op->read || f->f_op->read_iter)) f->f_mode |= FMODE_CAN_READ; if ((f->f_mode & FMODE_WRITE) && likely(f->f_op->write || f->f_op->write_iter)) f->f_mode |= FMODE_CAN_WRITE;
/* 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) return -EINVAL; } return0; //...... }