From patchwork Sun Oct 17 16:09:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Goffredo Baroncelli X-Patchwork-Id: 260301 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9HG60jY013412 for ; Sun, 17 Oct 2010 16:06:00 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757385Ab0JQQFz (ORCPT ); Sun, 17 Oct 2010 12:05:55 -0400 Received: from smtp206.alice.it ([82.57.200.102]:46630 "EHLO smtp206.alice.it" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757020Ab0JQQFy (ORCPT ); Sun, 17 Oct 2010 12:05:54 -0400 Received: from venice.localnet (87.6.20.83) by smtp206.alice.it (8.5.124.08) id 4C1A268C07CBC278; Sun, 17 Oct 2010 18:05:52 +0200 To: linux-btrfs@vger.kernel.org Subject: [PATCH V3] Removing a subvolume with a simple "rm -rf" Cc: Chris Mason From: Goffredo Baroncelli Reply-To: kreijack@libero.it Date: Sun, 17 Oct 2010 18:09:50 +0200 MIME-Version: 1.0 Message-Id: <201010171809.58152.kreijack@libero.it> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Sun, 17 Oct 2010 16:06:00 +0000 (UTC) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f08427c..f732ddf 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2944,6 +2944,88 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, return 0; } +static noinline int btrfs_snap_destroy(struct inode *dir, + struct dentry *dentry) +{ + + struct inode *inode; + struct btrfs_root *root = BTRFS_I(dir)->root; + struct btrfs_root *dest = NULL; + struct btrfs_trans_handle *trans; + int ret; + int err = 0; + + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + goto out; + } + + if (!dentry->d_inode) { + err = -ENOENT; + goto out; + } + + inode = dentry->d_inode; + if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { + err = -EINVAL; + goto out; + } + + dest = BTRFS_I(inode)->root; + + err = d_invalidate(dentry); + if (err) + goto out; + + down_write(&root->fs_info->subvol_sem); + + /* remove this check because the directory is empty. + * err = may_destroy_subvol(dest); + * if (err) + * goto out_up_write; + */ + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + err = PTR_ERR(trans); + goto out_up_write; + } + trans->block_rsv = &root->fs_info->global_block_rsv; + + ret = btrfs_unlink_subvol(trans, root, dir, + dest->root_key.objectid, + dentry->d_name.name, + dentry->d_name.len); + BUG_ON(ret); + + btrfs_record_root_in_trans(trans, dest); + + memset(&dest->root_item.drop_progress, 0, + sizeof(dest->root_item.drop_progress)); + dest->root_item.drop_level = 0; + btrfs_set_root_refs(&dest->root_item, 0); + + if (!xchg(&dest->orphan_item_inserted, 1)) { + ret = btrfs_insert_orphan_item(trans, + root->fs_info->tree_root, + dest->root_key.objectid); + BUG_ON(ret); + } + + ret = btrfs_commit_transaction(trans, root); + BUG_ON(ret); + inode->i_flags |= S_DEAD; +out_up_write: + up_write(&root->fs_info->subvol_sem); + if (!err) { + shrink_dcache_sb(root->fs_info->sb); + btrfs_invalidate_inodes(dest); + /*d_delete(dentry);*/ + } +out: + return err; +} + static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; @@ -2952,10 +3034,12 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) struct btrfs_trans_handle *trans; unsigned long nr = 0; - if (inode->i_size > BTRFS_EMPTY_DIR_SIZE || - inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) + if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) + return btrfs_snap_destroy(dir, dentry); + trans = __unlink_start_trans(dir, dentry); if (IS_ERR(trans)) return PTR_ERR(trans);