static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *parent; struct file *file; struct inode *dir; struct find_name_by_ino arg; int err; parent = path->dentry; if (nsi_lock) si_read_unlock(parent->d_sb); file = vfsub_dentry_open(path, au_dir_roflags); dentry = (void *)file; if (IS_ERR(file)) goto out; dentry = ERR_PTR(-ENOMEM); arg.name = __getname_gfp(GFP_NOFS); if (unlikely(!arg.name)) goto out_file; arg.ino = ino; arg.found = 0; do { arg.called = 0; /* smp_mb(); */ err = vfsub_readdir(file, find_name_by_ino, &arg); } while (!err && !arg.found && arg.called); dentry = ERR_PTR(err); if (unlikely(err)) goto out_name; dentry = ERR_PTR(-ENOENT); if (!arg.found) goto out_name; /* do not call au_lkup_one() */ dir = parent->d_inode; mutex_lock(&dir->i_mutex); dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); mutex_unlock(&dir->i_mutex); AuTraceErrPtr(dentry); if (IS_ERR(dentry)) goto out_name; AuDebugOn(au_test_anon(dentry)); if (unlikely(!dentry->d_inode)) { dput(dentry); dentry = ERR_PTR(-ENOENT); } out_name: __putname(arg.name); out_file: fput(file); out: if (unlikely(nsi_lock && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) if (!IS_ERR(dentry)) { dput(dentry); dentry = ERR_PTR(-ESTALE); } AuTraceErrPtr(dentry); return dentry; }
/* common functions to regular file and dir */ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, struct file *file) { struct file *h_file; struct dentry *h_dentry; struct inode *h_inode; struct super_block *sb; struct au_branch *br; struct path h_path; int err, exec_flag; /* a race condition can happen between open and unlink/rmdir */ h_file = ERR_PTR(-ENOENT); h_dentry = au_h_dptr(dentry, bindex); if (au_test_nfsd() && !h_dentry) goto out; h_inode = h_dentry->d_inode; if (au_test_nfsd() && !h_inode) goto out; spin_lock(&h_dentry->d_lock); err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) || !h_inode /* || !dentry->d_inode->i_nlink */ ; spin_unlock(&h_dentry->d_lock); if (unlikely(err)) goto out; sb = dentry->d_sb; br = au_sbr(sb, bindex); h_file = ERR_PTR(-EACCES); exec_flag = flags & __FMODE_EXEC; if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC)) goto out; /* drop flags for writing */ if (au_test_ro(sb, bindex, dentry->d_inode)) flags = au_file_roflags(flags); flags &= ~O_CREAT; atomic_inc(&br->br_count); h_path.dentry = h_dentry; h_path.mnt = br->br_mnt; if (!au_special_file(h_inode->i_mode)) h_file = vfsub_dentry_open(&h_path, flags); else { /* this block depends upon the configuration */ di_read_unlock(dentry, AuLock_IR); fi_write_unlock(file); si_read_unlock(sb); h_file = vfsub_dentry_open(&h_path, flags); si_noflush_read_lock(sb); fi_write_lock(file); di_read_lock_child(dentry, AuLock_IR); } if (IS_ERR(h_file)) goto out_br; if (exec_flag) { err = deny_write_access(h_file); if (unlikely(err)) { fput(h_file); h_file = ERR_PTR(err); goto out_br; } } fsnotify_open(h_file); goto out; /* success */ out_br: atomic_dec(&br->br_count); out: return h_file; }
/* common functions to regular file and dir */ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, struct file *file, int force_wr) { struct file *h_file; struct dentry *h_dentry; struct inode *h_inode; struct super_block *sb; struct au_branch *br; struct path h_path; int err, exec_flag; /* a race condition can happen between open and unlink/rmdir */ h_file = ERR_PTR(-ENOENT); h_dentry = au_h_dptr(dentry, bindex); if (au_test_nfsd() && !h_dentry) goto out; h_inode = h_dentry->d_inode; if (au_test_nfsd() && !h_inode) goto out; spin_lock(&h_dentry->d_lock); err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) || !h_inode /* || !dentry->d_inode->i_nlink */ ; spin_unlock(&h_dentry->d_lock); if (unlikely(err)) goto out; sb = dentry->d_sb; br = au_sbr(sb, bindex); h_file = ERR_PTR(-EACCES); exec_flag = flags & __FMODE_EXEC; if (exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC)) goto out; /* drop flags for writing */ if (au_test_ro(sb, bindex, dentry->d_inode)) { if (force_wr && !(flags & O_WRONLY)) force_wr = 0; flags = au_file_roflags(flags); if (force_wr) { h_file = ERR_PTR(-EROFS); flags = au_file_roflags(flags); if (unlikely(vfsub_native_ro(h_inode) || IS_APPEND(h_inode))) goto out; flags &= ~O_ACCMODE; flags |= O_WRONLY; } } flags &= ~O_CREAT; atomic_inc(&br->br_count); h_path.dentry = h_dentry; h_path.mnt = au_br_mnt(br); h_file = vfsub_dentry_open(&h_path, flags); if (IS_ERR(h_file)) goto out_br; if (exec_flag) { err = deny_write_access(h_file); if (unlikely(err)) { fput(h_file); h_file = ERR_PTR(err); goto out_br; } } fsnotify_open(h_file); goto out; /* success */ out_br: atomic_dec(&br->br_count); out: return h_file; }