/* common function to regular file and dir */ int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), int wlock) { int err; unsigned int sigen, figen; aufs_bindex_t bstart; unsigned char pseudo_link; struct dentry *dentry; struct inode *inode; err = 0; dentry = file->f_dentry; inode = dentry->d_inode; AuDebugOn(au_special_file(inode->i_mode)); sigen = au_sigen(dentry->d_sb); fi_write_lock(file); figen = au_figen(file); di_write_lock_child(dentry); bstart = au_dbstart(dentry); pseudo_link = (bstart != au_ibstart(inode)); if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { if (!wlock) { di_downgrade_lock(dentry, AuLock_IR); fi_downgrade_lock(file); } goto out; /* success */ } AuDbg("sigen %d, figen %d\n", sigen, figen); if (sigen != au_digen(dentry) || sigen != au_iigen(inode)) { err = au_reval_dpath(dentry, sigen); if (unlikely(err < 0)) goto out; AuDebugOn(au_digen(dentry) != sigen || au_iigen(inode) != sigen); } err = refresh_file(file, reopen); if (!err) { if (!wlock) { di_downgrade_lock(dentry, AuLock_IR); fi_downgrade_lock(file); } } else { di_write_unlock(dentry); fi_write_unlock(file); } out: return err; }
void au_finfo_fin(struct file *file) { struct au_finfo *finfo; aufs_bindex_t bindex, bend; fi_write_lock(file); bend = au_fbend(file); bindex = au_fbstart(file); if (bindex >= 0) /* * calls fput() instead of filp_close(), * since no dnotify or lock for the lower file. */ for (; bindex <= bend; bindex++) au_set_h_fptr(file, bindex, NULL); finfo = au_fi(file); au_dbg_verify_hf(finfo); kfree(finfo->fi_hfile); fi_write_unlock(file); AuRwDestroy(&finfo->fi_rwsem); au_cache_free_finfo(finfo); }
int au_do_open(struct file *file, int (*open)(struct file *file, int flags), struct au_fidir *fidir) { int err; struct dentry *dentry; err = au_finfo_init(file, fidir); if (unlikely(err)) goto out; dentry = file->f_dentry; di_read_lock_child(dentry, AuLock_IR); err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); fi_write_unlock(file); if (unlikely(err)) { au_fi(file)->fi_hdir = NULL; au_finfo_fin(file); } out: return err; }
int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) { int err; struct dentry *dentry; struct super_block *sb; dentry = file->f_dentry; sb = dentry->d_sb; si_read_lock(sb, AuLock_FLUSH); err = au_finfo_init(file); if (unlikely(err)) goto out; di_read_lock_child(dentry, AuLock_IR); err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); fi_write_unlock(file); if (unlikely(err)) au_finfo_fin(file); out: si_read_unlock(sb); return err; }
/* 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; }
int au_do_open(struct inode *inode, struct file *file, int (*open)(struct file *file, int flags)) { int err, coo; struct dentry *dentry; struct super_block *sb; aufs_bindex_t bstart; struct inode *h_dir, *dir; dentry = file->f_dentry; LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry)); sb = dentry->d_sb; si_read_lock(sb); coo = 0; #if 0 switch (au_flag_test_coo(sb)) { case AuFlag_COO_LEAF: coo = !S_ISDIR(inode->i_mode); break; case AuFlag_COO_ALL: coo = 1; break; } #endif err = au_init_finfo(file); //if (LktrCond) {fi_write_unlock(file); fin_finfo(file); err = -1;} if (unlikely(err)) goto out; if (!coo) { di_read_lock_child(dentry, AUFS_I_RLOCK); bstart = dbstart(dentry); } else { di_write_lock_child(dentry); bstart = dbstart(dentry); if (test_ro(sb, bstart, dentry->d_inode)) { err = do_coo(dentry, bstart); if (err) { di_write_unlock(dentry); goto out_finfo; } bstart = dbstart(dentry); } di_downgrade_lock(dentry, AUFS_I_RLOCK); } // todo: remove this extra locks dir = dentry->d_parent->d_inode; if (!IS_ROOT(dentry)) ii_read_lock_parent(dir); h_dir = au_h_iptr_i(dir, bstart); hdir_lock(h_dir, dir, bstart); err = open(file, file->f_flags); //if (LktrCond) err = -1; hdir_unlock(h_dir, dir, bstart); if (!IS_ROOT(dentry)) ii_read_unlock(dir); di_read_unlock(dentry, AUFS_I_RLOCK); out_finfo: fi_write_unlock(file); if (unlikely(err)) au_fin_finfo(file); //DbgFile(file); out: si_read_unlock(sb); TraceErr(err); return err; }
static int au_cmoo(struct dentry *dentry) { int err, cmoo; unsigned int udba; struct path h_path; struct au_pin pin; struct au_cp_generic cpg = { .dentry = dentry, .bdst = -1, .bsrc = -1, .len = -1, .pin = &pin, .flags = AuCpup_DTIME | AuCpup_HOPEN }; struct inode *inode, *delegated; struct super_block *sb; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; pid_t pid; struct au_branch *br; struct dentry *parent; struct au_hinode *hdir; DiMustWriteLock(dentry); inode = dentry->d_inode; IiMustWriteLock(inode); err = 0; if (IS_ROOT(dentry)) goto out; cpg.bsrc = au_dbstart(dentry); if (!cpg.bsrc) goto out; sb = dentry->d_sb; sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; pid = au_fhsm_pid(fhsm); if (pid && (current->pid == pid || current->real_parent->pid == pid)) goto out; br = au_sbr(sb, cpg.bsrc); cmoo = au_br_cmoo(br->br_perm); if (!cmoo) goto out; if (!S_ISREG(inode->i_mode)) cmoo &= AuBrAttr_COO_ALL; if (!cmoo) goto out; parent = dget_parent(dentry); di_write_lock_parent(parent); err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); cpg.bdst = err; if (unlikely(err < 0)) { err = 0; /* there is no upper writable branch */ goto out_dgrade; } AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); /* do not respect the coo attrib for the target branch */ err = au_cpup_dirs(dentry, cpg.bdst); if (unlikely(err)) goto out_dgrade; di_downgrade_lock(parent, AuLock_IR); udba = au_opt_udba(sb); err = au_pin(&pin, dentry, cpg.bdst, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; err = au_sio_cpup_simple(&cpg); au_unpin(&pin); if (unlikely(err)) goto out_parent; if (!(cmoo & AuBrWAttr_MOO)) goto out_parent; /* success */ err = au_pin(&pin, dentry, cpg.bsrc, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; h_path.mnt = au_br_mnt(br); h_path.dentry = au_h_dptr(dentry, cpg.bsrc); hdir = au_hi(parent->d_inode, cpg.bsrc); delegated = NULL; err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); au_unpin(&pin); /* todo: keep h_dentry or not? */ if (unlikely(err == -EWOULDBLOCK)) { pr_warn("cannot retry for NFSv4 delegation" " for an internal unlink\n"); iput(delegated); } if (unlikely(err)) { pr_err("unlink %pd after coo failed (%d), ignored\n", dentry, err); err = 0; } goto out_parent; /* success */ out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_parent: di_read_unlock(parent, AuLock_IR); dput(parent); out: AuTraceErr(err); return err; } int au_do_open(struct file *file, int (*open)(struct file *file, int flags), struct au_fidir *fidir) { int err; struct dentry *dentry; struct au_finfo *finfo; err = au_finfo_init(file, fidir); if (unlikely(err)) goto out; dentry = file->f_path.dentry; di_write_lock_child(dentry); err = au_cmoo(dentry); di_downgrade_lock(dentry, AuLock_IR); if (!err) err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); finfo = au_fi(file); if (!err) { finfo->fi_file = file; au_sphl_add(&finfo->fi_hlist, &au_sbi(file->f_path.dentry->d_sb)->si_files); } fi_write_unlock(file); if (unlikely(err)) { finfo->fi_hdir = NULL; au_finfo_fin(file); } out: return err; }