/* 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; }