int aufs_rmdir(struct inode *dir, struct dentry *dentry) { int err, rmdir_later; aufs_bindex_t bwh, bindex, bstart; struct au_dtime dt; struct au_pin pin; struct inode *inode; struct dentry *parent, *wh_dentry, *h_dentry; struct au_whtmp_rmdir *args; IMustLock(dir); err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); if (unlikely(err)) goto out; err = au_alive_dir(dentry); if (unlikely(err)) goto out_unlock; inode = dentry->d_inode; IMustLock(inode); err = -ENOTDIR; if (unlikely(!S_ISDIR(inode->i_mode))) goto out_unlock; /* possible? */ err = -ENOMEM; args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); if (unlikely(!args)) goto out_unlock; parent = dentry->d_parent; /* dir inode is locked */ di_write_lock_parent(parent); err = au_test_empty(dentry, &args->whlist); if (unlikely(err)) goto out_parent; bstart = au_dbstart(dentry); bwh = au_dbwh(dentry); bindex = -1; wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin); err = PTR_ERR(wh_dentry); if (IS_ERR(wh_dentry)) goto out_parent; h_dentry = au_h_dptr(dentry, bstart); dget(h_dentry); rmdir_later = 0; if (bindex == bstart) { err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); if (err > 0) { rmdir_later = err; err = 0; } } else { /* stop monitoring */ au_hn_free(au_hi(inode, bstart)); /* dir inode is locked */ IMustLock(wh_dentry->d_parent->d_inode); err = 0; } if (!err) { vfsub_dead_dir(inode); au_set_dbdiropq(dentry, -1); epilog(dir, dentry, bindex); if (rmdir_later) { au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); args = NULL; } goto out_unpin; /* success */ } /* revert */ AuLabel(revert); if (wh_dentry) { int rerr; rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt); if (rerr) err = rerr; } out_unpin: au_unpin(&pin); dput(wh_dentry); dput(h_dentry); out_parent: di_write_unlock(parent); if (args) au_whtmp_rmdir_free(args); out_unlock: aufs_read_unlock(dentry, AuLock_DW); out: AuTraceErr(err); return err; }
int aufs_rmdir(struct inode *dir, struct dentry *dentry) { int err, rmdir_later; struct inode *inode, *hidden_dir; struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent; struct dtime dt; aufs_bindex_t bwh, bindex, bstart; struct rmdir_whtmp_arg *arg; struct aufs_nhash *whlist; LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry)); IMustLock(dir); inode = dentry->d_inode; if (unlikely(!inode)) return -ENOENT; // possible? IMustLock(inode); whlist = nhash_new(GFP_KERNEL); err = PTR_ERR(whlist); if (IS_ERR(whlist)) goto out; err = -ENOMEM; arg = kmalloc(sizeof(*arg), GFP_KERNEL); //arg = NULL; if (unlikely(!arg)) goto out_whlist; aufs_read_lock(dentry, AUFS_D_WLOCK); parent = dentry->d_parent; di_write_lock_parent(parent); err = test_empty(dentry, whlist); //err = -1; if (unlikely(err)) goto out_arg; bstart = dbstart(dentry); bwh = dbwh(dentry); bindex = -1; wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/ 1, &bindex, &dt); //wh_dentry = ERR_PTR(-1); err = PTR_ERR(wh_dentry); if (IS_ERR(wh_dentry)) goto out_arg; hidden_dentry = au_h_dptr(dentry); dget(hidden_dentry); hidden_parent = hidden_dentry->d_parent; hidden_dir = hidden_parent->d_inode; rmdir_later = 0; if (bindex == bstart) { IMustLock(hidden_dir); err = renwh_and_rmdir(dentry, bstart, whlist, dir); //err = -1; if (err > 0) { rmdir_later = err; err = 0; } } else { DEBUG_ON(!wh_dentry); hidden_parent = wh_dentry->d_parent; DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex)); hidden_dir = hidden_parent->d_inode; IMustLock(hidden_dir); err = 0; } if (!err) { au_reset_hinotify(inode, /*flags*/0); inode->i_nlink = 0; set_dbdiropq(dentry, -1); epilog(dir, dentry, bindex); if (rmdir_later) { kick_rmdir_whtmp(hidden_dentry, whlist, bstart, dir, inode, arg); arg = NULL; } goto out_unlock; /* success */ } /* revert */ LKTRLabel(revert); if (wh_dentry) { int rerr; rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, need_dlgt(dir->i_sb)); if (rerr) err = rerr; } out_unlock: hdir_unlock(hidden_dir, dir, bindex); dput(wh_dentry); dput(hidden_dentry); out_arg: di_write_unlock(parent); aufs_read_unlock(dentry, AUFS_D_WLOCK); kfree(arg); out_whlist: nhash_del(whlist); out: TraceErr(err); return err; }