static void au_ren_rev_diropq(int err, struct au_ren_args *a) { int rerr; au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); rerr = au_diropq_remove(a->src_dentry, a->btgt); au_hn_imtx_unlock(a->src_hinode); au_set_dbdiropq(a->src_dentry, a->src_bdiropq); if (rerr) RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry)); }
/* make it 'opaque' dir. */ static int au_ren_diropq(struct au_ren_args *a) { int err; struct dentry *diropq; err = 0; a->src_bdiropq = au_dbdiropq(a->src_dentry); a->src_hinode = au_hi(a->src_inode, a->btgt); au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); diropq = au_diropq_create(a->src_dentry, a->btgt); au_hn_imtx_unlock(a->src_hinode); if (IS_ERR(diropq)) err = PTR_ERR(diropq); dput(diropq); return err; }
/* * initialize or clean the whiteouts for an adding branch */ static int au_br_init_wh(struct super_block *sb, struct au_branch *br, int new_perm, struct dentry *h_root) { int err, old_perm; aufs_bindex_t bindex; struct mutex *h_mtx; struct au_wbr *wbr; struct au_hinode *hdir; wbr = br->br_wbr; old_perm = br->br_perm; br->br_perm = new_perm; hdir = NULL; h_mtx = NULL; bindex = au_br_index(sb, br->br_id); if (0 <= bindex) { hdir = au_hi(sb->s_root->d_inode, bindex); au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); } else { h_mtx = &h_root->d_inode->i_mutex; mutex_lock_nested(h_mtx, AuLsc_I_PARENT); } if (!wbr) err = au_wh_init(h_root, br, sb); else { wbr_wh_write_lock(wbr); err = au_wh_init(h_root, br, sb); wbr_wh_write_unlock(wbr); } if (hdir) au_hn_imtx_unlock(hdir); else mutex_unlock(h_mtx); br->br_perm = old_perm; if (!err && wbr && !au_br_writable(new_perm)) { kfree(wbr); br->br_wbr = NULL; } return err; }
int au_opts_verify(struct super_block *sb, unsigned long sb_flags, unsigned int pending) { int err; aufs_bindex_t bindex, bend; unsigned char do_plink, skip, do_free; struct au_branch *br; struct au_wbr *wbr; struct dentry *root; struct inode *dir, *h_dir; struct au_sbinfo *sbinfo; struct au_hinode *hdir; SiMustAnyLock(sb); sbinfo = au_sbi(sb); AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); if (!(sb_flags & MS_RDONLY)) { if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) pr_warn("first branch should be rw\n"); if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) pr_warn("shwh should be used with ro\n"); } if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) && !au_opt_test(sbinfo->si_mntflags, XINO)) pr_warn("udba=*notify requires xino\n"); err = 0; root = sb->s_root; dir = root->d_inode; do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); bend = au_sbend(sb); for (bindex = 0; !err && bindex <= bend; bindex++) { skip = 0; h_dir = au_h_iptr(dir, bindex); br = au_sbr(sb, bindex); do_free = 0; wbr = br->br_wbr; if (wbr) wbr_wh_read_lock(wbr); if (!au_br_writable(br->br_perm)) { do_free = !!wbr; skip = (!wbr || (!wbr->wbr_whbase && !wbr->wbr_plink && !wbr->wbr_orph)); } else if (!au_br_wh_linkable(br->br_perm)) { /* skip = (!br->br_whbase && !br->br_orph); */ skip = (!wbr || !wbr->wbr_whbase); if (skip && wbr) { if (do_plink) skip = !!wbr->wbr_plink; else skip = !wbr->wbr_plink; } } else { /* skip = (br->br_whbase && br->br_ohph); */ skip = (wbr && wbr->wbr_whbase); if (skip) { if (do_plink) skip = !!wbr->wbr_plink; else skip = !wbr->wbr_plink; } } if (wbr) wbr_wh_read_unlock(wbr); if (skip) continue; hdir = au_hi(dir, bindex); au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); if (wbr) wbr_wh_write_lock(wbr); err = au_wh_init(br, sb); if (wbr) wbr_wh_write_unlock(wbr); au_hn_imtx_unlock(hdir); if (!err && do_free) { kfree(wbr); br->br_wbr = NULL; } } return err; }
int au_do_pin(struct au_pin *p) { int err; struct super_block *sb; struct dentry *h_dentry, *h_parent; struct au_branch *br; struct inode *h_dir; err = 0; sb = p->dentry->d_sb; br = au_sbr(sb, p->bindex); if (IS_ROOT(p->dentry)) { if (au_ftest_pin(p->flags, MNT_WRITE)) { p->h_mnt = br->br_mnt; err = mnt_want_write(p->h_mnt); if (unlikely(err)) { au_fclr_pin(p->flags, MNT_WRITE); goto out_err; } } goto out; } h_dentry = NULL; if (p->bindex <= au_dbend(p->dentry)) h_dentry = au_h_dptr(p->dentry, p->bindex); p->parent = dget_parent(p->dentry); if (!au_ftest_pin(p->flags, DI_LOCKED)) di_read_lock(p->parent, AuLock_IR, p->lsc_di); h_dir = NULL; h_parent = au_h_dptr(p->parent, p->bindex); p->hdir = au_hi(p->parent->d_inode, p->bindex); if (p->hdir) h_dir = p->hdir->hi_inode; /* * udba case, or * if DI_LOCKED is not set, then p->parent may be different * and h_parent can be NULL. */ if (unlikely(!p->hdir || !h_dir || !h_parent)) { err = -EBUSY; if (!au_ftest_pin(p->flags, DI_LOCKED)) di_read_unlock(p->parent, AuLock_IR); dput(p->parent); p->parent = NULL; goto out_err; } au_igrab(h_dir); au_hn_imtx_lock_nested(p->hdir, p->lsc_hi); if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) { err = -EBUSY; goto out_unpin; } if (h_dentry) { err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br); if (unlikely(err)) { au_fclr_pin(p->flags, MNT_WRITE); goto out_unpin; } } if (au_ftest_pin(p->flags, MNT_WRITE)) { p->h_mnt = br->br_mnt; err = mnt_want_write(p->h_mnt); if (unlikely(err)) { au_fclr_pin(p->flags, MNT_WRITE); goto out_unpin; } } goto out; /* success */ out_unpin: au_unpin(p); out_err: pr_err("err %d\n", err); err = au_busy_or_stale(); out: return err; }
int au_opts_verify(struct super_block *sb, unsigned long sb_flags, unsigned int pending) { int err, fhsm; aufs_bindex_t bindex, bend; unsigned char do_plink, skip, do_free; struct au_branch *br; struct au_wbr *wbr; struct dentry *root; struct inode *dir, *h_dir; struct au_sbinfo *sbinfo; struct au_hinode *hdir; SiMustAnyLock(sb); sbinfo = au_sbi(sb); AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); if (!(sb_flags & MS_RDONLY)) { if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) pr_warn("first branch should be rw\n"); if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) pr_warn("shwh should be used with ro\n"); } if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) && !au_opt_test(sbinfo->si_mntflags, XINO)) pr_warn("udba=*notify requires xino\n"); if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) pr_warn("dirperm1 breaks the protection" " by the permission bits on the lower branch\n"); err = 0; fhsm = 0; root = sb->s_root; dir = root->d_inode; do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); bend = au_sbend(sb); for (bindex = 0; !err && bindex <= bend; bindex++) { skip = 0; h_dir = au_h_iptr(dir, bindex); br = au_sbr(sb, bindex); if ((br->br_perm & AuBrAttr_ICEX) && !h_dir->i_op->listxattr) br->br_perm &= ~AuBrAttr_ICEX; #if 0 if ((br->br_perm & AuBrAttr_ICEX_SEC) && (au_br_sb(br)->s_flags & MS_NOSEC)) br->br_perm &= ~AuBrAttr_ICEX_SEC; #endif do_free = 0; wbr = br->br_wbr; if (wbr) wbr_wh_read_lock(wbr); if (!au_br_writable(br->br_perm)) { do_free = !!wbr; skip = (!wbr || (!wbr->wbr_whbase && !wbr->wbr_plink && !wbr->wbr_orph)); } else if (!au_br_wh_linkable(br->br_perm)) { /* skip = (!br->br_whbase && !br->br_orph); */ skip = (!wbr || !wbr->wbr_whbase); if (skip && wbr) { if (do_plink) skip = !!wbr->wbr_plink; else skip = !wbr->wbr_plink; } } else { /* skip = (br->br_whbase && br->br_ohph); */ skip = (wbr && wbr->wbr_whbase); if (skip) { if (do_plink) skip = !!wbr->wbr_plink; else skip = !wbr->wbr_plink; } } if (wbr) wbr_wh_read_unlock(wbr); if (au_br_fhsm(br->br_perm)) { fhsm++; AuDebugOn(!br->br_fhsm); } if (skip) continue; hdir = au_hi(dir, bindex); au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); if (wbr) wbr_wh_write_lock(wbr); err = au_wh_init(br, sb); if (wbr) wbr_wh_write_unlock(wbr); au_hn_imtx_unlock(hdir); if (!err && do_free) { kfree(wbr); br->br_wbr = NULL; } } if (fhsm >= 2) { au_fset_si(sbinfo, FHSM); for (bindex = bend; bindex >= 0; bindex--) { br = au_sbr(sb, bindex); if (au_br_fhsm(br->br_perm)) { au_fhsm_set_bottom(sb, bindex); break; } } } else { au_fclr_si(sbinfo, FHSM); au_fhsm_set_bottom(sb, -1); } return err; }