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; }
static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo, struct dentry *parent) { struct dentry *h_d, *h_dp; struct au_hdentry tmp, *q; struct super_block *sb; aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; AuRwMustWriteLock(&dinfo->di_rwsem); bend = dinfo->di_bend; bwh = dinfo->di_bwh; bdiropq = dinfo->di_bdiropq; for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { h_d = p->hd_dentry; if (!h_d) continue; h_dp = dget_parent(h_d); if (h_dp == au_h_dptr(parent, bindex)) { dput(h_dp); continue; } new_bindex = au_find_dbindex(parent, h_dp); dput(h_dp); if (dinfo->di_bwh == bindex) bwh = new_bindex; if (dinfo->di_bdiropq == bindex) bdiropq = new_bindex; if (new_bindex < 0) { au_hdput(p); p->hd_dentry = NULL; continue; } /* swap two lower dentries, and loop again */ q = dinfo->di_hdentry + new_bindex; tmp = *q; *q = *p; *p = tmp; if (tmp.hd_dentry) { bindex--; p--; } } sb = parent->d_sb; dinfo->di_bwh = -1; if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) dinfo->di_bwh = bwh; dinfo->di_bdiropq = -1; if (bdiropq >= 0 && bdiropq <= au_sbend(sb) && au_sbr_whable(sb, bdiropq)) dinfo->di_bdiropq = bdiropq; bend = au_dbend(parent); p = dinfo->di_hdentry; for (bindex = 0; bindex <= bend; bindex++, p++) if (p->hd_dentry) { dinfo->di_bstart = bindex; break; } p = dinfo->di_hdentry + bend; for (bindex = bend; bindex >= 0; bindex--, p--) if (p->hd_dentry) { dinfo->di_bend = bindex; break; } }
/* * returns: * 0: success, the caller will add it * plus: success, it is already unified, the caller should ignore it * minus: error */ static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) { int err; aufs_bindex_t bend, bindex; struct dentry *root; struct inode *inode, *h_inode; root = sb->s_root; bend = au_sbend(sb); if (unlikely(bend >= 0 && au_find_dbindex(root, add->path.dentry) >= 0)) { err = 1; if (!remount) { err = -EINVAL; pr_err("%s duplicated\n", add->pathname); } goto out; } err = -ENOSPC; /* -E2BIG; */ if (unlikely(AUFS_BRANCH_MAX <= add->bindex || AUFS_BRANCH_MAX - 1 <= bend)) { pr_err("number of branches exceeded %s\n", add->pathname); goto out; } err = -EDOM; if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { pr_err("bad index %d\n", add->bindex); goto out; } inode = add->path.dentry->d_inode; err = -ENOENT; if (unlikely(!inode->i_nlink)) { pr_err("no existence %s\n", add->pathname); goto out; } err = -EINVAL; if (unlikely(inode->i_sb == sb)) { pr_err("%s must be outside\n", add->pathname); goto out; } if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { pr_err("unsupported filesystem, %s (%s)\n", add->pathname, au_sbtype(inode->i_sb)); goto out; } err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); if (unlikely(err)) goto out; if (bend < 0) return 0; /* success */ err = -EINVAL; for (bindex = 0; bindex <= bend; bindex++) if (unlikely(test_overlap(sb, add->path.dentry, au_h_dptr(root, bindex)))) { pr_err("%s is overlapped\n", add->pathname); goto out; } err = 0; if (au_opt_test(au_mntflags(sb), WARN_PERM)) { h_inode = au_h_dptr(root, 0)->d_inode; if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) || h_inode->i_uid != inode->i_uid || h_inode->i_gid != inode->i_gid) pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", add->pathname, inode->i_uid, inode->i_gid, (inode->i_mode & S_IALLUGO), h_inode->i_uid, h_inode->i_gid, (h_inode->i_mode & S_IALLUGO)); } out: return err; }