/* 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); if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { a->rename_lock = 0; err = au_pin(&a->pin, a->dentry, a->mvd_bdst, au_opt_udba(a->sb), AuPin_MNT_WRITE | AuPin_DI_LOCKED); if (!err) { a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode; mutex_lock_nested(&a->mvd_h_src_dir->i_mutex, AuLsc_I_PARENT3); } else AU_MVD_PR(dmsg, "pin failed\n"); goto out; } err = 0; a->rename_lock = 1; 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 */ 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; }
int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) { int err, rerr, i; unsigned int mnt_flags; aufs_bindex_t bindex, bend, br_id; unsigned char do_wh, verbose; struct au_branch *br; struct au_wbr *wbr; err = 0; bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); if (bindex < 0) { if (remount) goto out; /* success */ err = -ENOENT; pr_err("%s no such branch\n", del->pathname); goto out; } AuDbg("bindex b%d\n", bindex); err = -EBUSY; mnt_flags = au_mntflags(sb); verbose = !!au_opt_test(mnt_flags, VERBOSE); bend = au_sbend(sb); if (unlikely(!bend)) { AuVerbose(verbose, "no more branches left\n"); goto out; } br = au_sbr(sb, bindex); i = atomic_read(&br->br_count); if (unlikely(i)) { AuVerbose(verbose, "%d file(s) opened\n", i); goto out; } wbr = br->br_wbr; do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); if (do_wh) { /* instead of WbrWhMustWriteLock(wbr) */ SiMustWriteLock(sb); for (i = 0; i < AuBrWh_Last; i++) { dput(wbr->wbr_wh[i]); wbr->wbr_wh[i] = NULL; } } err = test_children_busy(sb->s_root, bindex, verbose); if (unlikely(err)) { if (do_wh) goto out_wh; goto out; } err = 0; br_id = br->br_id; if (!remount) au_br_do_del(sb, bindex, br); else { sysaufs_brs_del(sb, bindex); au_br_do_del(sb, bindex, br); sysaufs_brs_add(sb, bindex); } if (!bindex) { au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; } else au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); if (au_opt_test(mnt_flags, PLINK)) au_plink_half_refresh(sb, br_id); if (au_xino_brid(sb) == br_id) au_xino_brid_set(sb, -1); goto out; /* success */ out_wh: /* revert */ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); if (rerr) pr_warning("failed re-creating base whiteout, %s. (%d)\n", del->pathname, rerr); out: return err; }