public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 00/10] btrfs: Error handling/propagation queue
@ 2009-11-04 19:03 Jeff Mahoney
  2009-11-04 19:03 ` [patch 01/10] btrfs: fix btrfs_read_block_groups return value Jeff Mahoney
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

 This patch series fixes a few existing problems and then addresses
 the need for better error handling and propagation in btrfs.

 The handling and propagation patch set first finds all locations of
 a particular condition not being checked and annotates them with
 BTRFS_UERROR to designate that there is an error condition that
 is currently unhandled but should be. Then, another patch traverses
 the call path to ensure that errors are properly propogated. When the
 fix for recovering or passing the error is obvious, we do that too.

 This set is not complete and I expect there to be more fixes coming. In
 particular, it currently only annotates btrfs_alloc_path failures as
 the call graph for it is quite large. This is in response to Chris asking
 for what I already have instead of waiting for it to be complete.

 -Jeff

-- 
Jeff Mahoney
SUSE Labs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 01/10] btrfs: fix btrfs_read_block_groups return value
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 02/10] btrfs: fix memleak in btrfs_init_new_device Jeff Mahoney
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

btrfs_read_block_groups returns an ambiguous value. Whether it finds
a block group or not, it will return -ENOENT. find_first_block_group
will eventually return -ENOENT when it reaches past the last block
group, and that is what is returned to the caller.

Also, if the kzalloc fails, it will return 0.

None of this matters right now because open_ctree isn't checking
the return value, but I have a patch to handle that as well.

This patch returns 0 if find_first_block_group after it has already
found at least one block group, and -ENOENT if it has found none. It
also returns -ENOMEM if the kzalloc fails.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

---
 fs/btrfs/extent-tree.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -7339,7 +7339,7 @@ int btrfs_free_block_groups(struct btrfs
 int btrfs_read_block_groups(struct btrfs_root *root)
 {
 	struct btrfs_path *path;
-	int ret;
+	int ret, found = 0;
 	struct btrfs_block_group_cache *cache;
 	struct btrfs_fs_info *info = root->fs_info;
 	struct btrfs_space_info *space_info;
@@ -7357,12 +7357,13 @@ int btrfs_read_block_groups(struct btrfs
 
 	while (1) {
 		ret = find_first_block_group(root, path, &key);
-		if (ret > 0) {
+		if (ret > 0 || (found && ret == -ENOENT)) {
 			ret = 0;
-			goto error;
+			break;
 		}
+
 		if (ret != 0)
-			goto error;
+			break;
 
 		leaf = path->nodes[0];
 		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
@@ -7439,9 +7440,8 @@ int btrfs_read_block_groups(struct btrfs
 		set_avail_alloc_bits(root->fs_info, cache->flags);
 		if (btrfs_chunk_readonly(root, cache->key.objectid))
 			set_block_group_readonly(cache);
+		found = 1;
 	}
-	ret = 0;
-error:
 	btrfs_free_path(path);
 	return ret;
 }


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 02/10] btrfs: fix memleak in btrfs_init_new_device
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
  2009-11-04 19:03 ` [patch 01/10] btrfs: fix btrfs_read_block_groups return value Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 03/10] btrfs: fix btrfs_read_fs_root* return values Jeff Mahoney
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

 If find_next_devid fails, btrfs_init_new_device frees device but
 not device->name.

 This patch fixes it.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/btrfs/volumes.c |    1 +
 1 file changed, 1 insertion(+)

--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1474,6 +1474,7 @@ int btrfs_init_new_device(struct btrfs_r
 
 	ret = find_next_devid(root, &device->devid);
 	if (ret) {
+		kfree(device->name);
 		kfree(device);
 		goto error;
 	}


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 03/10] btrfs: fix btrfs_read_fs_root* return values
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
  2009-11-04 19:03 ` [patch 01/10] btrfs: fix btrfs_read_block_groups return value Jeff Mahoney
  2009-11-04 19:03 ` [patch 02/10] btrfs: fix memleak in btrfs_init_new_device Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 04/10] btrfs: btrfs_sync_file should return -EIO not EIO Jeff Mahoney
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

 The btrfs_read_fs_root* functions return ERR_PTR values but the return
 is being checked for NULL instead.

 This patch fixes up the checks to use IS_ERR.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/btrfs/disk-io.c     |    4 +++-
 fs/btrfs/extent-tree.c |    6 +++---
 fs/btrfs/tree-log.c    |    4 ++--
 3 files changed, 8 insertions(+), 6 deletions(-)

--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1987,8 +1987,10 @@ struct btrfs_root *open_ctree(struct sup
 	location.offset = (u64)-1;
 
 	fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
-	if (!fs_info->fs_root)
+	if (IS_ERR(fs_info->fs_root)) {
+		err = PTR_ERR(fs_info->fs_root);
 		goto fail_trans_kthread;
+	}
 
 	return tree_root;
 
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6712,7 +6712,7 @@ int btrfs_cleanup_reloc_trees(struct btr
 	location.type = BTRFS_ROOT_ITEM_KEY;
 
 	reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
-	BUG_ON(!reloc_root);
+	BUG_ON(IS_ERR(reloc_root));
 	btrfs_orphan_cleanup(reloc_root);
 	return 0;
 }
@@ -6757,7 +6757,7 @@ static noinline int init_reloc_tree(stru
 
 	reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
 						 &root_key);
-	BUG_ON(!reloc_root);
+	BUG_ON(IS_ERR(reloc_root));
 	reloc_root->last_trans = trans->transid;
 	reloc_root->commit_root = NULL;
 	reloc_root->ref_tree = &root->fs_info->reloc_ref_tree;
@@ -6976,7 +6976,7 @@ static noinline int relocate_one_extent(
 			continue;
 
 		found_root = read_ref_root(extent_root->fs_info, ref_path);
-		BUG_ON(!found_root);
+		BUG_ON(IS_ERR(found_root));
 		/*
 		 * for reference counted tree, only process reference paths
 		 * rooted at the latest committed root.
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3042,7 +3042,7 @@ again:
 
 		log = btrfs_read_fs_root_no_radix(log_root_tree,
 						  &found_key);
-		BUG_ON(!log);
+		BUG_ON(IS_ERR(log));
 
 
 		tmp_key.objectid = found_key.offset;
@@ -3050,7 +3050,7 @@ again:
 		tmp_key.offset = (u64)-1;
 
 		wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
-		BUG_ON(!wc.replay_dest);
+		BUG_ON(IS_ERR(wc.replay_dest));
 
 		wc.replay_dest->log_root = log;
 		btrfs_record_root_in_trans(trans, wc.replay_dest);


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 04/10] btrfs: btrfs_sync_file should return -EIO not EIO
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (2 preceding siblings ...)
  2009-11-04 19:03 ` [patch 03/10] btrfs: fix btrfs_read_fs_root* return values Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 05/10] btrfs: Add BTRFS_UERROR for unhandled errors Jeff Mahoney
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

 This patch fixes a typo in the return path of btrfs_sync_file, which
 currently returns EIO instead of -EIO.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/btrfs/file.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1223,7 +1223,7 @@ int btrfs_sync_file(struct file *file, s
 	}
 	mutex_lock(&dentry->d_inode->i_mutex);
 out:
-	return ret > 0 ? EIO : ret;
+	return ret > 0 ? -EIO : ret;
 }
 
 static struct vm_operations_struct btrfs_file_vm_ops = {


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 05/10] btrfs: Add BTRFS_UERROR for unhandled errors
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (3 preceding siblings ...)
  2009-11-04 19:03 ` [patch 04/10] btrfs: btrfs_sync_file should return -EIO not EIO Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 06/10] btrfs: annotate kmalloc failures Jeff Mahoney
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

 This patch adds a BTRFS_UERROR macro to indicate than an error is
 unhandled but should be. This is to differentiate between internal
 logic errors and runtime errors so that we can go through later
 more easily to locate and fix them. It currently BUGs after
 printing a message indicating where the failure occured and what
 the failure condition was.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

---

 fs/btrfs/ctree.h |    8 ++++++++
 fs/btrfs/super.c |    8 ++++++++
 2 files changed, 16 insertions(+)

--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1951,6 +1951,13 @@ static inline struct dentry *fdentry(str
 	return file->f_path.dentry;
 }
 
+#define BTRFS_UERROR(condition) \
+	do { \
+		if (condition) \
+			btrfs_unhandled_error(__FILE__, __LINE__, \
+					      #condition); \
+	} while(0);
+
 /* extent-tree.c */
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
@@ -2373,6 +2380,7 @@ ssize_t btrfs_listxattr(struct dentry *d
 u64 btrfs_parse_size(char *str);
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+void btrfs_unhandled_error(const char *file, int line, const char *condition);
 
 /* acl.c */
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -51,6 +51,14 @@
 #include "export.h"
 #include "compression.h"
 
+void btrfs_unhandled_error(const char *file, int line, const char *msg)
+{
+	printk(KERN_CRIT "btrfs: Unhandled error at %s:%d: %s\n",
+	       file, line, msg);
+
+	BUG();
+}
+
 static struct super_operations btrfs_super_ops;
 
 static void btrfs_put_super(struct super_block *sb)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 06/10] btrfs: annotate kmalloc failures
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (4 preceding siblings ...)
  2009-11-04 19:03 ` [patch 05/10] btrfs: Add BTRFS_UERROR for unhandled errors Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 07/10] btrfs: handle kmalloc call path failures Jeff Mahoney
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

This patch adds checks to ensure that kmalloc or kmem_cache_alloc has
succeeded before using the memory.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---

 fs/btrfs/compression.c |    2 ++
 fs/btrfs/ctree.c       |    1 +
 fs/btrfs/disk-io.c     |    1 +
 fs/btrfs/extent-tree.c |   12 +++++++-----
 fs/btrfs/file-item.c   |    4 ++--
 fs/btrfs/file.c        |    1 +
 fs/btrfs/inode.c       |    4 ++++
 fs/btrfs/relocation.c  |    8 ++++----
 fs/btrfs/transaction.c |    4 +++-
 fs/btrfs/tree-log.c    |    9 +++++++--
 fs/btrfs/volumes.c     |    2 +-
 11 files changed, 33 insertions(+), 15 deletions(-)

--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -351,6 +351,7 @@ int btrfs_submit_compressed_write(struct
 
 	WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1));
 	cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
+	BTRFS_UERROR(!cb);
 	atomic_set(&cb->pending_bios, 0);
 	cb->errors = 0;
 	cb->inode = inode;
@@ -622,6 +623,7 @@ int btrfs_submit_compressed_read(struct
 				 PAGE_CACHE_SIZE;
 	cb->compressed_pages = kmalloc(sizeof(struct page *) * nr_pages,
 				       GFP_NOFS);
+	BTRFS_UERROR(!cb->compressed_pages);
 	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
 
 	for (page_index = 0; page_index < nr_pages; page_index++) {
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3073,6 +3073,7 @@ split:
 	item_size = btrfs_item_size(leaf, item);
 
 	buf = kmalloc(item_size, GFP_NOFS);
+	BTRFS_UERROR(!buf);
 	read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
 			    path->slots[0]), item_size);
 	slot = path->slots[0] + 1;
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1958,6 +1958,7 @@ struct btrfs_root *open_ctree(struct sup
 
 		log_tree_root = kzalloc(sizeof(struct btrfs_root),
 						      GFP_NOFS);
+		BTRFS_UERROR(!log_tree_root);
 
 		__setup_root(nodesize, leafsize, sectorsize, stripesize,
 			     log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -414,7 +414,7 @@ static int cache_block_group(struct btrf
 		return 0;
 
 	caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL);
-	BUG_ON(!caching_ctl);
+	BTRFS_UERROR(!caching_ctl);
 
 	INIT_LIST_HEAD(&caching_ctl->list);
 	mutex_init(&caching_ctl->mutex);
@@ -5388,7 +5388,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	BUG_ON(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
-	BUG_ON(!wc);
+	BTRFS_UERROR(!wc);
 
 	trans = btrfs_start_transaction(tree_root, 1);
 
@@ -5550,7 +5550,7 @@ int btrfs_drop_subtree(struct btrfs_tran
 	BUG_ON(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
-	BUG_ON(!wc);
+	BTRFS_UERROR(!wc);
 
 	btrfs_assert_tree_locked(parent);
 	parent_level = btrfs_header_level(parent);
@@ -6048,6 +6048,7 @@ static noinline int get_new_locations(st
 			struct disk_extent *old = exts;
 			max *= 2;
 			exts = kzalloc(sizeof(*exts) * max, GFP_NOFS);
+			BTRFS_UERROR(!exts);
 			memcpy(exts, old, sizeof(*exts) * nr);
 			if (old != *extents)
 				kfree(old);
@@ -6527,7 +6528,7 @@ static noinline int replace_extents_in_l
 	int ret;
 
 	new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS);
-	BUG_ON(!new_extent);
+	BTRFS_UERROR(!new_extent)
 
 	ref = btrfs_lookup_leaf_ref(root, leaf->start);
 	BUG_ON(!ref);
@@ -6731,7 +6732,7 @@ static noinline int init_reloc_tree(stru
 		return 0;
 
 	root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
-	BUG_ON(!root_item);
+	BTRFS_UERROR(!root_item);
 
 	ret = btrfs_copy_root(trans, root, root->commit_root,
 			      &eb, BTRFS_TREE_RELOC_OBJECTID);
@@ -7047,6 +7048,7 @@ static noinline int relocate_one_extent(
 				u64 group_start = group->key.objectid;
 				new_extents = kmalloc(sizeof(*new_extents),
 						      GFP_NOFS);
+				BTRFS_UERROR(!new_extents);
 				nr_extents = 1;
 				ret = get_new_locations(reloc_inode,
 							extent_key,
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -320,7 +320,7 @@ int btrfs_lookup_csums_range(struct btrf
 					MAX_ORDERED_SUM_BYTES(root));
 			sums = kzalloc(btrfs_ordered_sum_size(root, size),
 					GFP_NOFS);
-			BUG_ON(!sums);
+			BTRFS_UERROR(!sums);
 
 			sector_sum = sums->sums;
 			sums->bytenr = start;
@@ -401,7 +401,7 @@ int btrfs_csum_one_bio(struct btrfs_root
 
 			sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
 				       GFP_NOFS);
-			BUG_ON(!sums);
+			BTRFS_UERROR(!sums);
 			sector_sum = sums->sums;
 			sums->len = bytes_left;
 			ordered = btrfs_lookup_ordered_extent(inode, offset);
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -946,6 +946,7 @@ static ssize_t btrfs_file_write(struct f
 	file_update_time(file);
 
 	pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
+	BTRFS_UERROR(!pages);
 
 	/* generic_write_checks can change our pos */
 	start_pos = pos;
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -273,6 +273,7 @@ static noinline int add_async_extent(str
 	struct async_extent *async_extent;
 
 	async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
+	BTRFS_UERROR(!async_extent);
 	async_extent->start = start;
 	async_extent->ram_size = ram_size;
 	async_extent->compressed_size = compressed_size;
@@ -372,6 +373,7 @@ again:
 	    btrfs_test_opt(root, COMPRESS)) {
 		WARN_ON(pages);
 		pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
+		BTRFS_UERROR(!pages);
 
 		ret = btrfs_zlib_compress_pages(inode->i_mapping, start,
 						total_compressed, pages,
@@ -885,6 +887,7 @@ static int cow_file_range_async(struct i
 			 1, 0, NULL, GFP_NOFS);
 	while (start < end) {
 		async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
+		BTRFS_UERROR(!async_cow);
 		async_cow->inode = inode;
 		async_cow->root = root;
 		async_cow->locked_page = locked_page;
@@ -4447,6 +4450,7 @@ static noinline int uncompress_inline(st
 	inline_size = btrfs_file_extent_inline_item_len(leaf,
 					btrfs_item_nr(leaf, path->slots[0]));
 	tmp = kmalloc(inline_size, GFP_NOFS);
+	BTRFS_UERROR(!tmp);
 	ptr = btrfs_file_extent_inline_start(item);
 
 	read_extent_buffer(leaf, tmp, ptr, inline_size);
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -850,7 +850,7 @@ static int __add_reloc_root(struct btrfs
 	struct reloc_control *rc = root->fs_info->reloc_ctl;
 
 	node = kmalloc(sizeof(*node), GFP_NOFS);
-	BUG_ON(!node);
+	BTRFS_UERROR(!node);
 
 	node->bytenr = root->node->start;
 	node->data = root;
@@ -925,7 +925,7 @@ int btrfs_init_reloc_root(struct btrfs_t
 		return 0;
 
 	root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
-	BUG_ON(!root_item);
+	BTRFS_UERROR(!root_item);
 
 	root_key.objectid = BTRFS_TREE_RELOC_OBJECTID;
 	root_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -1167,7 +1167,7 @@ static int replace_file_extents(struct b
 		if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
 			if (!ivec || ivec->nr == INODEVEC_SIZE) {
 				ivec = kmalloc(sizeof(*ivec), GFP_NOFS);
-				BUG_ON(!ivec);
+				BTRFS_UERROR(!ivec);
 				ivec->nr = 0;
 				list_add_tail(&ivec->list, inode_list);
 			}
@@ -1824,7 +1824,7 @@ static int merge_reloc_roots(struct relo
 		list_del_init(&root->root_list);
 
 		async = kmalloc(sizeof(*async), GFP_NOFS);
-		BUG_ON(!async);
+		BTRFS_UERROR(!async);
 		async->work.func = merge_func;
 		async->work.flags = 0;
 		async->rc = rc;
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -56,7 +56,7 @@ static noinline int join_transaction(str
 	if (!cur_trans) {
 		cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
 					     GFP_NOFS);
-		BUG_ON(!cur_trans);
+		BTRFS_UERROR(!cur_trans);
 		root->fs_info->generation++;
 		cur_trans->num_writers = 1;
 		cur_trans->num_joined = 0;
@@ -170,6 +170,8 @@ static struct btrfs_trans_handle *start_
 		kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
 	int ret;
 
+	BTRFS_UERROR(!h);
+
 	mutex_lock(&root->fs_info->trans_mutex);
 	if (!root->fs_info->log_root_recovering &&
 	    ((wait == 1 && !root->fs_info->open_ioctl_trans) || wait == 2))
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -333,7 +333,9 @@ static noinline int overwrite_item(struc
 			return 0;
 		}
 		dst_copy = kmalloc(item_size, GFP_NOFS);
+		BTRFS_UERROR(!dst_copy);
 		src_copy = kmalloc(item_size, GFP_NOFS);
+		BTRFS_UERROR(!src_copy);
 
 		read_extent_buffer(eb, src_copy, src_ptr, item_size);
 
@@ -661,6 +663,7 @@ static noinline int drop_one_dir_item(st
 	btrfs_dir_item_key_to_cpu(leaf, di, &location);
 	name_len = btrfs_dir_name_len(leaf, di);
 	name = kmalloc(name_len, GFP_NOFS);
+	BTRFS_UERROR(!name);
 	read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
 	btrfs_release_path(root, path);
 
@@ -816,7 +819,7 @@ again:
 
 	namelen = btrfs_inode_ref_name_len(eb, ref);
 	name = kmalloc(namelen, GFP_NOFS);
-	BUG_ON(!name);
+	BTRFS_UERROR(!name);
 
 	read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);
 
@@ -861,7 +864,7 @@ conflict_again:
 			victim_name_len = btrfs_inode_ref_name_len(leaf,
 								   victim_ref);
 			victim_name = kmalloc(victim_name_len, GFP_NOFS);
-			BUG_ON(!victim_name);
+			BTRFS_UERROR(!victim_name);
 
 			read_extent_buffer(leaf, victim_name,
 					   (unsigned long)(victim_ref + 1),
@@ -1164,6 +1167,7 @@ static noinline int replay_one_name(stru
 
 	name_len = btrfs_dir_name_len(eb, di);
 	name = kmalloc(name_len, GFP_NOFS);
+	BTRFS_UERROR(!name);
 	log_type = btrfs_dir_type(eb, di);
 	read_extent_buffer(eb, name, (unsigned long)(di + 1),
 		   name_len);
@@ -2571,6 +2575,7 @@ static noinline int copy_items(struct bt
 
 	ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
 			   nr * sizeof(u32), GFP_NOFS);
+	BTRFS_UERROR(!ins_data);
 	ins_sizes = (u32 *)ins_data;
 	ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2819,7 +2819,7 @@ int btrfs_rmap_block(struct btrfs_mappin
 		do_div(length, map->num_stripes);
 
 	buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
-	BUG_ON(!buf);
+	BTRFS_UERROR(!buf);
 
 	for (i = 0; i < map->num_stripes; i++) {
 		if (devid && map->stripes[i].dev->devid != devid)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 07/10] btrfs: handle kmalloc call path failures
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (5 preceding siblings ...)
  2009-11-04 19:03 ` [patch 06/10] btrfs: annotate kmalloc failures Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 08/10] btrfs: annotate btrfs_{start,join}_transaction failures Jeff Mahoney
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

This patch adds checks to ensure that kmalloc or kmem_cache_alloc has
succeeded before using the memory.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/btrfs/compression.c |    3 ++-
 fs/btrfs/disk-io.c     |    5 ++++-
 fs/btrfs/extent-tree.c |   28 +++++++++++++++++++---------
 fs/btrfs/file.c        |    5 ++++-
 fs/btrfs/inode.c       |   17 +++++++++++------
 fs/btrfs/relocation.c  |   12 ++++++++----
 fs/btrfs/transaction.c |   10 +++++++---
 fs/btrfs/tree-log.c    |   25 +++++++++++++++----------
 fs/btrfs/volumes.c     |    5 ++++-
 9 files changed, 74 insertions(+), 36 deletions(-)

--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -351,7 +351,8 @@ int btrfs_submit_compressed_write(struct
 
 	WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1));
 	cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
-	BTRFS_UERROR(!cb);
+	if (!cb)
+		return -ENOMEM;
 	atomic_set(&cb->pending_bios, 0);
 	cb->errors = 0;
 	cb->inode = inode;
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1958,7 +1958,10 @@ struct btrfs_root *open_ctree(struct sup
 
 		log_tree_root = kzalloc(sizeof(struct btrfs_root),
 						      GFP_NOFS);
-		BTRFS_UERROR(!log_tree_root);
+		if (!log_tree_root) {
+			err = -EIO;
+			goto fail_trans_kthread;
+		}
 
 		__setup_root(nodesize, leafsize, sectorsize, stripesize,
 			     log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -414,7 +414,8 @@ static int cache_block_group(struct btrf
 		return 0;
 
 	caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL);
-	BTRFS_UERROR(!caching_ctl);
+	if (!caching_ctl)
+		return -ENOMEM;
 
 	INIT_LIST_HEAD(&caching_ctl->list);
 	mutex_init(&caching_ctl->mutex);
@@ -4217,7 +4218,7 @@ have_block_group:
 			if (loop > LOOP_CACHING_NOWAIT ||
 			    atomic_read(&space_info->caching_threads) < 2) {
 				ret = cache_block_group(block_group);
-				BUG_ON(ret);
+				BTRFS_UERROR(ret);
 			}
 		}
 
@@ -4743,7 +4744,8 @@ int btrfs_alloc_logged_file_extent(struc
 	u64 num_bytes = ins->offset;
 
 	block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
-	cache_block_group(block_group);
+	ret = cache_block_group(block_group);
+	BTRFS_UERROR(ret);
 	caching_ctl = get_caching_control(block_group);
 
 	if (!caching_ctl) {
@@ -5388,7 +5390,10 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	BUG_ON(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
-	BTRFS_UERROR(!wc);
+	if (!wc) {
+		btrfs_free_path(path);
+		return -ENOMEM;
+	}
 
 	trans = btrfs_start_transaction(tree_root, 1);
 
@@ -5550,7 +5555,10 @@ int btrfs_drop_subtree(struct btrfs_tran
 	BUG_ON(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
-	BTRFS_UERROR(!wc);
+	if (!wc) {
+		btrfs_free_path(path);
+		return -ENOMEM;
+	}
 
 	btrfs_assert_tree_locked(parent);
 	parent_level = btrfs_header_level(parent);
@@ -6528,7 +6536,8 @@ static noinline int replace_extents_in_l
 	int ret;
 
 	new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS);
-	BTRFS_UERROR(!new_extent)
+	if (!new_extent)
+		return -ENOMEM;
 
 	ref = btrfs_lookup_leaf_ref(root, leaf->start);
 	BUG_ON(!ref);
@@ -6732,7 +6741,8 @@ static noinline int init_reloc_tree(stru
 		return 0;
 
 	root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
-	BTRFS_UERROR(!root_item);
+	if (!root_item)
+		return -ENOMEM;
 
 	ret = btrfs_copy_root(trans, root, root->commit_root,
 			      &eb, BTRFS_TREE_RELOC_OBJECTID);
@@ -6816,7 +6826,7 @@ static noinline int relocate_one_path(st
 
 	mutex_lock(&root->fs_info->tree_reloc_mutex);
 	ret = init_reloc_tree(trans, root);
-	BUG_ON(ret);
+	BTRFS_UERROR(ret);
 	reloc_root = root->reloc_root;
 
 	shared_level = ref_path->shared_level;
@@ -6849,7 +6859,7 @@ static noinline int relocate_one_path(st
 			eb = path->nodes[0];
 			ret = replace_extents_in_leaf(trans, reloc_root, eb,
 						      group, reloc_inode);
-			BUG_ON(ret);
+			BTRFS_UERROR(ret);
 		}
 		btrfs_release_path(reloc_root, path);
 	} else {
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -946,7 +946,10 @@ static ssize_t btrfs_file_write(struct f
 	file_update_time(file);
 
 	pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
-	BTRFS_UERROR(!pages);
+	if (!pages) {
+		err = -ENOMEM;
+		goto out;
+	}
 
 	/* generic_write_checks can change our pos */
 	start_pos = pos;
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -273,7 +273,8 @@ static noinline int add_async_extent(str
 	struct async_extent *async_extent;
 
 	async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
-	BTRFS_UERROR(!async_extent);
+	if (!async_extent)
+		return -ENOMEM;
 	async_extent->start = start;
 	async_extent->ram_size = ram_size;
 	async_extent->compressed_size = compressed_size;
@@ -483,8 +484,9 @@ again:
 		 * allocation on disk for these compressed pages,
 		 * and will submit them to the elevator.
 		 */
-		add_async_extent(async_cow, start, num_bytes,
-				 total_compressed, pages, nr_pages_ret);
+		ret = add_async_extent(async_cow, start, num_bytes,
+				       total_compressed, pages, nr_pages_ret);
+		BTRFS_UERROR(ret);
 
 		if (start + num_bytes < end && start + num_bytes < actual_end) {
 			start += num_bytes;
@@ -506,7 +508,9 @@ cleanup_and_bail_uncompressed:
 			__set_page_dirty_nobuffers(locked_page);
 			/* unlocked later on in the async handlers */
 		}
-		add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0);
+		ret = add_async_extent(async_cow, start,
+				       end - start + 1, 0, NULL, 0);
+		BTRFS_UERROR(ret);
 		*num_added += 1;
 	}
 
@@ -4450,7 +4454,8 @@ static noinline int uncompress_inline(st
 	inline_size = btrfs_file_extent_inline_item_len(leaf,
 					btrfs_item_nr(leaf, path->slots[0]));
 	tmp = kmalloc(inline_size, GFP_NOFS);
-	BTRFS_UERROR(!tmp);
+	if (!tmp)
+		return -ENOMEM;
 	ptr = btrfs_file_extent_inline_start(item);
 
 	read_extent_buffer(leaf, tmp, ptr, inline_size);
@@ -4648,7 +4653,7 @@ again:
 				ret = uncompress_inline(path, inode, page,
 							pg_offset,
 							extent_offset, item);
-				BUG_ON(ret);
+				BTRFS_UERROR(ret);
 			} else {
 				map = kmap(page);
 				read_extent_buffer(leaf, map + pg_offset, ptr,
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -850,7 +850,8 @@ static int __add_reloc_root(struct btrfs
 	struct reloc_control *rc = root->fs_info->reloc_ctl;
 
 	node = kmalloc(sizeof(*node), GFP_NOFS);
-	BTRFS_UERROR(!node);
+	if (!node)
+		return -ENOMEM;
 
 	node->bytenr = root->node->start;
 	node->data = root;
@@ -925,7 +926,8 @@ int btrfs_init_reloc_root(struct btrfs_t
 		return 0;
 
 	root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
-	BTRFS_UERROR(!root_item);
+	if (!root_item)
+		return -ENOMEM;
 
 	root_key.objectid = BTRFS_TREE_RELOC_OBJECTID;
 	root_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -957,7 +959,8 @@ int btrfs_init_reloc_root(struct btrfs_t
 	BUG_ON(IS_ERR(reloc_root));
 	reloc_root->last_trans = trans->transid;
 
-	__add_reloc_root(reloc_root);
+	ret = __add_reloc_root(reloc_root);
+	BTRFS_UERROR(ret);
 	root->reloc_root = reloc_root;
 	return 0;
 }
@@ -3721,7 +3724,8 @@ int btrfs_recover_relocation(struct btrf
 				       reloc_root->root_key.offset);
 		BUG_ON(IS_ERR(fs_root));
 
-		__add_reloc_root(reloc_root);
+		err = __add_reloc_root(reloc_root);
+		BTRFS_UERROR(err);
 		fs_root->reloc_root = reloc_root;
 	}
 
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -56,7 +56,8 @@ static noinline int join_transaction(str
 	if (!cur_trans) {
 		cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
 					     GFP_NOFS);
-		BTRFS_UERROR(!cur_trans);
+		if (!cur_trans)
+			return -ENOMEM;
 		root->fs_info->generation++;
 		cur_trans->num_writers = 1;
 		cur_trans->num_joined = 0;
@@ -102,6 +103,7 @@ static noinline int join_transaction(str
 static noinline int record_root_in_trans(struct btrfs_trans_handle *trans,
 					 struct btrfs_root *root)
 {
+	int ret;
 	if (root->ref_cows && root->last_trans < trans->transid) {
 		WARN_ON(root == root->fs_info->extent_root);
 		WARN_ON(root->commit_root != root->node);
@@ -110,7 +112,8 @@ static noinline int record_root_in_trans
 			   (unsigned long)root->root_key.objectid,
 			   BTRFS_ROOT_TRANS_TAG);
 		root->last_trans = trans->transid;
-		btrfs_init_reloc_root(trans, root);
+		ret = btrfs_init_reloc_root(trans, root);
+		BTRFS_UERROR(ret);
 	}
 	return 0;
 }
@@ -170,7 +173,8 @@ static struct btrfs_trans_handle *start_
 		kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
 	int ret;
 
-	BTRFS_UERROR(!h);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
 
 	mutex_lock(&root->fs_info->trans_mutex);
 	if (!root->fs_info->log_root_recovering &&
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -663,7 +663,8 @@ static noinline int drop_one_dir_item(st
 	btrfs_dir_item_key_to_cpu(leaf, di, &location);
 	name_len = btrfs_dir_name_len(leaf, di);
 	name = kmalloc(name_len, GFP_NOFS);
-	BTRFS_UERROR(!name);
+	if (!name)
+		return -ENOMEM;
 	read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
 	btrfs_release_path(root, path);
 
@@ -895,7 +896,7 @@ conflict_again:
 					 name, namelen, 0);
 	if (di && !IS_ERR(di)) {
 		ret = drop_one_dir_item(trans, root, path, dir, di);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 	}
 	btrfs_release_path(root, path);
 
@@ -905,7 +906,7 @@ conflict_again:
 				   name, namelen, 0);
 	if (di && !IS_ERR(di)) {
 		ret = drop_one_dir_item(trans, root, path, dir, di);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 	}
 	btrfs_release_path(root, path);
 
@@ -1167,7 +1168,10 @@ static noinline int replay_one_name(stru
 
 	name_len = btrfs_dir_name_len(eb, di);
 	name = kmalloc(name_len, GFP_NOFS);
-	BTRFS_UERROR(!name);
+	if (!name) {
+		iput(dir);
+		return -ENOMEM;
+	}
 	log_type = btrfs_dir_type(eb, di);
 	read_extent_buffer(eb, name, (unsigned long)(di + 1),
 		   name_len);
@@ -1217,7 +1221,7 @@ static noinline int replay_one_name(stru
 		goto out;
 
 	ret = drop_one_dir_item(trans, root, path, dir, dst_di);
-	BUG_ON(ret);
+	BTRFS_UERROR(ret);
 
 	if (key->type == BTRFS_DIR_INDEX_KEY)
 		goto insert;
@@ -1261,7 +1265,7 @@ static noinline int replay_one_dir_item(
 		di = (struct btrfs_dir_item *)ptr;
 		name_len = btrfs_dir_name_len(eb, di);
 		ret = replay_one_name(trans, root, path, eb, di, key);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 		ptr = (unsigned long)(di + 1);
 		ptr += name_len;
 	}
@@ -2575,7 +2579,8 @@ static noinline int copy_items(struct bt
 
 	ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
 			   nr * sizeof(u32), GFP_NOFS);
-	BTRFS_UERROR(!ins_data);
+	if (!ins_data)
+		return -ENOMEM;
 	ins_sizes = (u32 *)ins_data;
 	ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
@@ -2766,7 +2771,7 @@ again:
 
 		ret = copy_items(trans, log, dst_path, src, ins_start_slot,
 				 ins_nr, inode_only);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 		ins_nr = 1;
 		ins_start_slot = path->slots[0];
 next_slot:
@@ -2782,7 +2787,7 @@ next_slot:
 			ret = copy_items(trans, log, dst_path, src,
 					 ins_start_slot,
 					 ins_nr, inode_only);
-			BUG_ON(ret);
+			BTRFS_UERROR(ret);
 			ins_nr = 0;
 		}
 		btrfs_release_path(root, path);
@@ -2800,7 +2805,7 @@ next_slot:
 		ret = copy_items(trans, log, dst_path, src,
 				 ins_start_slot,
 				 ins_nr, inode_only);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 		ins_nr = 0;
 	}
 	WARN_ON(ins_nr);
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2819,7 +2819,10 @@ int btrfs_rmap_block(struct btrfs_mappin
 		do_div(length, map->num_stripes);
 
 	buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
-	BTRFS_UERROR(!buf);
+	if (!buf) {
+		free_extent_map(em);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < map->num_stripes; i++) {
 		if (devid && map->stripes[i].dev->devid != devid)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 08/10] btrfs: annotate btrfs_{start,join}_transaction failures
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (6 preceding siblings ...)
  2009-11-04 19:03 ` [patch 07/10] btrfs: handle kmalloc call path failures Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 09/10] btrfs: handle btrfs_{start,join}_transaction call path failures Jeff Mahoney
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

This patch locates and adds checks for failed transaction joins
and starts. It doesn't do anything other than use BTRFS_UERROR to
annotate them to keep the patch simple and obvious.

The next patch will add handling up the call chain where it's obvious.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

---
 fs/btrfs/disk-io.c     |    3 +++
 fs/btrfs/extent-tree.c |   11 +++++++----
 fs/btrfs/file.c        |    1 +
 fs/btrfs/inode.c       |   23 ++++++++++++++++++++---
 fs/btrfs/ioctl.c       |   10 ++++++----
 fs/btrfs/relocation.c  |   12 +++++++++++-
 fs/btrfs/super.c       |    1 +
 fs/btrfs/transaction.c |    3 +++
 fs/btrfs/tree-log.c    |    1 +
 fs/btrfs/volumes.c     |    6 ++++--
 fs/btrfs/xattr.c       |    1 +
 11 files changed, 58 insertions(+), 14 deletions(-)

--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1529,6 +1529,7 @@ static int transaction_kthread(void *arg
 		}
 		mutex_unlock(&root->fs_info->trans_mutex);
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		ret = btrfs_commit_transaction(trans, root);
 
 sleep:
@@ -2395,10 +2396,12 @@ int btrfs_commit_super(struct btrfs_root
 	btrfs_clean_old_snapshots(root);
 	mutex_unlock(&root->fs_info->cleaner_mutex);
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	ret = btrfs_commit_transaction(trans, root);
 	BUG_ON(ret);
 	/* run commit again to drop the original snapshot */
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_commit_transaction(trans, root);
 	ret = btrfs_write_and_wait_transaction(NULL, root);
 	BUG_ON(ret);
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3272,7 +3272,7 @@ alloc:
 			committed = 1;
 			trans = btrfs_join_transaction(root, 1);
 			if (!trans)
-				return -ENOMEM;
+				return PTR_ERR(trans);
 			ret = btrfs_commit_transaction(trans, root);
 			if (ret)
 				return ret;
@@ -5396,6 +5396,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	}
 
 	trans = btrfs_start_transaction(tree_root, 1);
+	BTRFS_UERROR(!trans);
 
 	if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
 		level = btrfs_header_level(root->node);
@@ -5492,6 +5493,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 
 			btrfs_end_transaction(trans, tree_root);
 			trans = btrfs_start_transaction(tree_root, 1);
+			BTRFS_UERROR(!trans);
 		} else {
 			unsigned long update;
 			update = trans->delayed_ref_updates;
@@ -6654,7 +6656,7 @@ int btrfs_drop_dead_reloc_roots(struct b
 		BUG_ON(reloc_root->commit_root != NULL);
 		while (1) {
 			trans = btrfs_join_transaction(root, 1);
-			BUG_ON(!trans);
+			BTRFS_UERROR(!trans);
 
 			mutex_lock(&root->fs_info->drop_mutex);
 			ret = btrfs_drop_snapshot(trans, reloc_root);
@@ -6712,7 +6714,7 @@ int btrfs_cleanup_reloc_trees(struct btr
 
 	if (found) {
 		trans = btrfs_start_transaction(root, 1);
-		BUG_ON(!trans);
+		BTRFS_UERROR(!trans);
 		ret = btrfs_commit_transaction(trans, root);
 		BUG_ON(ret);
 	}
@@ -6957,7 +6959,7 @@ static noinline int relocate_one_extent(
 
 
 	trans = btrfs_start_transaction(extent_root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	if (extent_key->objectid == 0) {
 		ret = del_extent_zero(trans, extent_root, path, extent_key);
@@ -7140,6 +7142,7 @@ static int __alloc_chunk_for_shrink(stru
 		spin_unlock(&shrink_block_group->lock);
 
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		spin_lock(&shrink_block_group->lock);
 
 		new_alloc_flags = update_block_group_flags(root,
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1083,6 +1083,7 @@ out_nolock:
 
 		if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
 			trans = btrfs_start_transaction(root, 1);
+			BTRFS_UERROR(!trans);
 			ret = btrfs_log_dentry_safe(trans, root,
 						    file->f_dentry);
 			if (ret == 0) {
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -403,7 +403,7 @@ again:
 	}
 	if (start == 0) {
 		trans = btrfs_join_transaction(root, 1);
-		BUG_ON(!trans);
+		BTRFS_UERROR(!trans);
 		btrfs_set_trans_block_group(trans, inode);
 
 		/* lets try to make an inline extent */
@@ -550,6 +550,7 @@ static noinline int submit_compressed_ex
 		return 0;
 
 	trans = btrfs_join_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	while (!list_empty(&async_cow->extents)) {
 		async_extent = list_entry(async_cow->extents.next,
@@ -664,6 +665,7 @@ static noinline int submit_compressed_ex
 
 		BUG_ON(ret);
 		trans = btrfs_join_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		alloc_hint = ins.objectid + ins.offset;
 		kfree(async_extent);
 		cond_resched();
@@ -708,7 +710,7 @@ static noinline int cow_file_range(struc
 	int ret = 0;
 
 	trans = btrfs_join_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, inode);
 
 	actual_end = min_t(u64, isize, end + 1);
@@ -990,7 +992,7 @@ static noinline int run_delalloc_nocow(s
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
 	trans = btrfs_join_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	cow_start = (u64)-1;
 	cur_offset = start;
@@ -1709,6 +1711,7 @@ static int btrfs_finish_ordered_io(struc
 	}
 
 	trans = btrfs_join_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	if (!ordered_extent)
 		ordered_extent = btrfs_lookup_ordered_extent(inode, start);
@@ -2129,6 +2132,7 @@ void btrfs_orphan_cleanup(struct btrfs_r
 		 */
 		if (is_bad_inode(inode)) {
 			trans = btrfs_start_transaction(root, 1);
+			BTRFS_UERROR(!trans);
 			btrfs_orphan_del(trans, inode);
 			btrfs_end_transaction(trans, root);
 			iput(inode);
@@ -2482,6 +2486,7 @@ static int btrfs_unlink(struct inode *di
 	root = BTRFS_I(dir)->root;
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	btrfs_set_trans_block_group(trans, dir);
 
@@ -2577,6 +2582,7 @@ static int btrfs_rmdir(struct inode *dir
 		return -ENOTEMPTY;
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, dir);
 
 	if (unlikely(inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
@@ -3152,6 +3158,7 @@ int btrfs_cont_expand(struct inode *inod
 	}
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, inode);
 
 	cur_offset = hole_start;
@@ -3249,6 +3256,7 @@ void btrfs_delete_inode(struct inode *in
 
 	btrfs_i_size_write(inode, 0);
 	trans = btrfs_join_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	btrfs_set_trans_block_group(trans, inode);
 	ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, 0);
@@ -3845,6 +3853,7 @@ int btrfs_write_inode(struct inode *inod
 
 	if (wait) {
 		trans = btrfs_join_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		btrfs_set_trans_block_group(trans, inode);
 		ret = btrfs_commit_transaction(trans, root);
 	}
@@ -3863,6 +3872,7 @@ void btrfs_dirty_inode(struct inode *ino
 	struct btrfs_trans_handle *trans;
 
 	trans = btrfs_join_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, inode);
 	btrfs_update_inode(trans, root, inode);
 	btrfs_end_transaction(trans, root);
@@ -4156,6 +4166,7 @@ static int btrfs_mknod(struct inode *dir
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
+	err = -ENOMEM;
 	if (!trans)
 		goto fail;
 	btrfs_set_trans_block_group(trans, dir);
@@ -4226,6 +4237,7 @@ static int btrfs_create(struct inode *di
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
+	err = -ENOMEM;
 	if (!trans)
 		goto fail;
 	btrfs_set_trans_block_group(trans, dir);
@@ -4306,6 +4318,7 @@ static int btrfs_link(struct dentry *old
 		goto fail;
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	btrfs_set_trans_block_group(trans, dir);
 	atomic_inc(&inode->i_count);
@@ -4673,6 +4686,7 @@ again:
 				em = NULL;
 				btrfs_release_path(root, path);
 				trans = btrfs_join_transaction(root, 1);
+				BTRFS_UERROR(!trans);
 				goto again;
 			}
 			map = kmap(page);
@@ -5042,6 +5056,7 @@ static void btrfs_truncate(struct inode
 	btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 
 	/*
 	 * setattr is responsible for setting the ordered_data_close flag,
@@ -5314,6 +5329,7 @@ static int btrfs_rename(struct inode *ol
 		down_read(&root->fs_info->subvol_sem);
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, new_dir);
 
 	if (dest != root)
@@ -5494,6 +5510,7 @@ static int btrfs_symlink(struct inode *d
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
+	err = -ENOMEM;
 	if (!trans)
 		goto out_fail;
 	btrfs_set_trans_block_group(trans, dir);
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -199,7 +199,7 @@ static int btrfs_ioctl_setflags(struct f
 
 
 	trans = btrfs_join_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	ret = btrfs_update_inode(trans, root, inode);
 	BUG_ON(ret);
@@ -250,7 +250,7 @@ static noinline int create_subvol(struct
 		return ret;
 
 	trans = btrfs_start_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
 				       0, &objectid);
@@ -391,7 +391,7 @@ static int create_snapshot(struct btrfs_
 	pending_snapshot->name[namelen] = '\0';
 	pending_snapshot->dentry = dentry;
 	trans = btrfs_start_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 	pending_snapshot->root = root;
 	list_add(&pending_snapshot->list,
 		 &trans->transaction->pending_snapshots);
@@ -639,6 +639,7 @@ static noinline int btrfs_ioctl_resize(s
 
 	if (new_size > old_size) {
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		ret = btrfs_grow_device(trans, device, new_size);
 		btrfs_commit_transaction(trans, root);
 	} else {
@@ -804,6 +805,7 @@ static noinline int btrfs_ioctl_snap_des
 		goto out_up_write;
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	ret = btrfs_unlink_subvol(trans, root, dir,
 				dest->root_key.objectid,
 				dentry->d_name.name,
@@ -1024,7 +1026,7 @@ static noinline long btrfs_ioctl_clone(s
 	}
 
 	trans = btrfs_start_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	/* punch hole in destination first */
 	btrfs_drop_extents(trans, root, inode, off, off + len,
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1638,6 +1638,7 @@ static noinline_for_stack int merge_relo
 
 	if (level == 0 && rc->stage == UPDATE_DATA_PTRS) {
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 
 		leaf = path->nodes[0];
 		btrfs_item_key_to_cpu(leaf, &key, 0);
@@ -1664,6 +1665,7 @@ static noinline_for_stack int merge_relo
 		leaf = NULL;
 		replaced = 0;
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		max_level = level;
 
 		ret = walk_down_reloc_tree(reloc_root, path, &level);
@@ -1799,6 +1801,7 @@ static void merge_func(struct btrfs_work
 		merge_reloc_root(async->rc, root);
 
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		btrfs_update_reloc_root(trans, root);
 		btrfs_end_transaction(trans, root);
 	}
@@ -3291,10 +3294,12 @@ static noinline_for_stack int relocate_b
 	set_reloc_control(rc);
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_commit_transaction(trans, rc->extent_root);
 
 	while (1) {
 		trans = btrfs_start_transaction(rc->extent_root, 1);
+		BTRFS_UERROR(!trans);
 
 		ret = find_next_extent(trans, rc, path);
 		if (ret < 0)
@@ -3405,6 +3410,7 @@ static noinline_for_stack int relocate_b
 
 	if (rc->extents_found > 0) {
 		trans = btrfs_start_transaction(rc->extent_root, 1);
+		BTRFS_UERROR(!trans);
 		btrfs_commit_transaction(trans, rc->extent_root);
 	}
 
@@ -3414,6 +3420,7 @@ static noinline_for_stack int relocate_b
 
 	/* get rid of pinned extents */
 	trans = btrfs_start_transaction(rc->extent_root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_commit_transaction(trans, rc->extent_root);
 
 	return err;
@@ -3469,7 +3476,7 @@ static struct inode *create_reloc_inode(
 		return ERR_CAST(root);
 
 	trans = btrfs_start_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
 	if (err)
@@ -3603,6 +3610,7 @@ static noinline_for_stack int mark_garba
 	int ret;
 
 	trans = btrfs_start_transaction(root->fs_info->tree_root, 1);
+	BTRFS_UERROR(!trans);
 
 	memset(&root->root_item.drop_progress, 0,
 		sizeof(root->root_item.drop_progress));
@@ -3730,6 +3738,7 @@ int btrfs_recover_relocation(struct btrf
 	}
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_commit_transaction(trans, rc->extent_root);
 
 	merge_reloc_roots(rc);
@@ -3737,6 +3746,7 @@ int btrfs_recover_relocation(struct btrf
 	unset_reloc_control(rc);
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_commit_transaction(trans, rc->extent_root);
 out:
 	if (rc) {
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -417,6 +417,7 @@ int btrfs_sync_fs(struct super_block *sb
 	btrfs_wait_ordered_extents(root, 0);
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	ret = btrfs_commit_transaction(trans, root);
 	return ret;
 }
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -630,6 +630,7 @@ int btrfs_defrag_root(struct btrfs_root
 	if (root->defrag_running)
 		return 0;
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	while (1) {
 		root->defrag_running = 1;
 		ret = btrfs_defrag_leaves(trans, root, cacheonly);
@@ -639,6 +640,7 @@ int btrfs_defrag_root(struct btrfs_root
 		cond_resched();
 
 		trans = btrfs_start_transaction(root, 1);
+		BTRFS_UERROR(!trans);
 		if (root->fs_info->closing || ret != -EAGAIN)
 			break;
 	}
@@ -812,6 +814,7 @@ static noinline int finish_pending_snaps
 	parent_inode = pending->dentry->d_parent->d_inode;
 	parent_root = BTRFS_I(parent_inode)->root;
 	trans = btrfs_join_transaction(parent_root, 1);
+	BTRFS_UERROR(!trans);
 
 	/*
 	 * insert the directory item
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3024,6 +3024,7 @@ int btrfs_recover_log_trees(struct btrfs
 	BUG_ON(!path);
 
 	trans = btrfs_start_transaction(fs_info->tree_root, 1);
+	BTRFS_UERROR(!trans);
 
 	wc.trans = trans;
 	wc.pin = 1;
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1090,6 +1090,7 @@ static int btrfs_rm_dev_item(struct btrf
 		return -ENOMEM;
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
 	key.type = BTRFS_DEV_ITEM_KEY;
 	key.offset = device->devid;
@@ -1480,6 +1481,7 @@ int btrfs_init_new_device(struct btrfs_r
 	}
 
 	trans = btrfs_start_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	lock_chunks(root);
 
 	device->barriers = 1;
@@ -1747,7 +1749,7 @@ static int btrfs_relocate_chunk(struct b
 	BUG_ON(ret);
 
 	trans = btrfs_start_transaction(root, 1);
-	BUG_ON(!trans);
+	BTRFS_UERROR(!trans);
 
 	lock_chunks(root);
 
@@ -1919,7 +1921,7 @@ int btrfs_balance(struct btrfs_root *dev
 		BUG_ON(ret);
 
 		trans = btrfs_start_transaction(dev_root, 1);
-		BUG_ON(!trans);
+		BTRFS_UERROR(!trans);
 
 		ret = btrfs_grow_device(trans, device, old_size);
 		BUG_ON(ret);
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -99,6 +99,7 @@ int __btrfs_setxattr(struct inode *inode
 		return -ENOMEM;
 
 	trans = btrfs_join_transaction(root, 1);
+	BTRFS_UERROR(!trans);
 	btrfs_set_trans_block_group(trans, inode);
 
 	/* first lets see if we already have this xattr */


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 09/10] btrfs: handle btrfs_{start,join}_transaction call path failures
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (7 preceding siblings ...)
  2009-11-04 19:03 ` [patch 08/10] btrfs: annotate btrfs_{start,join}_transaction failures Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:03 ` [patch 10/10] btrfs: annotate btrfs_alloc_path failures Jeff Mahoney
  2009-11-04 19:43 ` [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

This patch changes start_transaction() to return an ERR_PTR instead of
NULL. Things like I/O errors and allocation failures can be handled
differently.

Many calls that were previously handled by BTRFS_UERROR are changed to
actually pass the error up the tree where appropriate.

In cases where the handling isn't small or obvious, the BTRFS_UERROR
call is kept for handling in small patches specific to that site.

Eventually it may be preferable to allow passing of gfp_t to
btrfs_start_transaction (or a one-off) so that handling can be done at
allocation time instead of failing all the way up the call path.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

---
 fs/btrfs/compression.c |   10 ++-
 fs/btrfs/disk-io.c     |   37 +++++++++-----
 fs/btrfs/extent-tree.c |   43 ++++++++++------
 fs/btrfs/extent_io.c   |   60 ++++++++++++++--------
 fs/btrfs/file.c        |   16 ++++--
 fs/btrfs/inode.c       |  128 ++++++++++++++++++++++++++++++-------------------
 fs/btrfs/ioctl.c       |   73 +++++++++++++++++++--------
 fs/btrfs/relocation.c  |   96 ++++++++++++++++++++++++++++--------
 fs/btrfs/super.c       |   12 +++-
 fs/btrfs/transaction.c |   34 +++++++++----
 fs/btrfs/tree-log.c    |   14 +++--
 fs/btrfs/volumes.c     |   44 ++++++++++------
 fs/btrfs/xattr.c       |    3 -
 13 files changed, 382 insertions(+), 188 deletions(-)

--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -280,6 +280,7 @@ static void end_compressed_bio_write(str
 	struct inode *inode;
 	struct page *page;
 	unsigned long index;
+	int ret;
 
 	if (err)
 		cb->errors = 1;
@@ -296,10 +297,11 @@ static void end_compressed_bio_write(str
 	inode = cb->inode;
 	tree = &BTRFS_I(inode)->io_tree;
 	cb->compressed_pages[0]->mapping = cb->inode->i_mapping;
-	tree->ops->writepage_end_io_hook(cb->compressed_pages[0],
-					 cb->start,
-					 cb->start + cb->len - 1,
-					 NULL, 1);
+	ret = tree->ops->writepage_end_io_hook(cb->compressed_pages[0],
+					       cb->start,
+					       cb->start + cb->len - 1,
+					       NULL, 1);
+	BTRFS_UERROR(ret);
 	cb->compressed_pages[0]->mapping = NULL;
 
 	end_compressed_writeback(inode, cb->start, cb->len);
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1468,6 +1468,7 @@ static void end_workqueue_fn(struct btrf
 static int cleaner_kthread(void *arg)
 {
 	struct btrfs_root *root = arg;
+	int ret;
 
 	do {
 		smp_mb();
@@ -1478,7 +1479,8 @@ static int cleaner_kthread(void *arg)
 
 		if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
 		    mutex_trylock(&root->fs_info->cleaner_mutex)) {
-			btrfs_clean_old_snapshots(root);
+			ret = btrfs_clean_old_snapshots(root);
+			BTRFS_UERROR(ret);
 			mutex_unlock(&root->fs_info->cleaner_mutex);
 		}
 
@@ -1529,9 +1531,11 @@ static int transaction_kthread(void *arg
 		}
 		mutex_unlock(&root->fs_info->trans_mutex);
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
-		ret = btrfs_commit_transaction(trans, root);
+		if (!IS_ERR(trans))
+			ret = btrfs_commit_transaction(trans, root);
 
+		if (IS_ERR(trans) || ret)
+			delay = HZ * 5;
 sleep:
 		wake_up_process(root->fs_info->cleaner_kthread);
 		mutex_unlock(&root->fs_info->transaction_kthread_mutex);
@@ -1971,11 +1975,15 @@ struct btrfs_root *open_ctree(struct sup
 						      blocksize,
 						      generation + 1);
 		ret = btrfs_recover_log_trees(log_tree_root);
-		BUG_ON(ret);
+		if (ret) {
+			/* log_tree_root is cleaned up by
+			 * btrfs_recover_log_trees */
+			goto fail_trans_thread;
+		}
 
 		if (sb->s_flags & MS_RDONLY) {
 			ret =  btrfs_commit_super(tree_root);
-			BUG_ON(ret);
+			BTRFS_UERROR(ret);
 		}
 	}
 
@@ -1984,7 +1992,7 @@ struct btrfs_root *open_ctree(struct sup
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		ret = btrfs_recover_relocation(tree_root);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 	}
 
 	location.objectid = BTRFS_FS_TREE_OBJECTID;
@@ -2393,16 +2401,23 @@ int btrfs_commit_super(struct btrfs_root
 	int ret;
 
 	mutex_lock(&root->fs_info->cleaner_mutex);
-	btrfs_clean_old_snapshots(root);
+	ret = btrfs_clean_old_snapshots(root);
 	mutex_unlock(&root->fs_info->cleaner_mutex);
+	if (ret)
+		return ret;
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 	ret = btrfs_commit_transaction(trans, root);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 	/* run commit again to drop the original snapshot */
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
-	btrfs_commit_transaction(trans, root);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
+	ret = btrfs_commit_transaction(trans, root);
+	if (ret)
+		return ret;
 	ret = btrfs_write_and_wait_transaction(NULL, root);
 	BUG_ON(ret);
 
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3009,8 +3009,8 @@ static int maybe_allocate_chunk(struct b
 	}
 
 	trans = btrfs_start_transaction(root, 1);
-	if (!trans) {
-		ret = -ENOMEM;
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
 		goto out;
 	}
 
@@ -3044,6 +3044,7 @@ int btrfs_reserve_metadata_for_delalloc(
 	u64 alloc_target;
 	int flushed = 0;
 	int force_delalloc;
+	int ret = 0;
 
 	/* get the space info for where the metadata will live */
 	alloc_target = btrfs_get_alloc_profile(root, 0);
@@ -3249,8 +3250,8 @@ again:
 alloc:
 			alloc_target = btrfs_get_alloc_profile(root, 1);
 			trans = btrfs_start_transaction(root, 1);
-			if (!trans)
-				return -ENOMEM;
+			if (IS_ERR(trans))
+				return PTR_ERR(trans);
 
 			ret = do_chunk_alloc(trans, root->fs_info->extent_root,
 					     bytes + 2 * 1024 * 1024,
@@ -3271,7 +3272,7 @@ alloc:
 		if (!committed && !root->fs_info->open_ioctl_trans) {
 			committed = 1;
 			trans = btrfs_join_transaction(root, 1);
-			if (!trans)
+			if (IS_ERR(trans))
 				return PTR_ERR(trans);
 			ret = btrfs_commit_transaction(trans, root);
 			if (ret)
@@ -5396,7 +5397,10 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	}
 
 	trans = btrfs_start_transaction(tree_root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		goto out_err;
+	}
 
 	if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
 		level = btrfs_header_level(root->node);
@@ -5493,7 +5497,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 
 			btrfs_end_transaction(trans, tree_root);
 			trans = btrfs_start_transaction(tree_root, 1);
-			BTRFS_UERROR(!trans);
+			BTRFS_UERROR(IS_ERR(trans));
 		} else {
 			unsigned long update;
 			update = trans->delayed_ref_updates;
@@ -5529,6 +5533,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	}
 out:
 	btrfs_end_transaction(trans, tree_root);
+out_err:
 	kfree(wc);
 	btrfs_free_path(path);
 	return err;
@@ -6656,7 +6661,7 @@ int btrfs_drop_dead_reloc_roots(struct b
 		BUG_ON(reloc_root->commit_root != NULL);
 		while (1) {
 			trans = btrfs_join_transaction(root, 1);
-			BTRFS_UERROR(!trans);
+			BTRFS_UERROR(IS_ERR(trans));
 
 			mutex_lock(&root->fs_info->drop_mutex);
 			ret = btrfs_drop_snapshot(trans, reloc_root);
@@ -6669,6 +6674,7 @@ int btrfs_drop_dead_reloc_roots(struct b
 			BUG_ON(ret);
 			btrfs_btree_balance_dirty(root, nr);
 		}
+		BTRFS_UERROR(ret);
 
 		free_extent_buffer(reloc_root->node);
 
@@ -6714,9 +6720,11 @@ int btrfs_cleanup_reloc_trees(struct btr
 
 	if (found) {
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
 		ret = btrfs_commit_transaction(trans, root);
-		BUG_ON(ret);
+		if (ret)
+			return ret;
 	}
 
 	location.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
@@ -6959,7 +6967,8 @@ static noinline int relocate_one_extent(
 
 
 	trans = btrfs_start_transaction(extent_root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	if (extent_key->objectid == 0) {
 		ret = del_extent_zero(trans, extent_root, path, extent_key);
@@ -6989,7 +6998,7 @@ static noinline int relocate_one_extent(
 			continue;
 
 		found_root = read_ref_root(extent_root->fs_info, ref_path);
-		BUG_ON(IS_ERR(found_root));
+		BTRFS_UERROR(IS_ERR(found_root));
 		/*
 		 * for reference counted tree, only process reference paths
 		 * rooted at the latest committed root.
@@ -7142,7 +7151,8 @@ static int __alloc_chunk_for_shrink(stru
 		spin_unlock(&shrink_block_group->lock);
 
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
 		spin_lock(&shrink_block_group->lock);
 
 		new_alloc_flags = update_block_group_flags(root,
@@ -7169,9 +7179,10 @@ int btrfs_prepare_block_group_relocation
 					 struct btrfs_block_group_cache *group)
 
 {
-	__alloc_chunk_for_shrink(root, group, 1);
-	set_block_group_readonly(group);
-	return 0;
+	int ret = __alloc_chunk_for_shrink(root, group, 1);
+	if (!ret)
+		set_block_group_readonly(group);
+	return ret;
 }
 
 /*
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1899,10 +1899,11 @@ static int submit_one_bio(int rw, struct
 
 	bio_get(bio);
 
-	if (tree->ops && tree->ops->submit_bio_hook)
-		tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
-					   mirror_num, bio_flags);
-	else
+	if (tree->ops && tree->ops->submit_bio_hook) {
+		ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
+						 mirror_num, bio_flags);
+		BTRFS_UERROR(ret);
+	} else
 		submit_bio(rw, bio);
 	if (bio_flagged(bio, BIO_EOPNOTSUPP))
 		ret = -EOPNOTSUPP;
@@ -2189,7 +2190,7 @@ static int __extent_writepage(struct pag
 	struct extent_state *cached_state = NULL;
 	struct extent_map *em;
 	struct block_device *bdev;
-	int ret;
+	int ret = 0;
 	int nr = 0;
 	size_t pg_offset = 0;
 	size_t blocksize;
@@ -2250,9 +2251,12 @@ static int __extent_writepage(struct pag
 				delalloc_start = delalloc_end + 1;
 				continue;
 			}
-			tree->ops->fill_delalloc(inode, page, delalloc_start,
-						 delalloc_end, &page_started,
-						 &nr_written);
+			ret = tree->ops->fill_delalloc(inode, page,
+						       delalloc_start,
+						       delalloc_end,
+						       &page_started,
+						       &nr_written);
+			BTRFS_UERROR(ret);
 			/*
 			 * delalloc_end is already one less than the total
 			 * length, so we don't subtract one from
@@ -2306,9 +2310,11 @@ static int __extent_writepage(struct pag
 
 	end = page_end;
 	if (last_byte <= start) {
-		if (tree->ops && tree->ops->writepage_end_io_hook)
-			tree->ops->writepage_end_io_hook(page, start,
-							 page_end, NULL, 1);
+		if (tree->ops && tree->ops->writepage_end_io_hook) {
+			ret = tree->ops->writepage_end_io_hook(page, start,
+							page_end, NULL, 1);
+			BTRFS_UERROR(ret);
+		}
 		unlock_start = page_end + 1;
 		goto done;
 	}
@@ -2317,9 +2323,12 @@ static int __extent_writepage(struct pag
 
 	while (cur <= end) {
 		if (cur >= last_byte) {
-			if (tree->ops && tree->ops->writepage_end_io_hook)
-				tree->ops->writepage_end_io_hook(page, cur,
-							 page_end, NULL, 1);
+			if (tree->ops && tree->ops->writepage_end_io_hook) {
+				ret = tree->ops->writepage_end_io_hook(page,
+								cur, page_end,
+								NULL, 1);
+				BTRFS_UERROR(ret);
+			}
 			unlock_start = page_end + 1;
 			break;
 		}
@@ -2353,10 +2362,12 @@ static int __extent_writepage(struct pag
 			 * compressed extents
 			 */
 			if (!compressed && tree->ops &&
-			    tree->ops->writepage_end_io_hook)
-				tree->ops->writepage_end_io_hook(page, cur,
-							 cur + iosize - 1,
-							 NULL, 1);
+			    tree->ops->writepage_end_io_hook) {
+				ret = tree->ops->writepage_end_io_hook(page,
+							cur, cur + iosize - 1,
+							NULL, 1);
+				BTRFS_UERROR(ret);
+			}
 			else if (compressed) {
 				/* we don't want to end_page_writeback on
 				 * a compressed extent.  this happens
@@ -2421,7 +2432,7 @@ done_unlocked:
 
 	/* drop our reference on any cached states */
 	free_extent_state(cached_state);
-	return 0;
+	return ret;
 }
 
 /**
@@ -2621,10 +2632,13 @@ int extent_write_locked_range(struct ext
 		if (clear_page_dirty_for_io(page))
 			ret = __extent_writepage(page, &wbc_writepages, &epd);
 		else {
-			if (tree->ops && tree->ops->writepage_end_io_hook)
-				tree->ops->writepage_end_io_hook(page, start,
-						 start + PAGE_CACHE_SIZE - 1,
-						 NULL, 1);
+			if (tree->ops && tree->ops->writepage_end_io_hook) {
+				ret = tree->ops->writepage_end_io_hook(page,
+						start,
+						start + PAGE_CACHE_SIZE - 1,
+						NULL, 1);
+				BTRFS_UERROR(ret);
+			}
 			unlock_page(page);
 		}
 		page_cache_release(page);
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1083,7 +1083,10 @@ out_nolock:
 
 		if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
 			trans = btrfs_start_transaction(root, 1);
-			BTRFS_UERROR(!trans);
+			if (IS_ERR(trans)) {
+				err = PTR_ERR(trans);
+				goto out;
+			}
 			ret = btrfs_log_dentry_safe(trans, root,
 						    file->f_dentry);
 			if (ret == 0) {
@@ -1091,9 +1094,11 @@ out_nolock:
 				if (ret == 0)
 					btrfs_end_transaction(trans, root);
 				else
-					btrfs_commit_transaction(trans, root);
+					err = btrfs_commit_transaction(trans,
+								       root);
+
 			} else if (ret != BTRFS_NO_LOG_SYNC) {
-				btrfs_commit_transaction(trans, root);
+				err = btrfs_commit_transaction(trans, root);
 			} else {
 				btrfs_end_transaction(trans, root);
 			}
@@ -1104,6 +1109,7 @@ out_nolock:
 			     (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
 		}
 	}
+out:
 	current->backing_dev_info = NULL;
 	return num_written ? num_written : err;
 }
@@ -1180,8 +1186,8 @@ int btrfs_sync_file(struct file *file, s
 		btrfs_ioctl_trans_end(file);
 
 	trans = btrfs_start_transaction(root, 1);
-	if (!trans) {
-		ret = -ENOMEM;
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
 		goto out;
 	}
 
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -403,7 +403,7 @@ again:
 	}
 	if (start == 0) {
 		trans = btrfs_join_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 		btrfs_set_trans_block_group(trans, inode);
 
 		/* lets try to make an inline extent */
@@ -550,7 +550,8 @@ static noinline int submit_compressed_ex
 		return 0;
 
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	while (!list_empty(&async_cow->extents)) {
 		async_extent = list_entry(async_cow->extents.next,
@@ -569,11 +570,12 @@ static noinline int submit_compressed_ex
 				    async_extent->ram_size - 1, GFP_NOFS);
 
 			/* allocate blocks */
-			cow_file_range(inode, async_cow->locked_page,
-				       async_extent->start,
-				       async_extent->start +
-				       async_extent->ram_size - 1,
-				       &page_started, &nr_written, 0);
+			ret = cow_file_range(inode, async_cow->locked_page,
+					     async_extent->start,
+					     async_extent->start +
+					     async_extent->ram_size - 1,
+					     &page_started, &nr_written, 0);
+			BTRFS_UERROR(ret);
 
 			/*
 			 * if page_started, cow_file_range inserted an
@@ -581,13 +583,15 @@ static noinline int submit_compressed_ex
 			 * and IO for us.  Otherwise, we need to submit
 			 * all those pages down to the drive.
 			 */
-			if (!page_started)
-				extent_write_locked_range(io_tree,
+			if (!page_started) {
+				ret = extent_write_locked_range(io_tree,
 						  inode, async_extent->start,
 						  async_extent->start +
 						  async_extent->ram_size - 1,
 						  btrfs_get_extent,
 						  WB_SYNC_ALL);
+				BTRFS_UERROR(ret);
+			}
 			kfree(async_extent);
 			cond_resched();
 			continue;
@@ -665,7 +669,7 @@ static noinline int submit_compressed_ex
 
 		BUG_ON(ret);
 		trans = btrfs_join_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 		alloc_hint = ins.objectid + ins.offset;
 		kfree(async_extent);
 		cond_resched();
@@ -710,7 +714,8 @@ static noinline int cow_file_range(struc
 	int ret = 0;
 
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 	btrfs_set_trans_block_group(trans, inode);
 
 	actual_end = min_t(u64, isize, end + 1);
@@ -838,10 +843,12 @@ static noinline void async_cow_start(str
 	struct async_cow *async_cow;
 	int num_added = 0;
 	async_cow = container_of(work, struct async_cow, work);
+	int ret;
 
-	compress_file_range(async_cow->inode, async_cow->locked_page,
-			    async_cow->start, async_cow->end, async_cow,
-			    &num_added);
+	ret = compress_file_range(async_cow->inode, async_cow->locked_page,
+				  async_cow->start, async_cow->end, async_cow,
+				  &num_added);
+	BTRFS_UERROR(ret);
 	if (num_added == 0)
 		async_cow->inode = NULL;
 }
@@ -992,7 +999,8 @@ static noinline int run_delalloc_nocow(s
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	cow_start = (u64)-1;
 	cur_offset = start;
@@ -1102,7 +1110,7 @@ out_check:
 			ret = cow_file_range(inode, locked_page, cow_start,
 					found_key.offset - 1, page_started,
 					nr_written, 1);
-			BUG_ON(ret);
+			BTRFS_UERROR(ret);
 			cow_start = (u64)-1;
 		}
 
@@ -1154,7 +1162,7 @@ out_check:
 	if (cow_start != (u64)-1) {
 		ret = cow_file_range(inode, locked_page, cow_start, end,
 				     page_started, nr_written, 1);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 	}
 
 	ret = btrfs_end_transaction(trans, root);
@@ -1711,7 +1719,8 @@ static int btrfs_finish_ordered_io(struc
 	}
 
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	if (!ordered_extent)
 		ordered_extent = btrfs_lookup_ordered_extent(inode, start);
@@ -2132,7 +2141,7 @@ void btrfs_orphan_cleanup(struct btrfs_r
 		 */
 		if (is_bad_inode(inode)) {
 			trans = btrfs_start_transaction(root, 1);
-			BTRFS_UERROR(!trans);
+			BTRFS_UERROR(IS_ERR(trans));
 			btrfs_orphan_del(trans, inode);
 			btrfs_end_transaction(trans, root);
 			iput(inode);
@@ -2486,7 +2495,8 @@ static int btrfs_unlink(struct inode *di
 	root = BTRFS_I(dir)->root;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	btrfs_set_trans_block_group(trans, dir);
 
@@ -2582,7 +2592,9 @@ static int btrfs_rmdir(struct inode *dir
 		return -ENOTEMPTY;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
+
 	btrfs_set_trans_block_group(trans, dir);
 
 	if (unlikely(inode->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
@@ -3158,14 +3170,17 @@ int btrfs_cont_expand(struct inode *inod
 	}
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		goto out;
+	}
 	btrfs_set_trans_block_group(trans, inode);
 
 	cur_offset = hole_start;
 	while (1) {
 		em = btrfs_get_extent(inode, NULL, 0, cur_offset,
 				block_end - cur_offset, 0);
-		BUG_ON(IS_ERR(em) || !em);
+		BTRFS_UERROR(IS_ERR(em) || !em);
 		last_byte = min(extent_map_end(em), block_end);
 		last_byte = (last_byte + mask) & ~mask;
 		if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
@@ -3198,6 +3213,7 @@ int btrfs_cont_expand(struct inode *inod
 	}
 
 	btrfs_end_transaction(trans, root);
+out:
 	unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
 	return err;
 }
@@ -3256,7 +3272,7 @@ void btrfs_delete_inode(struct inode *in
 
 	btrfs_i_size_write(inode, 0);
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	BTRFS_UERROR(IS_ERR(trans));
 
 	btrfs_set_trans_block_group(trans, inode);
 	ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, 0);
@@ -3853,7 +3869,8 @@ int btrfs_write_inode(struct inode *inod
 
 	if (wait) {
 		trans = btrfs_join_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans))
+			return PTR_ERR(trans);
 		btrfs_set_trans_block_group(trans, inode);
 		ret = btrfs_commit_transaction(trans, root);
 	}
@@ -3872,7 +3889,8 @@ void btrfs_dirty_inode(struct inode *ino
 	struct btrfs_trans_handle *trans;
 
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return;
 	btrfs_set_trans_block_group(trans, inode);
 	btrfs_update_inode(trans, root, inode);
 	btrfs_end_transaction(trans, root);
@@ -4166,9 +4184,10 @@ static int btrfs_mknod(struct inode *dir
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
-	err = -ENOMEM;
-	if (!trans)
-		goto fail;
+	if (IS_ERR(trans)) {
+		btrfs_unreserve_metadata_space(root, 5);
+		return PTR_ERR(trans);
+	}
 	btrfs_set_trans_block_group(trans, dir);
 
 	err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
@@ -4237,9 +4256,10 @@ static int btrfs_create(struct inode *di
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
-	err = -ENOMEM;
-	if (!trans)
-		goto fail;
+	if (IS_ERR(trans)) {
+		btrfs_unreserve_metadata_space(root, 5);
+		return PTR_ERR(trans);
+	}
 	btrfs_set_trans_block_group(trans, dir);
 
 	err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
@@ -4318,7 +4338,12 @@ static int btrfs_link(struct dentry *old
 		goto fail;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		btrfs_dec_nlink(inode);
+		BTRFS_I(dir)->index_cnt = index;
+		err = PTR_ERR(trans);
+		goto fail;
+	}
 
 	btrfs_set_trans_block_group(trans, dir);
 	atomic_inc(&inode->i_count);
@@ -4367,8 +4392,8 @@ static int btrfs_mkdir(struct inode *dir
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
-	if (!trans) {
-		err = -ENOMEM;
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
 		goto out_unlock;
 	}
 	btrfs_set_trans_block_group(trans, dir);
@@ -4686,7 +4711,7 @@ again:
 				em = NULL;
 				btrfs_release_path(root, path);
 				trans = btrfs_join_transaction(root, 1);
-				BTRFS_UERROR(!trans);
+				BTRFS_UERROR(IS_ERR(trans));
 				goto again;
 			}
 			map = kmap(page);
@@ -4892,8 +4917,10 @@ static void btrfs_invalidatepage(struct
 		 * for the finish_ordered_io
 		 */
 		if (TestClearPagePrivate2(page)) {
-			btrfs_finish_ordered_io(page->mapping->host,
-						page_start, page_end);
+			int ret;
+			ret = btrfs_finish_ordered_io(page->mapping->host,
+						      page_start, page_end);
+			BTRFS_UERROR(ret);
 		}
 		btrfs_put_ordered_extent(ordered);
 		lock_extent(tree, page_start, page_end, GFP_NOFS);
@@ -5042,7 +5069,7 @@ static void btrfs_truncate(struct inode
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	int ret;
 	struct btrfs_trans_handle *trans;
-	unsigned long nr;
+	unsigned long nr = 0;
 	u64 mask = root->sectorsize - 1;
 
 	if (!S_ISREG(inode->i_mode))
@@ -5056,7 +5083,7 @@ static void btrfs_truncate(struct inode
 	btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	BTRFS_UERROR(IS_ERR(trans));
 
 	/*
 	 * setattr is responsible for setting the ordered_data_close flag,
@@ -5329,7 +5356,10 @@ static int btrfs_rename(struct inode *ol
 		down_read(&root->fs_info->subvol_sem);
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto out_fail_notrans;
+	}
 	btrfs_set_trans_block_group(trans, new_dir);
 
 	if (dest != root)
@@ -5425,6 +5455,8 @@ static int btrfs_rename(struct inode *ol
 out_fail:
 	btrfs_end_transaction_throttle(trans, root);
 
+out_fail_notrans:
+
 	if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
 		up_read(&root->fs_info->subvol_sem);
 
@@ -5510,9 +5542,10 @@ static int btrfs_symlink(struct inode *d
 		return err;
 
 	trans = btrfs_start_transaction(root, 1);
-	err = -ENOMEM;
-	if (!trans)
-		goto out_fail;
+	if (IS_ERR(trans)) {
+		btrfs_unreserve_metadata_space(root, 5);
+		return PTR_ERR(trans);
+	}
 	btrfs_set_trans_block_group(trans, dir);
 
 	err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
@@ -5592,7 +5625,6 @@ static int btrfs_symlink(struct inode *d
 out_unlock:
 	nr = trans->blocks_used;
 	btrfs_end_transaction_throttle(trans, root);
-out_fail:
 	btrfs_unreserve_metadata_space(root, 5);
 	if (drop_inode) {
 		inode_dec_link_count(inode);
@@ -5698,8 +5730,8 @@ static long btrfs_fallocate(struct inode
 		struct btrfs_ordered_extent *ordered;
 
 		trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
-		if (!trans) {
-			ret = -EIO;
+		if (IS_ERR(trans)) {
+			ret = PTR_ERR(trans);
 			goto out_free;
 		}
 
@@ -5735,7 +5767,7 @@ static long btrfs_fallocate(struct inode
 	while (1) {
 		em = btrfs_get_extent(inode, NULL, 0, cur_offset,
 				      alloc_end - cur_offset, 0);
-		BUG_ON(IS_ERR(em) || !em);
+		BTRFS_UERROR(IS_ERR(em) || !em);
 		last_byte = min(extent_map_end(em), alloc_end);
 		last_byte = (last_byte + mask) & ~mask;
 		if (em->block_start == EXTENT_MAP_HOLE) {
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -172,6 +172,12 @@ static int btrfs_ioctl_setflags(struct f
 	if (ret)
 		goto out_unlock;
 
+	trans = btrfs_join_transaction(root, 1);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto out_drop_write;
+	}
+
 	if (flags & FS_SYNC_FL)
 		ip->flags |= BTRFS_INODE_SYNC;
 	else
@@ -197,10 +203,6 @@ static int btrfs_ioctl_setflags(struct f
 	else
 		ip->flags &= ~BTRFS_INODE_DIRSYNC;
 
-
-	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
-
 	ret = btrfs_update_inode(trans, root, inode);
 	BUG_ON(ret);
 
@@ -208,10 +210,11 @@ static int btrfs_ioctl_setflags(struct f
 	inode->i_ctime = CURRENT_TIME;
 	btrfs_end_transaction(trans, root);
 
+out_drop_write:
 	mnt_drop_write(file->f_path.mnt);
- out_unlock:
+out_unlock:
 	mutex_unlock(&inode->i_mutex);
-	return 0;
+	return ret;
 }
 
 static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
@@ -232,6 +235,7 @@ static noinline int create_subvol(struct
 	struct extent_buffer *leaf;
 	struct btrfs_root *new_root;
 	struct inode *dir = dentry->d_parent->d_inode;
+	struct inode *inode;
 	int ret;
 	int err;
 	u64 objectid;
@@ -250,7 +254,10 @@ static noinline int create_subvol(struct
 		return ret;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		btrfs_unreserve_metadata_space(root, 6);
+		return PTR_ERR(trans);
+	}
 
 	ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
 				       0, &objectid);
@@ -312,7 +319,7 @@ static noinline int create_subvol(struct
 
 	key.offset = (u64)-1;
 	new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
-	BUG_ON(IS_ERR(new_root));
+	BTRFS_UERROR(IS_ERR(new_root));
 
 	btrfs_record_root_in_trans(trans, new_root);
 
@@ -340,13 +347,14 @@ static noinline int create_subvol(struct
 
 	BUG_ON(ret);
 
-	d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
+	inode = btrfs_lookup_dentry(dir, dentry);
+	BTRFS_UERROR(IS_ERR(inode));
+	d_instantiate(dentry, inode);
 fail:
 	nr = trans->blocks_used;
 	err = btrfs_commit_transaction(trans, root);
 	if (err && !ret)
 		ret = err;
-
 	btrfs_unreserve_metadata_space(root, 6);
 	btrfs_btree_balance_dirty(root, nr);
 	return ret;
@@ -358,7 +366,6 @@ static int create_snapshot(struct btrfs_
 	struct btrfs_pending_snapshot *pending_snapshot;
 	struct btrfs_trans_handle *trans;
 	int ret = 0;
-	int err;
 	unsigned long nr = 0;
 
 	if (!root->ref_cows)
@@ -391,11 +398,16 @@ static int create_snapshot(struct btrfs_
 	pending_snapshot->name[namelen] = '\0';
 	pending_snapshot->dentry = dentry;
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		kfree(pending_snapshot->name);
+		kfree(pending_snapshot);
+		ret = PTR_ERR(trans);
+		goto fail_unlock;
+	}
 	pending_snapshot->root = root;
 	list_add(&pending_snapshot->list,
 		 &trans->transaction->pending_snapshots);
-	err = btrfs_commit_transaction(trans, root);
+	ret = btrfs_commit_transaction(trans, root);
 
 fail_unlock:
 	btrfs_btree_balance_dirty(root, nr);
@@ -638,10 +650,15 @@ static noinline int btrfs_ioctl_resize(s
 		device->name, (unsigned long long)new_size);
 
 	if (new_size > old_size) {
+		int err;
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans)) {
+			ret = PTR_ERR(trans);
+			goto out_unlock;
+		}
 		ret = btrfs_grow_device(trans, device, new_size);
-		btrfs_commit_transaction(trans, root);
+		err = btrfs_commit_transaction(trans, root);
+		ret = ret ?: err;
 	} else {
 		ret = btrfs_shrink_device(device, new_size);
 	}
@@ -805,7 +822,10 @@ static noinline int btrfs_ioctl_snap_des
 		goto out_up_write;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		goto out_up_write;
+	}
 	ret = btrfs_unlink_subvol(trans, root, dir,
 				dest->root_key.objectid,
 				dentry->d_name.name,
@@ -825,7 +845,7 @@ static noinline int btrfs_ioctl_snap_des
 	BUG_ON(ret);
 
 	ret = btrfs_commit_transaction(trans, root);
-	BUG_ON(ret);
+	BTRFS_UERROR(ret);
 	inode->i_flags |= S_DEAD;
 out_up_write:
 	up_write(&root->fs_info->subvol_sem);
@@ -862,15 +882,16 @@ static int btrfs_ioctl_defrag(struct fil
 			ret = -EPERM;
 			goto out;
 		}
-		btrfs_defrag_root(root, 0);
-		btrfs_defrag_root(root->fs_info->extent_root, 0);
+		ret = btrfs_defrag_root(root, 0);
+		if (!ret)
+			ret = btrfs_defrag_root(root->fs_info->extent_root, 0);
 		break;
 	case S_IFREG:
 		if (!(file->f_mode & FMODE_WRITE)) {
 			ret = -EINVAL;
 			goto out;
 		}
-		btrfs_defrag_file(file);
+		ret = btrfs_defrag_file(file);
 		break;
 	}
 out:
@@ -1026,7 +1047,12 @@ static noinline long btrfs_ioctl_clone(s
 	}
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		btrfs_release_path(root, path);
+		unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
+		goto out_unlock;
+	}
 
 	/* punch hole in destination first */
 	btrfs_drop_extents(trans, root, inode, off, off + len,
@@ -1255,10 +1281,11 @@ static long btrfs_ioctl_trans_start(stru
 	root->fs_info->open_ioctl_trans++;
 	mutex_unlock(&root->fs_info->trans_mutex);
 
-	ret = -ENOMEM;
 	trans = btrfs_start_ioctl_transaction(root, 0);
-	if (!trans)
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
 		goto out_drop;
+	}
 
 	file->private_data = trans;
 	return 0;
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -398,7 +398,8 @@ struct btrfs_root *find_tree_root(struct
 	BUG_ON(root_objectid == BTRFS_TREE_RELOC_OBJECTID);
 
 	root = read_fs_root(rc->extent_root->fs_info, root_objectid);
-	BUG_ON(IS_ERR(root));
+	if (IS_ERR(root))
+		return ERR_CAST(root);
 
 	if (root->ref_cows &&
 	    generation != btrfs_root_generation(&root->root_item))
@@ -592,6 +593,7 @@ again:
 				ref0 = btrfs_item_ptr(eb, path1->slots[0],
 						struct btrfs_extent_ref_v0);
 				root = find_tree_root(rc, eb, ref0);
+				BTRFS_UERROR(IS_ERR(root));
 				if (root)
 					cur->root = root;
 				else
@@ -1638,12 +1640,20 @@ static noinline_for_stack int merge_relo
 
 	if (level == 0 && rc->stage == UPDATE_DATA_PTRS) {
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans)) {
+			extent_buffer_put(reloc_root->node);
+		}
+		BTRFS_UERROR(IS_ERR(trans));
 
 		leaf = path->nodes[0];
 		btrfs_item_key_to_cpu(leaf, &key, 0);
 		btrfs_release_path(reloc_root, path);
 
+		if (IS_ERR(trans)) {
+			err = PTR_ERR(trans);
+			goto out;
+		}
+
 		ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
 		if (ret < 0) {
 			err = ret;
@@ -1665,7 +1675,7 @@ static noinline_for_stack int merge_relo
 		leaf = NULL;
 		replaced = 0;
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 		max_level = level;
 
 		ret = walk_down_reloc_tree(reloc_root, path, &level);
@@ -1788,6 +1798,7 @@ static void merge_func(struct btrfs_work
 	struct btrfs_root *root;
 	struct btrfs_root *reloc_root;
 	struct async_merge *async;
+	int ret = 0;
 
 	async = container_of(work, struct async_merge, work);
 	reloc_root = async->root;
@@ -1795,18 +1806,20 @@ static void merge_func(struct btrfs_work
 	if (btrfs_root_refs(&reloc_root->root_item) > 0) {
 		root = read_fs_root(reloc_root->fs_info,
 				    reloc_root->root_key.offset);
-		BUG_ON(IS_ERR(root));
+		BTRFS_UERROR(IS_ERR(root));
 		BUG_ON(root->reloc_root != reloc_root);
 
-		merge_reloc_root(async->rc, root);
+		ret = merge_reloc_root(async->rc, root);
+		BTRFS_UERROR(ret);
 
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 		btrfs_update_reloc_root(trans, root);
 		btrfs_end_transaction(trans, root);
 	}
 
-	btrfs_drop_snapshot(reloc_root, 0);
+	ret = btrfs_drop_snapshot(reloc_root, 0);
+	BTRFS_UERROR(ret);
 
 	if (atomic_dec_and_test(async->num_pending))
 		complete(async->done);
@@ -1868,7 +1881,8 @@ static int record_reloc_root_in_trans(st
 		return 0;
 
 	root = read_fs_root(reloc_root->fs_info, reloc_root->root_key.offset);
-	BUG_ON(IS_ERR(root));
+	if (IS_ERR(root))
+		return PTR_ERR(root);
 	BUG_ON(root->reloc_root != reloc_root);
 
 	return btrfs_record_root_in_trans(trans, root);
@@ -1888,6 +1902,7 @@ static struct btrfs_root *__select_one_r
 	struct btrfs_root *root;
 	int index;
 	int loop = 0;
+	int ret;
 again:
 	index = 0;
 	next = node;
@@ -1907,7 +1922,11 @@ again:
 		}
 
 		if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
-			record_reloc_root_in_trans(trans, root);
+			ret = record_reloc_root_in_trans(trans, root);
+			if (ret) {
+				root = ERR_PTR(ret);
+				goto out;
+			}
 			break;
 		}
 
@@ -1946,6 +1965,7 @@ skip:
 	else
 		*nr = 0;
 
+out:
 	return root;
 }
 
@@ -2026,6 +2046,7 @@ static int do_relocation(struct btrfs_tr
 		root = select_reloc_root(trans, upper, edges, &nr);
 		if (!root)
 			continue;
+		BTRFS_UERROR(IS_ERR(root));
 
 		if (upper->eb && !upper->locked)
 			drop_node_buffer(upper);
@@ -2372,6 +2393,11 @@ static int relocate_tree_block(struct bt
 	int ret;
 
 	root = select_one_root(trans, node);
+	if (unlikely(IS_ERR(root))) {
+		ret = PTR_ERR(root);
+		goto out;
+	}
+
 	if (unlikely(!root)) {
 		rc->found_old_snapshot = 1;
 		update_processed_blocks(rc, node);
@@ -3109,6 +3135,7 @@ int add_data_references(struct reloc_con
 			dref = (struct btrfs_extent_data_ref *)(&iref->offset);
 			ret = find_data_references(rc, extent_key,
 						   eb, dref, blocks);
+			BTRFS_UERROR(ret);
 		} else {
 			BUG();
 		}
@@ -3294,12 +3321,18 @@ static noinline_for_stack int relocate_b
 	set_reloc_control(rc);
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
-	BTRFS_UERROR(!trans);
+	BTRFS_UERROR(IS_ERR(trans));
+	if (IS_ERR(trans)) {
+		rc->create_reloc_root = 0;
+		smp_mb();
+		unset_reloc_control(rc);
+		return PTR_ERR(trans);
+	}
 	btrfs_commit_transaction(trans, rc->extent_root);
 
 	while (1) {
 		trans = btrfs_start_transaction(rc->extent_root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 
 		ret = find_next_extent(trans, rc, path);
 		if (ret < 0)
@@ -3356,6 +3389,7 @@ static noinline_for_stack int relocate_b
 		} else if (rc->stage == UPDATE_DATA_PTRS &&
 			 (flags & BTRFS_EXTENT_FLAG_DATA)) {
 			ret = add_data_references(rc, &key, path, &blocks);
+			BTRFS_UERROR(ret);
 		} else {
 			btrfs_release_path(rc->extent_root, path);
 			ret = 0;
@@ -3410,7 +3444,7 @@ static noinline_for_stack int relocate_b
 
 	if (rc->extents_found > 0) {
 		trans = btrfs_start_transaction(rc->extent_root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 		btrfs_commit_transaction(trans, rc->extent_root);
 	}
 
@@ -3420,7 +3454,7 @@ static noinline_for_stack int relocate_b
 
 	/* get rid of pinned extents */
 	trans = btrfs_start_transaction(rc->extent_root, 1);
-	BTRFS_UERROR(!trans);
+	BTRFS_UERROR(IS_ERR(trans));
 	btrfs_commit_transaction(trans, rc->extent_root);
 
 	return err;
@@ -3476,7 +3510,8 @@ static struct inode *create_reloc_inode(
 		return ERR_CAST(root);
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return ERR_CAST(trans);
 
 	err = btrfs_find_free_objectid(trans, root, objectid, &objectid);
 	if (err)
@@ -3531,9 +3566,14 @@ int btrfs_relocate_block_group(struct bt
 			   fs_info->thread_pool_size, NULL);
 
 	rc->extent_root = extent_root;
-	btrfs_prepare_block_group_relocation(extent_root, rc->block_group);
+	ret = btrfs_prepare_block_group_relocation(extent_root,
+						   rc->block_group);
+	if (ret)
+		goto out;
 
 	rc->data_inode = create_reloc_inode(fs_info, rc->block_group);
+	/* We can't clean up from btrfs_prepare_block_group_relocation */
+	BTRFS_UERROR(IS_ERR(rc->data_inode));
 	if (IS_ERR(rc->data_inode)) {
 		err = PTR_ERR(rc->data_inode);
 		rc->data_inode = NULL;
@@ -3553,7 +3593,8 @@ int btrfs_relocate_block_group(struct bt
 
 		mutex_lock(&fs_info->cleaner_mutex);
 
-		btrfs_clean_old_snapshots(fs_info->tree_root);
+		ret = btrfs_clean_old_snapshots(fs_info->tree_root);
+		BTRFS_UERROR(ret);
 		ret = relocate_block_group(rc);
 
 		mutex_unlock(&fs_info->cleaner_mutex);
@@ -3610,7 +3651,8 @@ static noinline_for_stack int mark_garba
 	int ret;
 
 	trans = btrfs_start_transaction(root->fs_info->tree_root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	memset(&root->root_item.drop_progress, 0,
 		sizeof(root->root_item.drop_progress));
@@ -3689,7 +3731,11 @@ int btrfs_recover_relocation(struct btrf
 					err = ret;
 					goto out;
 				}
-				mark_garbage_root(reloc_root);
+				ret = mark_garbage_root(reloc_root);
+				if (ret) {
+					err = ret;
+					goto out;
+				}
 			}
 		}
 
@@ -3738,16 +3784,22 @@ int btrfs_recover_relocation(struct btrf
 	}
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
-	BTRFS_UERROR(!trans);
-	btrfs_commit_transaction(trans, rc->extent_root);
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		unset_reloc_control(rc);
+		goto out;
+	}
+	err = btrfs_commit_transaction(trans, rc->extent_root);
 
 	merge_reloc_roots(rc);
 
 	unset_reloc_control(rc);
 
 	trans = btrfs_start_transaction(rc->extent_root, 1);
-	BTRFS_UERROR(!trans);
-	btrfs_commit_transaction(trans, rc->extent_root);
+	if (IS_ERR(trans)) {
+		err = PTR_ERR(trans);
+		goto out;
+	err = btrfs_commit_transaction(trans, rc->extent_root);
 out:
 	if (rc) {
 		btrfs_stop_workers(&rc->workers);
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -417,8 +417,11 @@ int btrfs_sync_fs(struct super_block *sb
 	btrfs_wait_ordered_extents(root, 0);
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
-	ret = btrfs_commit_transaction(trans, root);
+	if (!IS_ERR(trans))
+		ret = btrfs_commit_transaction(trans, root);
+	else
+		ret = PTR_ERR(trans);
+
 	return ret;
 }
 
@@ -601,7 +604,8 @@ static int btrfs_remount(struct super_bl
 
 		/* recover relocation */
 		ret = btrfs_recover_relocation(root);
-		WARN_ON(ret);
+		if (ret)
+			return ret;
 
 		ret = btrfs_cleanup_fs_roots(root->fs_info);
 		WARN_ON(ret);
@@ -609,7 +613,7 @@ static int btrfs_remount(struct super_bl
 		sb->s_flags &= ~MS_RDONLY;
 	}
 
-	return 0;
+	return ret;
 }
 
 static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -181,7 +181,10 @@ static struct btrfs_trans_handle *start_
 	    ((wait == 1 && !root->fs_info->open_ioctl_trans) || wait == 2))
 		wait_current_trans(root);
 	ret = join_transaction(root);
-	BUG_ON(ret);
+	if (ret) {
+		h = ERR_PTR(ret);
+		goto out;
+	}
 
 	h->transid = root->fs_info->running_transaction->transid;
 	h->transaction = root->fs_info->running_transaction;
@@ -197,6 +200,7 @@ static struct btrfs_trans_handle *start_
 
 	root->fs_info->running_transaction->use_count++;
 	record_root_in_trans(h, root);
+out:
 	mutex_unlock(&root->fs_info->trans_mutex);
 	return h;
 }
@@ -629,8 +633,11 @@ int btrfs_defrag_root(struct btrfs_root
 	smp_mb();
 	if (root->defrag_running)
 		return 0;
+
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
+
 	while (1) {
 		root->defrag_running = 1;
 		ret = btrfs_defrag_leaves(trans, root, cacheonly);
@@ -640,14 +647,16 @@ int btrfs_defrag_root(struct btrfs_root
 		cond_resched();
 
 		trans = btrfs_start_transaction(root, 1);
-		BTRFS_UERROR(!trans);
+		if (IS_ERR(trans))
+			ret = PTR_ERR(trans);
 		if (root->fs_info->closing || ret != -EAGAIN)
 			break;
 	}
 	root->defrag_running = 0;
 	smp_mb();
-	btrfs_end_transaction(trans, root);
-	return 0;
+	if (!IS_ERR(trans))
+		btrfs_end_transaction(trans, root);
+	return ret;
 }
 
 #if 0
@@ -814,7 +823,8 @@ static noinline int finish_pending_snaps
 	parent_inode = pending->dentry->d_parent->d_inode;
 	parent_root = BTRFS_I(parent_inode)->root;
 	trans = btrfs_join_transaction(parent_root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 
 	/*
 	 * insert the directory item
@@ -842,6 +852,7 @@ static noinline int finish_pending_snaps
 	BUG_ON(ret);
 
 	inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
+	BTRFS_UERROR(IS_ERR(inode));
 	d_instantiate(pending->dentry, inode);
 fail:
 	btrfs_end_transaction(trans, fs_info->fs_root);
@@ -876,7 +887,7 @@ static noinline int finish_pending_snaps
 		pending = list_entry(head->next,
 				     struct btrfs_pending_snapshot, list);
 		ret = finish_pending_snapshot(fs_info, pending);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 		list_del(&pending->list);
 		kfree(pending->name);
 		kfree(pending);
@@ -1099,7 +1110,8 @@ int btrfs_commit_transaction(struct btrf
 	btrfs_finish_extent_commit(trans, root);
 
 	/* do the directory inserts of any pending snapshot creations */
-	finish_pending_snapshots(trans, root->fs_info);
+	ret = finish_pending_snapshots(trans, root->fs_info);
+	BTRFS_UERROR(ret);
 
 	mutex_lock(&root->fs_info->trans_mutex);
 
@@ -1128,6 +1140,7 @@ int btrfs_clean_old_snapshots(struct btr
 {
 	LIST_HEAD(list);
 	struct btrfs_fs_info *fs_info = root->fs_info;
+	int ret = 0;
 
 	mutex_lock(&fs_info->trans_mutex);
 	list_splice_init(&fs_info->dead_roots, &list);
@@ -1139,9 +1152,10 @@ int btrfs_clean_old_snapshots(struct btr
 
 		if (btrfs_header_backref_rev(root->node) <
 		    BTRFS_MIXED_BACKREF_REV)
-			btrfs_drop_snapshot(root, 0);
+			ret = btrfs_drop_snapshot(root, 0);
 		else
-			btrfs_drop_snapshot(root, 1);
+			ret = btrfs_drop_snapshot(root, 1);
+		BTRFS_UERROR(ret);
 	}
 	return 0;
 }
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3024,7 +3024,10 @@ int btrfs_recover_log_trees(struct btrfs
 	BUG_ON(!path);
 
 	trans = btrfs_start_transaction(fs_info->tree_root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto fail;
+	}
 
 	wc.trans = trans;
 	wc.pin = 1;
@@ -3053,8 +3056,7 @@ again:
 
 		log = btrfs_read_fs_root_no_radix(log_root_tree,
 						  &found_key);
-		BUG_ON(IS_ERR(log));
-
+		BTRFS_UERROR(IS_ERR(log));
 
 		tmp_key.objectid = found_key.offset;
 		tmp_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -3098,6 +3100,7 @@ again:
 		goto again;
 	}
 
+fail:
 	btrfs_free_path(path);
 
 	free_extent_buffer(log_root_tree->node);
@@ -3105,10 +3108,11 @@ again:
 	fs_info->log_root_recovering = 0;
 
 	/* step 4: commit the transaction, which also unpins the blocks */
-	btrfs_commit_transaction(trans, fs_info->tree_root);
+	if (!ret)
+		ret = btrfs_commit_transaction(trans, fs_info->tree_root);
 
 	kfree(log_root_tree);
-	return 0;
+	return ret;
 }
 
 /*
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1078,7 +1078,7 @@ out:
 static int btrfs_rm_dev_item(struct btrfs_root *root,
 			     struct btrfs_device *device)
 {
-	int ret;
+	int ret, err;
 	struct btrfs_path *path;
 	struct btrfs_key key;
 	struct btrfs_trans_handle *trans;
@@ -1090,7 +1090,10 @@ static int btrfs_rm_dev_item(struct btrf
 		return -ENOMEM;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		btrfs_free_path(path);
+		return PTR_ERR(trans);
+	}
 	key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
 	key.type = BTRFS_DEV_ITEM_KEY;
 	key.offset = device->devid;
@@ -1111,7 +1114,8 @@ static int btrfs_rm_dev_item(struct btrf
 out:
 	btrfs_free_path(path);
 	unlock_chunks(root);
-	btrfs_commit_transaction(trans, root);
+	err = btrfs_commit_transaction(trans, root);
+	ret = ret ?: err;
 	return ret;
 }
 
@@ -1429,7 +1433,7 @@ int btrfs_init_new_device(struct btrfs_r
 	struct super_block *sb = root->fs_info->sb;
 	u64 total_bytes;
 	int seeding_dev = 0;
-	int ret = 0;
+	int err, ret = 0;
 
 	if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding)
 		return -EINVAL;
@@ -1481,7 +1485,12 @@ int btrfs_init_new_device(struct btrfs_r
 	}
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans)) {
+		kfree(device->name);
+		kfree(device);
+		ret = PTR_ERR(trans);
+		goto error;
+	}
 	lock_chunks(root);
 
 	device->barriers = 1;
@@ -1550,14 +1559,15 @@ int btrfs_init_new_device(struct btrfs_r
 	btrfs_clear_space_info_full(root->fs_info);
 
 	unlock_chunks(root);
-	btrfs_commit_transaction(trans, root);
+	err = btrfs_commit_transaction(trans, root);
+	ret = ret ?: err;
 
 	if (seeding_dev) {
 		mutex_unlock(&uuid_mutex);
 		up_write(&sb->s_umount);
 
 		ret = btrfs_relocate_sys_chunks(root);
-		BUG_ON(ret);
+		BTRFS_UERROR(ret);
 	}
 out:
 	mutex_unlock(&root->fs_info->volume_mutex);
@@ -1746,10 +1756,11 @@ static int btrfs_relocate_chunk(struct b
 
 	/* step one, relocate all the extents inside this chunk */
 	ret = btrfs_relocate_block_group(extent_root, chunk_offset);
-	BUG_ON(ret);
+	if (ret)
+		return ret;
 
 	trans = btrfs_start_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	BTRFS_UERROR(IS_ERR(trans));
 
 	lock_chunks(root);
 
@@ -1855,8 +1866,8 @@ again:
 						   found_key.offset);
 			if (ret == -ENOSPC)
 				failed++;
-			else if (ret)
-				BUG();
+			else
+				BTRFS_UERROR(ret);
 		}
 
 		if (found_key.offset == 0)
@@ -1918,10 +1929,11 @@ int btrfs_balance(struct btrfs_root *dev
 		ret = btrfs_shrink_device(device, old_size - size_to_free);
 		if (ret == -ENOSPC)
 			break;
-		BUG_ON(ret);
+		else if (ret)
+			return ret;
 
 		trans = btrfs_start_transaction(dev_root, 1);
-		BTRFS_UERROR(!trans);
+		BTRFS_UERROR(IS_ERR(trans));
 
 		ret = btrfs_grow_device(trans, device, old_size);
 		BUG_ON(ret);
@@ -1971,7 +1983,7 @@ int btrfs_balance(struct btrfs_root *dev
 					   chunk_root->root_key.objectid,
 					   found_key.objectid,
 					   found_key.offset);
-		BUG_ON(ret && ret != -ENOSPC);
+		BTRFS_UERROR(ret && ret != -ENOSPC);
 		key.offset = found_key.offset - 1;
 	}
 	ret = 0;
@@ -2090,8 +2102,8 @@ again:
 
 	/* Shrinking succeeded, else we would be at "done". */
 	trans = btrfs_start_transaction(root, 1);
-	if (!trans) {
-		ret = -ENOMEM;
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
 		goto done;
 	}
 	lock_chunks(root);
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -99,7 +99,8 @@ int __btrfs_setxattr(struct inode *inode
 		return -ENOMEM;
 
 	trans = btrfs_join_transaction(root, 1);
-	BTRFS_UERROR(!trans);
+	if (IS_ERR(trans))
+		return PTR_ERR(trans);
 	btrfs_set_trans_block_group(trans, inode);
 
 	/* first lets see if we already have this xattr */


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 10/10] btrfs: annotate btrfs_alloc_path failures
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (8 preceding siblings ...)
  2009-11-04 19:03 ` [patch 09/10] btrfs: handle btrfs_{start,join}_transaction call path failures Jeff Mahoney
@ 2009-11-04 19:03 ` Jeff Mahoney
  2009-11-04 19:43 ` [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:03 UTC (permalink / raw)
  To: linux-btrfs

This patch adds checks for btrfs_alloc_path failures and annotates them
with BTRFS_UERROR.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

---
 fs/btrfs/ctree.c       |    2 +-
 fs/btrfs/dir-item.c    |    1 +
 fs/btrfs/disk-io.c     |    2 +-
 fs/btrfs/export.c      |    1 +
 fs/btrfs/extent-tree.c |   14 +++++++-------
 fs/btrfs/file-item.c   |    8 +++++---
 fs/btrfs/file.c        |    2 +-
 fs/btrfs/inode-map.c   |    2 +-
 fs/btrfs/inode.c       |   19 ++++++++++---------
 fs/btrfs/root-tree.c   |    8 ++++----
 fs/btrfs/tree-log.c    |   11 ++++++++---
 fs/btrfs/volumes.c     |    4 ++--
 12 files changed, 42 insertions(+), 32 deletions(-)

--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3635,7 +3635,7 @@ int btrfs_insert_item(struct btrfs_trans
 	unsigned long ptr;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
 	if (!ret) {
 		leaf = path->nodes[0];
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -147,6 +147,7 @@ int btrfs_insert_dir_item(struct btrfs_t
 	key.offset = btrfs_name_hash(name, name_len);
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	path->leave_spinning = 1;
 
 	data_size = sizeof(*dir_item) + name_len;
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1123,7 +1123,7 @@ struct btrfs_root *btrfs_read_fs_root_no
 		     root, fs_info, location->objectid);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
 	if (ret == 0) {
 		l = path->nodes[0];
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -176,6 +176,7 @@ static struct dentry *btrfs_get_parent(s
 	int ret;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 
 	if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
 		key.objectid = root->root_key.objectid;
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -583,7 +583,7 @@ int btrfs_lookup_extent(struct btrfs_roo
 	struct btrfs_path *path;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	key.objectid = start;
 	key.offset = len;
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
@@ -4607,7 +4607,7 @@ static int alloc_reserved_file_extent(st
 	size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	path->leave_spinning = 1;
 	ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
@@ -4668,7 +4668,7 @@ static int alloc_reserved_tree_block(str
 	u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	path->leave_spinning = 1;
 	ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
@@ -5388,7 +5388,7 @@ int btrfs_drop_snapshot(struct btrfs_roo
 	int level;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
 	if (!wc) {
@@ -5559,7 +5559,7 @@ int btrfs_drop_subtree(struct btrfs_tran
 	BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	wc = kzalloc(sizeof(*wc), GFP_NOFS);
 	if (!wc) {
@@ -6021,7 +6021,7 @@ static noinline int get_new_locations(st
 	}
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	cur_pos = extent_key->objectid - offset;
 	last_byte = extent_key->objectid + extent_key->offset;
@@ -7578,7 +7578,7 @@ int btrfs_remove_block_group(struct btrf
 	spin_unlock(&cluster->refill_lock);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	spin_lock(&root->fs_info->block_group_cache_lock);
 	rb_erase(&block_group->cache_node,
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -47,7 +47,7 @@ int btrfs_insert_file_extent(struct btrf
 	struct extent_buffer *leaf;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	file_key.objectid = objectid;
 	file_key.offset = pos;
 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
@@ -167,6 +167,7 @@ int btrfs_lookup_bio_sums(struct btrfs_r
 	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	if (bio->bi_size > PAGE_CACHE_SIZE * 8)
 		path->reada = 2;
 
@@ -260,7 +261,7 @@ int btrfs_lookup_csums_range(struct btrf
 	u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
 	key.offset = start;
@@ -518,6 +519,7 @@ int btrfs_del_csums(struct btrfs_trans_h
 	root = root->fs_info->csum_root;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 
 	while (1) {
 		key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
@@ -639,7 +641,7 @@ int btrfs_csum_file_blocks(struct btrfs_
 		btrfs_super_csum_size(&root->fs_info->super_copy);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	sector_sum = sums->sums;
 again:
 	next_offset = (u64)-1;
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -642,7 +642,7 @@ int btrfs_mark_extent_written(struct btr
 	btrfs_drop_extent_cache(inode, start, end - 1, 0);
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 again:
 	key.objectid = inode->i_ino;
 	key.type = BTRFS_EXTENT_DATA_KEY;
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -30,7 +30,7 @@ int btrfs_find_highest_inode(struct btrf
 	int slot;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	search_key.objectid = BTRFS_LAST_FREE_OBJECTID;
 	search_key.type = -1;
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -997,7 +997,7 @@ static noinline int run_delalloc_nocow(s
 	int check_prev = 1;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	trans = btrfs_join_transaction(root, 1);
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
@@ -1597,7 +1597,7 @@ static int insert_reserved_file_extent(s
 	int ret;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	path->leave_spinning = 1;
 
@@ -2236,7 +2236,7 @@ static void btrfs_read_locked_inode(stru
 	int ret;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
 
 	ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
@@ -2374,7 +2374,7 @@ noinline int btrfs_update_inode(struct b
 	int ret;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	path->leave_spinning = 1;
 	ret = btrfs_lookup_inode(trans, root, path,
 				 &BTRFS_I(inode)->location, 1);
@@ -2834,7 +2834,7 @@ noinline int btrfs_truncate_inode_items(
 	if (root->ref_cows)
 		btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	path->reada = -1;
 
 	/* FIXME, add redo link to tree so we don't leak on crash */
@@ -3313,7 +3313,7 @@ static int btrfs_inode_by_name(struct in
 	int ret = 0;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
 				    namelen, 0);
@@ -3756,6 +3756,7 @@ static int btrfs_real_readdir(struct fil
 		filp->f_pos = 2;
 	}
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	path->reada = 2;
 
 	btrfs_set_key_type(&key, key_type);
@@ -3992,7 +3993,7 @@ static struct inode *btrfs_new_inode(str
 	int owner;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	inode = new_inode(root->fs_info->sb);
 	if (!inode)
@@ -4572,7 +4573,7 @@ again:
 
 	if (!path) {
 		path = btrfs_alloc_path();
-		BUG_ON(!path);
+		BTRFS_UERROR(!path);
 	}
 
 	ret = btrfs_lookup_file_extent(trans, root, path,
@@ -5586,7 +5587,7 @@ static int btrfs_symlink(struct inode *d
 		goto out_unlock;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	key.objectid = inode->i_ino;
 	key.offset = 0;
 	btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -40,7 +40,7 @@ int btrfs_search_root(struct btrfs_root
 	search_key.offset = (u64)-1;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 again:
 	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
 	if (ret < 0)
@@ -88,7 +88,7 @@ int btrfs_find_last_root(struct btrfs_ro
 	search_key.offset = (u64)-1;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
 	if (ret < 0)
 		goto out;
@@ -140,7 +140,7 @@ int btrfs_update_root(struct btrfs_trans
 	unsigned long ptr;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
 	if (ret < 0)
 		goto out;
@@ -319,7 +319,7 @@ int btrfs_del_root(struct btrfs_trans_ha
 	struct extent_buffer *leaf;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
 	if (ret < 0)
 		goto out;
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -744,6 +744,7 @@ static noinline int backref_in_log(struc
 	int match = 0;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	ret = btrfs_search_slot(NULL, log, key, path, 0, 0);
 	if (ret != 0)
 		goto out;
@@ -961,6 +962,7 @@ static noinline int fixup_inode_link_cou
 	key.offset = (u64)-1;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 
 	while (1) {
 		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -1585,7 +1587,7 @@ static int replay_one_buffer(struct btrf
 		return 0;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	nritems = btrfs_header_nritems(eb);
 	for (i = 0; i < nritems; i++) {
@@ -1848,7 +1850,7 @@ static int walk_log_tree(struct btrfs_tr
 	int orig_level;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	level = btrfs_header_level(log->node);
 	orig_level = level;
@@ -2217,6 +2219,7 @@ int btrfs_del_dir_entries_in_log(struct
 
 	log = root->log_root;
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
 				   name, name_len, -1);
 	if (di && !IS_ERR(di)) {
@@ -2708,7 +2711,9 @@ static int btrfs_log_inode(struct btrfs_
 	log = root->log_root;
 
 	path = btrfs_alloc_path();
+	BTRFS_UERROR(!path);
 	dst_path = btrfs_alloc_path();
+	BTRFS_UERROR(!dst_path);
 
 	min_key.objectid = inode->i_ino;
 	min_key.type = BTRFS_INODE_ITEM_KEY;
@@ -3021,7 +3026,7 @@ int btrfs_recover_log_trees(struct btrfs
 
 	fs_info->log_root_recovering = 1;
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	trans = btrfs_start_transaction(fs_info->tree_root, 1);
 	if (IS_ERR(trans)) {
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -946,7 +946,7 @@ static noinline int find_next_chunk(stru
 	struct btrfs_key found_key;
 
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	key.objectid = objectid;
 	key.offset = (u64)-1;
@@ -1943,7 +1943,7 @@ int btrfs_balance(struct btrfs_root *dev
 
 	/* step two, relocate all the chunks */
 	path = btrfs_alloc_path();
-	BUG_ON(!path);
+	BTRFS_UERROR(!path);
 
 	key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
 	key.offset = (u64)-1;


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 00/10] btrfs: Error handling/propagation queue
  2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
                   ` (9 preceding siblings ...)
  2009-11-04 19:03 ` [patch 10/10] btrfs: annotate btrfs_alloc_path failures Jeff Mahoney
@ 2009-11-04 19:43 ` Jeff Mahoney
  10 siblings, 0 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-11-04 19:43 UTC (permalink / raw)
  To: linux-btrfs

On 11/04/2009 02:03 PM, Jeff Mahoney wrote:
>  This patch series fixes a few existing problems and then addresses
>  the need for better error handling and propagation in btrfs.
> 
>  The handling and propagation patch set first finds all locations of
>  a particular condition not being checked and annotates them with
>  BTRFS_UERROR to designate that there is an error condition that
>  is currently unhandled but should be. Then, another patch traverses
>  the call path to ensure that errors are properly propogated. When the
>  fix for recovering or passing the error is obvious, we do that too.
> 
>  This set is not complete and I expect there to be more fixes coming. In
>  particular, it currently only annotates btrfs_alloc_path failures as
>  the call graph for it is quite large. This is in response to Chris asking
>  for what I already have instead of waiting for it to be complete.

I should be clear that this is just what I've been working on so far and
hasn't received any testing yet. It was a quick quilt mail in the middle
of working on it. (As you might notice by the fact that it doesn't build.)

-Jeff

-- 
Jeff Mahoney
SUSE Labs

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-11-04 19:43 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-04 19:03 [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney
2009-11-04 19:03 ` [patch 01/10] btrfs: fix btrfs_read_block_groups return value Jeff Mahoney
2009-11-04 19:03 ` [patch 02/10] btrfs: fix memleak in btrfs_init_new_device Jeff Mahoney
2009-11-04 19:03 ` [patch 03/10] btrfs: fix btrfs_read_fs_root* return values Jeff Mahoney
2009-11-04 19:03 ` [patch 04/10] btrfs: btrfs_sync_file should return -EIO not EIO Jeff Mahoney
2009-11-04 19:03 ` [patch 05/10] btrfs: Add BTRFS_UERROR for unhandled errors Jeff Mahoney
2009-11-04 19:03 ` [patch 06/10] btrfs: annotate kmalloc failures Jeff Mahoney
2009-11-04 19:03 ` [patch 07/10] btrfs: handle kmalloc call path failures Jeff Mahoney
2009-11-04 19:03 ` [patch 08/10] btrfs: annotate btrfs_{start,join}_transaction failures Jeff Mahoney
2009-11-04 19:03 ` [patch 09/10] btrfs: handle btrfs_{start,join}_transaction call path failures Jeff Mahoney
2009-11-04 19:03 ` [patch 10/10] btrfs: annotate btrfs_alloc_path failures Jeff Mahoney
2009-11-04 19:43 ` [patch 00/10] btrfs: Error handling/propagation queue Jeff Mahoney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox