/* * simple tests for rename. * following the checks in vfs, plus the parent-child relationship. */ static int au_may_ren(struct au_ren_args *a) { int err, isdir; struct inode *h_inode; if (a->src_bstart == a->btgt) { err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, au_ftest_ren(a->flags, ISDIR)); if (unlikely(err)) goto out; err = -EINVAL; if (unlikely(a->src_h_dentry == a->h_trap)) goto out; } err = 0; if (a->dst_bstart != a->btgt) goto out; err = -ENOTEMPTY; if (unlikely(a->dst_h_dentry == a->h_trap)) goto out; err = -EIO; h_inode = a->dst_h_dentry->d_inode; isdir = !!au_ftest_ren(a->flags, ISDIR); if (!a->dst_dentry->d_inode) { if (unlikely(h_inode)) goto out; err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, isdir); } else { if (unlikely(!h_inode || !h_inode->i_nlink)) goto out; err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, isdir); if (unlikely(err)) goto out; } out: if (unlikely(err == -ENOENT || err == -EEXIST)) err = -EIO; AuTraceErr(err); return err; }
/* * decide the branch where we operate for @dentry. the branch index will be set * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent * dir for reverting. * when a new whiteout is necessary, create it. */ static struct dentry* lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, struct au_dtime *dt, struct au_pin *pin) { struct dentry *wh_dentry; struct super_block *sb; struct path h_path; int err, need_wh; unsigned int udba; aufs_bindex_t bcpup; need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); wh_dentry = ERR_PTR(need_wh); if (unlikely(need_wh < 0)) goto out; sb = dentry->d_sb; udba = au_opt_udba(sb); bcpup = *rbcpup; err = au_pin(pin, dentry, bcpup, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); wh_dentry = ERR_PTR(err); if (unlikely(err)) goto out; h_path.dentry = au_pinned_h_parent(pin); if (udba != AuOpt_UDBA_NONE && au_dbstart(dentry) == bcpup) { err = au_may_del(dentry, bcpup, h_path.dentry, isdir); wh_dentry = ERR_PTR(err); if (unlikely(err)) goto out_unpin; } h_path.mnt = au_sbr_mnt(sb, bcpup); au_dtime_store(dt, au_pinned_parent(pin), &h_path); wh_dentry = NULL; if (!need_wh) goto out; /* success, no need to create whiteout */ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); if (IS_ERR(wh_dentry)) goto out_unpin; /* returns with the parent is locked and wh_dentry is dget-ed */ goto out; /* success */ out_unpin: au_unpin(pin); out: return wh_dentry; }