diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-09-08 01:01:14 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-09-08 01:01:14 -0300 |
commit | e5fd91f1ef340da553f7a79da9540c3db711c937 (patch) | |
tree | b11842027dc6641da63f4bcc524f8678263304a3 /fs/aufs/mvdown.c | |
parent | 2a9b0348e685a63d97486f6749622b61e9e3292f (diff) |
Linux-libre 4.2-gnu
Diffstat (limited to 'fs/aufs/mvdown.c')
-rw-r--r-- | fs/aufs/mvdown.c | 694 |
1 files changed, 0 insertions, 694 deletions
diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c deleted file mode 100644 index 25e3a80b9..000000000 --- a/fs/aufs/mvdown.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (C) 2011-2015 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* - * move-down, opposite of copy-up - */ - -#include "aufs.h" - -struct au_mvd_args { - struct { - struct super_block *h_sb; - struct dentry *h_parent; - struct au_hinode *hdir; - struct inode *h_dir, *h_inode; - struct au_pin pin; - } info[AUFS_MVDOWN_NARRAY]; - - struct aufs_mvdown mvdown; - struct dentry *dentry, *parent; - struct inode *inode, *dir; - struct super_block *sb; - aufs_bindex_t bopq, bwh, bfound; - unsigned char rename_lock; -}; - -#define mvd_errno mvdown.au_errno -#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex -#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid -#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex -#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid - -#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb -#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent -#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir -#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir -#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode -#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin - -#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb -#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent -#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir -#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir -#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode -#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin - -#define AU_MVD_PR(flag, ...) do { \ - if (flag) \ - pr_err(__VA_ARGS__); \ - } while (0) - -static int find_lower_writable(struct au_mvd_args *a) -{ - struct super_block *sb; - aufs_bindex_t bindex, bend; - struct au_branch *br; - - sb = a->sb; - bindex = a->mvd_bsrc; - bend = au_sbend(sb); - if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) - for (bindex++; bindex <= bend; bindex++) { - br = au_sbr(sb, bindex); - if (au_br_fhsm(br->br_perm) - && (!(au_br_sb(br)->s_flags & MS_RDONLY))) - return bindex; - } - else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) - for (bindex++; bindex <= bend; bindex++) { - br = au_sbr(sb, bindex); - if (!au_br_rdonly(br)) - return bindex; - } - else - for (bindex++; bindex <= bend; bindex++) { - br = au_sbr(sb, bindex); - if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { - if (au_br_rdonly(br)) - a->mvdown.flags - |= AUFS_MVDOWN_ROLOWER_R; - return bindex; - } - } - - return -1; -} - -/* make the parent dir on bdst */ -static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - - err = 0; - a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); - a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); - a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); - a->mvd_h_dst_parent = NULL; - if (au_dbend(a->parent) >= a->mvd_bdst) - a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); - if (!a->mvd_h_dst_parent) { - err = au_cpdown_dirs(a->dentry, a->mvd_bdst); - if (unlikely(err)) { - AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); - goto out; - } - a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); - } - -out: - AuTraceErr(err); - return err; -} - -/* lock them all */ -static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct dentry *h_trap; - - a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); - a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); - err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, - au_opt_udba(a->sb), - AuPin_MNT_WRITE | AuPin_DI_LOCKED); - AuTraceErr(err); - if (unlikely(err)) { - AU_MVD_PR(dmsg, "pin_dst failed\n"); - goto out; - } - - if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { - a->rename_lock = 0; - au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, - AuLsc_DI_PARENT, AuLsc_I_PARENT3, - au_opt_udba(a->sb), - AuPin_MNT_WRITE | AuPin_DI_LOCKED); - err = au_do_pin(&a->mvd_pin_src); - AuTraceErr(err); - a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); - if (unlikely(err)) { - AU_MVD_PR(dmsg, "pin_src failed\n"); - goto out_dst; - } - goto out; /* success */ - } - - a->rename_lock = 1; - au_pin_hdir_unlock(&a->mvd_pin_dst); - err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, - au_opt_udba(a->sb), - AuPin_MNT_WRITE | AuPin_DI_LOCKED); - AuTraceErr(err); - a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); - if (unlikely(err)) { - AU_MVD_PR(dmsg, "pin_src failed\n"); - au_pin_hdir_lock(&a->mvd_pin_dst); - goto out_dst; - } - au_pin_hdir_unlock(&a->mvd_pin_src); - h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, - a->mvd_h_dst_parent, a->mvd_hdir_dst); - if (h_trap) { - err = (h_trap != a->mvd_h_src_parent); - if (err) - err = (h_trap != a->mvd_h_dst_parent); - } - BUG_ON(err); /* it should never happen */ - if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { - err = -EBUSY; - AuTraceErr(err); - vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, - a->mvd_h_dst_parent, a->mvd_hdir_dst); - au_pin_hdir_lock(&a->mvd_pin_src); - au_unpin(&a->mvd_pin_src); - au_pin_hdir_lock(&a->mvd_pin_dst); - goto out_dst; - } - goto out; /* success */ - -out_dst: - au_unpin(&a->mvd_pin_dst); -out: - AuTraceErr(err); - return err; -} - -static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) -{ - if (!a->rename_lock) - au_unpin(&a->mvd_pin_src); - else { - vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, - a->mvd_h_dst_parent, a->mvd_hdir_dst); - au_pin_hdir_lock(&a->mvd_pin_src); - au_unpin(&a->mvd_pin_src); - au_pin_hdir_lock(&a->mvd_pin_dst); - } - au_unpin(&a->mvd_pin_dst); -} - -/* copy-down the file */ -static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct au_cp_generic cpg = { - .dentry = a->dentry, - .bdst = a->mvd_bdst, - .bsrc = a->mvd_bsrc, - .len = -1, - .pin = &a->mvd_pin_dst, - .flags = AuCpup_DTIME | AuCpup_HOPEN - }; - - AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); - if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) - au_fset_cpup(cpg.flags, OVERWRITE); - if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) - au_fset_cpup(cpg.flags, RWDST); - err = au_sio_cpdown_simple(&cpg); - if (unlikely(err)) - AU_MVD_PR(dmsg, "cpdown failed\n"); - - AuTraceErr(err); - return err; -} - -/* - * unlink the whiteout on bdst if exist which may be created by UDBA while we - * were sleeping - */ -static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct path h_path; - struct au_branch *br; - struct inode *delegated; - - br = au_sbr(a->sb, a->mvd_bdst); - h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); - err = PTR_ERR(h_path.dentry); - if (IS_ERR(h_path.dentry)) { - AU_MVD_PR(dmsg, "wh_lkup failed\n"); - goto out; - } - - err = 0; - if (d_is_positive(h_path.dentry)) { - h_path.mnt = au_br_mnt(br); - delegated = NULL; - err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, - &delegated, /*force*/0); - if (unlikely(err == -EWOULDBLOCK)) { - pr_warn("cannot retry for NFSv4 delegation" - " for an internal unlink\n"); - iput(delegated); - } - if (unlikely(err)) - AU_MVD_PR(dmsg, "wh_unlink failed\n"); - } - dput(h_path.dentry); - -out: - AuTraceErr(err); - return err; -} - -/* - * unlink the topmost h_dentry - */ -static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct path h_path; - struct inode *delegated; - - h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); - h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); - delegated = NULL; - err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); - if (unlikely(err == -EWOULDBLOCK)) { - pr_warn("cannot retry for NFSv4 delegation" - " for an internal unlink\n"); - iput(delegated); - } - if (unlikely(err)) - AU_MVD_PR(dmsg, "unlink failed\n"); - - AuTraceErr(err); - return err; -} - -/* Since mvdown succeeded, we ignore an error of this function */ -static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct au_branch *br; - - a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; - br = au_sbr(a->sb, a->mvd_bsrc); - err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); - if (!err) { - br = au_sbr(a->sb, a->mvd_bdst); - a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; - err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); - } - if (!err) - a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; - else - AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); -} - -/* - * copy-down the file and unlink the bsrc file. - * - unlink the bdst whout if exist - * - copy-down the file (with whtmp name and rename) - * - unlink the bsrc file - */ -static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - - err = au_do_mkdir(dmsg, a); - if (!err) - err = au_do_lock(dmsg, a); - if (unlikely(err)) - goto out; - - /* - * do not revert the activities we made on bdst since they should be - * harmless in aufs. - */ - - err = au_do_cpdown(dmsg, a); - if (!err) - err = au_do_unlink_wh(dmsg, a); - if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) - err = au_do_unlink(dmsg, a); - if (unlikely(err)) - goto out_unlock; - - AuDbg("%pd2, 0x%x, %d --> %d\n", - a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); - if (find_lower_writable(a) < 0) - a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; - - if (a->mvdown.flags & AUFS_MVDOWN_STFS) - au_do_stfs(dmsg, a); - - /* maintain internal array */ - if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { - au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); - au_set_dbstart(a->dentry, a->mvd_bdst); - au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); - au_set_ibstart(a->inode, a->mvd_bdst); - } - if (au_dbend(a->dentry) < a->mvd_bdst) - au_set_dbend(a->dentry, a->mvd_bdst); - if (au_ibend(a->inode) < a->mvd_bdst) - au_set_ibend(a->inode, a->mvd_bdst); - -out_unlock: - au_do_unlock(dmsg, a); -out: - AuTraceErr(err); - return err; -} - -/* ---------------------------------------------------------------------- */ - -/* make sure the file is idle */ -static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err, plinked; - - err = 0; - plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); - if (au_dbstart(a->dentry) == a->mvd_bsrc - && au_dcount(a->dentry) == 1 - && atomic_read(&a->inode->i_count) == 1 - /* && a->mvd_h_src_inode->i_nlink == 1 */ - && (!plinked || !au_plink_test(a->inode)) - && a->inode->i_nlink == 1) - goto out; - - err = -EBUSY; - AU_MVD_PR(dmsg, - "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", - a->mvd_bsrc, au_dbstart(a->dentry), au_dcount(a->dentry), - atomic_read(&a->inode->i_count), a->inode->i_nlink, - a->mvd_h_src_inode->i_nlink, - plinked, plinked ? au_plink_test(a->inode) : 0); - -out: - AuTraceErr(err); - return err; -} - -/* make sure the parent dir is fine */ -static int au_mvd_args_parent(const unsigned char dmsg, - struct au_mvd_args *a) -{ - int err; - aufs_bindex_t bindex; - - err = 0; - if (unlikely(au_alive_dir(a->parent))) { - err = -ENOENT; - AU_MVD_PR(dmsg, "parent dir is dead\n"); - goto out; - } - - a->bopq = au_dbdiropq(a->parent); - bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); - AuDbg("b%d\n", bindex); - if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) - || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { - err = -EINVAL; - a->mvd_errno = EAU_MVDOWN_OPAQUE; - AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", - a->bopq, a->mvd_bdst); - } - -out: - AuTraceErr(err); - return err; -} - -static int au_mvd_args_intermediate(const unsigned char dmsg, - struct au_mvd_args *a) -{ - int err; - struct au_dinfo *dinfo, *tmp; - - /* lookup the next lower positive entry */ - err = -ENOMEM; - tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); - if (unlikely(!tmp)) - goto out; - - a->bfound = -1; - a->bwh = -1; - dinfo = au_di(a->dentry); - au_di_cp(tmp, dinfo); - au_di_swap(tmp, dinfo); - - /* returns the number of positive dentries */ - err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0); - if (!err) - a->bwh = au_dbwh(a->dentry); - else if (err > 0) - a->bfound = au_dbstart(a->dentry); - - au_di_swap(tmp, dinfo); - au_rw_write_unlock(&tmp->di_rwsem); - au_di_free(tmp); - if (unlikely(err < 0)) - AU_MVD_PR(dmsg, "failed look-up lower\n"); - - /* - * here, we have these cases. - * bfound == -1 - * no positive dentry under bsrc. there are more sub-cases. - * bwh < 0 - * there no whiteout, we can safely move-down. - * bwh <= bsrc - * impossible - * bsrc < bwh && bwh < bdst - * there is a whiteout on RO branch. cannot proceed. - * bwh == bdst - * there is a whiteout on the RW target branch. it should - * be removed. - * bdst < bwh - * there is a whiteout somewhere unrelated branch. - * -1 < bfound && bfound <= bsrc - * impossible. - * bfound < bdst - * found, but it is on RO branch between bsrc and bdst. cannot - * proceed. - * bfound == bdst - * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return - * error. - * bdst < bfound - * found, after we create the file on bdst, it will be hidden. - */ - - AuDebugOn(a->bfound == -1 - && a->bwh != -1 - && a->bwh <= a->mvd_bsrc); - AuDebugOn(-1 < a->bfound - && a->bfound <= a->mvd_bsrc); - - err = -EINVAL; - if (a->bfound == -1 - && a->mvd_bsrc < a->bwh - && a->bwh != -1 - && a->bwh < a->mvd_bdst) { - a->mvd_errno = EAU_MVDOWN_WHITEOUT; - AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", - a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); - goto out; - } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { - a->mvd_errno = EAU_MVDOWN_UPPER; - AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", - a->mvd_bdst, a->bfound); - goto out; - } - - err = 0; /* success */ - -out: - AuTraceErr(err); - return err; -} - -static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - - err = 0; - if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) - && a->bfound == a->mvd_bdst) - err = -EEXIST; - AuTraceErr(err); - return err; -} - -static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) -{ - int err; - struct au_branch *br; - - err = -EISDIR; - if (unlikely(S_ISDIR(a->inode->i_mode))) - goto out; - - err = -EINVAL; - if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) - a->mvd_bsrc = au_ibstart(a->inode); - else { - a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); - if (unlikely(a->mvd_bsrc < 0 - || (a->mvd_bsrc < au_dbstart(a->dentry) - || au_dbend(a->dentry) < a->mvd_bsrc - || !au_h_dptr(a->dentry, a->mvd_bsrc)) - || (a->mvd_bsrc < au_ibstart(a->inode) - || au_ibend(a->inode) < a->mvd_bsrc - || !au_h_iptr(a->inode, a->mvd_bsrc)))) { - a->mvd_errno = EAU_MVDOWN_NOUPPER; - AU_MVD_PR(dmsg, "no upper\n"); - goto out; - } - } - if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) { - a->mvd_errno = EAU_MVDOWN_BOTTOM; - AU_MVD_PR(dmsg, "on the bottom\n"); - goto out; - } - a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); - br = au_sbr(a->sb, a->mvd_bsrc); - err = au_br_rdonly(br); - if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { - if (unlikely(err)) - goto out; - } else if (!(vfsub_native_ro(a->mvd_h_src_inode) - || IS_APPEND(a->mvd_h_src_inode))) { - if (err) - a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; - /* go on */ - } else - goto out; - - err = -EINVAL; - if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { - a->mvd_bdst = find_lower_writable(a); - if (unlikely(a->mvd_bdst < 0)) { - a->mvd_errno = EAU_MVDOWN_BOTTOM; - AU_MVD_PR(dmsg, "no writable lower branch\n"); - goto out; - } - } else { - a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); - if (unlikely(a->mvd_bdst < 0 - || au_sbend(a->sb) < a->mvd_bdst)) { - a->mvd_errno = EAU_MVDOWN_NOLOWERBR; - AU_MVD_PR(dmsg, "no lower brid\n"); - goto out; - } - } - - err = au_mvd_args_busy(dmsg, a); - if (!err) - err = au_mvd_args_parent(dmsg, a); - if (!err) - err = au_mvd_args_intermediate(dmsg, a); - if (!err) - err = au_mvd_args_exist(dmsg, a); - if (!err) - AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); - -out: - AuTraceErr(err); - return err; -} - -int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) -{ - int err, e; - unsigned char dmsg; - struct au_mvd_args *args; - - err = -EPERM; - if (unlikely(!capable(CAP_SYS_ADMIN))) - goto out; - - err = -ENOMEM; - args = kmalloc(sizeof(*args), GFP_NOFS); - if (unlikely(!args)) - goto out; - - err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); - if (!err) - err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg)); - if (unlikely(err)) { - err = -EFAULT; - AuTraceErr(err); - goto out_free; - } - AuDbg("flags 0x%x\n", args->mvdown.flags); - args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); - args->mvdown.au_errno = 0; - args->dentry = dentry; - args->inode = d_inode(dentry); - args->sb = dentry->d_sb; - - err = -ENOENT; - dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); - args->parent = dget_parent(dentry); - args->dir = d_inode(args->parent); - mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT); - dput(args->parent); - if (unlikely(args->parent != dentry->d_parent)) { - AU_MVD_PR(dmsg, "parent dir is moved\n"); - goto out_dir; - } - - mutex_lock_nested(&args->inode->i_mutex, I_MUTEX_CHILD); - err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH); - if (unlikely(err)) - goto out_inode; - - di_write_lock_parent(args->parent); - err = au_mvd_args(dmsg, args); - if (unlikely(err)) - goto out_parent; - - err = au_do_mvdown(dmsg, args); - if (unlikely(err)) - goto out_parent; - - au_cpup_attr_timesizes(args->dir); - au_cpup_attr_timesizes(args->inode); - au_cpup_igen(args->inode, au_h_iptr(args->inode, args->mvd_bdst)); - /* au_digen_dec(dentry); */ - -out_parent: - di_write_unlock(args->parent); - aufs_read_unlock(dentry, AuLock_DW); -out_inode: - mutex_unlock(&args->inode->i_mutex); -out_dir: - mutex_unlock(&args->dir->i_mutex); -out_free: - e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); - if (unlikely(e)) - err = -EFAULT; - kfree(args); -out: - AuTraceErr(err); - return err; -} |