Btrfs: improve error handling for btrfs_insert_dir_item callers
Chris Mason [Mon, 20 Feb 2012 13:40:56 +0000 (08:40 -0500)]
This allows us to gracefully continue if we aren't able to insert
directory items, both for normal files/dirs and snapshots.

Signed-off-by: Chris Mason <chris.mason@oracle.com>

fs/btrfs/inode.c
fs/btrfs/transaction.c

index 6e0ee9b..cbeb2e3 100644 (file)
@@ -4585,7 +4585,8 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
                ret = btrfs_insert_dir_item(trans, root, name, name_len,
                                            parent_inode, &key,
                                            btrfs_inode_type(inode), index);
-               BUG_ON(ret);
+               if (ret)
+                       goto fail_dir_item;
 
                btrfs_i_size_write(parent_inode, parent_inode->i_size +
                                   name_len * 2);
@@ -4593,6 +4594,23 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
                ret = btrfs_update_inode(trans, root, parent_inode);
        }
        return ret;
+
+fail_dir_item:
+       if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
+               u64 local_index;
+               int err;
+               err = btrfs_del_root_ref(trans, root->fs_info->tree_root,
+                                key.objectid, root->root_key.objectid,
+                                parent_ino, &local_index, name, name_len);
+
+       } else if (add_backref) {
+               u64 local_index;
+               int err;
+
+               err = btrfs_del_inode_ref(trans, root, name, name_len,
+                                         ino, parent_ino, &local_index);
+       }
+       return ret;
 }
 
 static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
index 287a672..016977b 100644 (file)
@@ -915,7 +915,11 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                dentry->d_name.name, dentry->d_name.len,
                                parent_inode, &key,
                                BTRFS_FT_DIR, index);
-       BUG_ON(ret);
+       if (ret) {
+               pending->error = -EEXIST;
+               dput(parent);
+               goto fail;
+       }
 
        btrfs_i_size_write(parent_inode, parent_inode->i_size +
                                         dentry->d_name.len * 2);
@@ -993,12 +997,9 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
 {
        struct btrfs_pending_snapshot *pending;
        struct list_head *head = &trans->transaction->pending_snapshots;
-       int ret;
 
-       list_for_each_entry(pending, head, list) {
-               ret = create_pending_snapshot(trans, fs_info, pending);
-               BUG_ON(ret);
-       }
+       list_for_each_entry(pending, head, list)
+               create_pending_snapshot(trans, fs_info, pending);
        return 0;
 }