Btrfs: handle errors in btrfs_orphan_cleanup
authorJosef Bacik <josef@redhat.com>
Mon, 31 Jan 2011 21:22:42 +0000 (16:22 -0500)
committerJosef Bacik <josef@redhat.com>
Thu, 17 Mar 2011 18:21:26 +0000 (14:21 -0400)
If we cannot truncate an inode for some reason we will never delete the orphan
item associated with that inode, which means that we will loop forever in
btrfs_orphan_cleanup.  Instead of doing this just return error so we fail to
mount.  It sucks, but hey it's better than hanging.  Thanks,

Signed-off-by: Josef Bacik <josef@redhat.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c

index 34142d5647df08febde710641948642022181cf3..841330f3d68d33ad55a2f96edc2005b18aa92be4 100644 (file)
@@ -2529,7 +2529,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
                              struct inode *inode);
 int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
 int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
-void btrfs_orphan_cleanup(struct btrfs_root *root);
+int btrfs_orphan_cleanup(struct btrfs_root *root);
 void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
                                struct btrfs_pending_snapshot *pending,
                                u64 *bytes_to_reserve);
index e1aa8d607bc7d1a85734d9d28f26c8cd6efff585..495b1ac45f8c1f046fec9a05f7b1e5958a991ae1 100644 (file)
@@ -2058,9 +2058,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        if (!(sb->s_flags & MS_RDONLY)) {
                down_read(&fs_info->cleanup_work_sem);
-               btrfs_orphan_cleanup(fs_info->fs_root);
-               btrfs_orphan_cleanup(fs_info->tree_root);
+               err = btrfs_orphan_cleanup(fs_info->fs_root);
+               if (!err)
+                       err = btrfs_orphan_cleanup(fs_info->tree_root);
                up_read(&fs_info->cleanup_work_sem);
+               if (err) {
+                       close_ctree(tree_root);
+                       return ERR_PTR(err);
+               }
        }
 
        return tree_root;
@@ -2435,8 +2440,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
 
                root_objectid = gang[ret - 1]->root_key.objectid + 1;
                for (i = 0; i < ret; i++) {
+                       int err;
+
                        root_objectid = gang[i]->root_key.objectid;
-                       btrfs_orphan_cleanup(gang[i]);
+                       err = btrfs_orphan_cleanup(gang[i]);
+                       if (err)
+                               return err;
                }
                root_objectid++;
        }
index 27376c97d85f9407378896c3237f0e6fbbfddcc8..a8f4e8d2ba606d5c54a2983f1648a45e92fbdcb1 100644 (file)
@@ -7619,7 +7619,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root)
 
        reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
        BUG_ON(!reloc_root);
-       btrfs_orphan_cleanup(reloc_root);
+       ret = btrfs_orphan_cleanup(reloc_root);
+       BUG_ON(ret);
        return 0;
 }
 
index d83025063ee7676b827244ebf8e411a4ee984e27..0600265cb9b06f17e63cf4a81d2c80492bdfc53d 100644 (file)
@@ -2284,7 +2284,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
  * this cleans up any orphans that may be left on the list from the last use
  * of this root.
  */
-void btrfs_orphan_cleanup(struct btrfs_root *root)
+int btrfs_orphan_cleanup(struct btrfs_root *root)
 {
        struct btrfs_path *path;
        struct extent_buffer *leaf;
@@ -2294,10 +2294,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
        int ret = 0, nr_unlink = 0, nr_truncate = 0;
 
        if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
-               return;
+               return 0;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
        path->reada = -1;
 
        key.objectid = BTRFS_ORPHAN_OBJECTID;
@@ -2306,11 +2309,8 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
 
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-               if (ret < 0) {
-                       printk(KERN_ERR "Error searching slot for orphan: %d"
-                              "\n", ret);
-                       break;
-               }
+               if (ret < 0)
+                       goto out;
 
                /*
                 * if ret == 0 means we found what we were searching for, which
@@ -2318,6 +2318,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                 * find the key and see if we have stuff that matches
                 */
                if (ret > 0) {
+                       ret = 0;
                        if (path->slots[0] == 0)
                                break;
                        path->slots[0]--;
@@ -2345,7 +2346,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                found_key.type = BTRFS_INODE_ITEM_KEY;
                found_key.offset = 0;
                inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
-               BUG_ON(IS_ERR(inode));
+               if (IS_ERR(inode)) {
+                       ret = PTR_ERR(inode);
+                       goto out;
+               }
 
                /*
                 * add this inode to the orphan list so btrfs_orphan_del does
@@ -2363,7 +2367,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                 */
                if (is_bad_inode(inode)) {
                        trans = btrfs_start_transaction(root, 0);
-                       BUG_ON(IS_ERR(trans));
+                       if (IS_ERR(trans)) {
+                               ret = PTR_ERR(trans);
+                               goto out;
+                       }
                        btrfs_orphan_del(trans, inode);
                        btrfs_end_transaction(trans, root);
                        iput(inode);
@@ -2378,16 +2385,16 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                                continue;
                        }
                        nr_truncate++;
-                       btrfs_truncate(inode);
+                       ret = btrfs_truncate(inode);
                } else {
                        nr_unlink++;
                }
 
                /* this will do delete_inode and everything for us */
                iput(inode);
+               if (ret)
+                       goto out;
        }
-       btrfs_free_path(path);
-
        root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
 
        if (root->orphan_block_rsv)
@@ -2396,14 +2403,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
 
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
                trans = btrfs_join_transaction(root, 1);
-               BUG_ON(IS_ERR(trans));
-               btrfs_end_transaction(trans, root);
+               if (!IS_ERR(trans))
+                       btrfs_end_transaction(trans, root);
        }
 
        if (nr_unlink)
                printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
        if (nr_truncate)
                printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate);
+
+out:
+       if (ret)
+               printk(KERN_CRIT "btrfs: could not do orphan cleanup %d\n", ret);
+       btrfs_free_path(path);
+       return ret;
 }
 
 /*
@@ -4156,8 +4169,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        if (!IS_ERR(inode) && root != sub_root) {
                down_read(&root->fs_info->cleanup_work_sem);
                if (!(inode->i_sb->s_flags & MS_RDONLY))
-                       btrfs_orphan_cleanup(sub_root);
+                       ret = btrfs_orphan_cleanup(sub_root);
                up_read(&root->fs_info->cleanup_work_sem);
+               if (ret)
+                       inode = ERR_PTR(ret);
        }
 
        return inode;
index 5fdb2abc4fa789d49db9b76cd4e459d8c0d3bc85..ad9b8c0e930b49f64e17460bdb3bdbbd58dd880b 100644 (file)
@@ -409,7 +409,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        if (ret)
                goto fail;
 
-       btrfs_orphan_cleanup(pending_snapshot->snap);
+       ret = btrfs_orphan_cleanup(pending_snapshot->snap);
+       if (ret)
+               goto fail;
 
        parent = dget_parent(dentry);
        inode = btrfs_lookup_dentry(parent->d_inode, dentry);
index 31ade5802ae8a31f8ab48c5bdcbba0cebcddfe96..c863c844701529c3fc47f173ee51b65b00958c53 100644 (file)
@@ -4209,7 +4209,7 @@ out:
                if (IS_ERR(fs_root))
                        err = PTR_ERR(fs_root);
                else
-                       btrfs_orphan_cleanup(fs_root);
+                       err = btrfs_orphan_cleanup(fs_root);
        }
        return err;
 }