Merge branch 'alloc_path' of git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh...
[linux-2.6.git] / fs / btrfs / tree-log.c
index f51bf13..babee65 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include "ctree.h"
 #include "transaction.h"
 #include "disk-io.h"
@@ -134,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root)
 {
        int ret;
+       int err = 0;
 
        mutex_lock(&root->log_mutex);
        if (root->log_root) {
@@ -154,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
        mutex_lock(&root->fs_info->tree_log_mutex);
        if (!root->fs_info->log_root_tree) {
                ret = btrfs_init_log_root_tree(trans, root->fs_info);
-               BUG_ON(ret);
+               if (ret)
+                       err = ret;
        }
-       if (!root->log_root) {
+       if (err == 0 && !root->log_root) {
                ret = btrfs_add_log_tree(trans, root);
-               BUG_ON(ret);
+               if (ret)
+                       err = ret;
        }
        mutex_unlock(&root->fs_info->tree_log_mutex);
        root->log_batch++;
        atomic_inc(&root->log_writers);
        mutex_unlock(&root->log_mutex);
-       return 0;
+       return err;
 }
 
 /*
@@ -329,11 +333,17 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                        goto insert;
 
                if (item_size == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return 0;
                }
                dst_copy = kmalloc(item_size, GFP_NOFS);
                src_copy = kmalloc(item_size, GFP_NOFS);
+               if (!dst_copy || !src_copy) {
+                       btrfs_release_path(path);
+                       kfree(dst_copy);
+                       kfree(src_copy);
+                       return -ENOMEM;
+               }
 
                read_extent_buffer(eb, src_copy, src_ptr, item_size);
 
@@ -351,13 +361,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                 * sync
                 */
                if (ret == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return 0;
                }
 
        }
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        /* try to insert the key into the destination tree */
        ret = btrfs_insert_empty_item(trans, root, path,
                                      key, item_size);
@@ -372,10 +382,9 @@ insert:
                } else if (found_size < item_size) {
                        ret = btrfs_extend_item(trans, root, path,
                                                item_size - found_size);
-                       BUG_ON(ret);
                }
        } else if (ret) {
-               BUG();
+               return ret;
        }
        dst_ptr = btrfs_item_ptr_offset(path->nodes[0],
                                        path->slots[0]);
@@ -428,7 +437,7 @@ insert:
        }
 no_copy:
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return 0;
 }
 
@@ -445,7 +454,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
        key.objectid = objectid;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       inode = btrfs_iget(root->fs_info->sb, &key, root);
+       inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
        if (IS_ERR(inode)) {
                inode = NULL;
        } else if (is_bad_inode(inode)) {
@@ -509,7 +518,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
         * file.  This must be done before the btrfs_drop_extents run
         * so we don't try to drop this extent.
         */
-       ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
+       ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
                                       start, 0);
 
        if (ret == 0 &&
@@ -534,16 +543,16 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                 * we don't have to do anything
                 */
                if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        goto out;
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        saved_nbytes = inode_get_bytes(inode);
        /* drop any overlapping extents */
-       ret = btrfs_drop_extents(trans, root, inode,
-                        start, extent_end, extent_end, start, &alloc_hint, 1);
+       ret = btrfs_drop_extents(trans, inode, start, extent_end,
+                                &alloc_hint, 1);
        BUG_ON(ret);
 
        if (found_type == BTRFS_FILE_EXTENT_REG ||
@@ -580,6 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                                ins.objectid, ins.offset,
                                                0, root->root_key.objectid,
                                                key->objectid, offset);
+                               BUG_ON(ret);
                        } else {
                                /*
                                 * insert the extent pointer in the extent
@@ -590,7 +600,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                                key->objectid, offset, &ins);
                                BUG_ON(ret);
                        }
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
 
                        if (btrfs_file_extent_compression(eb, item)) {
                                csum_start = ins.objectid;
@@ -604,7 +614,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
 
                        ret = btrfs_lookup_csums_range(root->log_root,
                                                csum_start, csum_end - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                        BUG_ON(ret);
                        while (!list_empty(&ordered_sums)) {
                                struct btrfs_ordered_sum *sums;
@@ -619,7 +629,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                kfree(sums);
                        }
                } else {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                }
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                /* inline extents are easy, we just overwrite them */
@@ -661,11 +671,17 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        btrfs_dir_item_key_to_cpu(leaf, di, &location);
        name_len = btrfs_dir_name_len(leaf, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        inode = read_one_inode(root, location.objectid);
-       BUG_ON(!inode);
+       if (!inode) {
+               kfree(name);
+               return -EIO;
+       }
 
        ret = link_to_fixup_dir(trans, root, path, location.objectid);
        BUG_ON(ret);
@@ -700,7 +716,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
                        goto out;
        } else
                goto out;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
        if (di && !IS_ERR(di)) {
@@ -711,7 +727,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
                goto out;
        match = 1;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return match;
 }
 
@@ -740,6 +756,9 @@ static noinline int backref_in_log(struct btrfs_root *log,
        int match = 0;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        ret = btrfs_search_slot(NULL, log, key, path, 0, 0);
        if (ret != 0)
                goto out;
@@ -782,18 +801,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
 {
        struct inode *dir;
        int ret;
-       struct btrfs_key location;
        struct btrfs_inode_ref *ref;
-       struct btrfs_dir_item *di;
        struct inode *inode;
        char *name;
        int namelen;
        unsigned long ref_ptr;
        unsigned long ref_end;
-
-       location.objectid = key->objectid;
-       location.type = BTRFS_INODE_ITEM_KEY;
-       location.offset = 0;
+       int search_done = 0;
 
        /*
         * it is possible that we didn't log all the parent directories
@@ -806,7 +820,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                return -ENOENT;
 
        inode = read_one_inode(root, key->objectid);
-       BUG_ON(!inode);
+       if (!inode) {
+               iput(dir);
+               return -EIO;
+       }
 
        ref_ptr = btrfs_item_ptr_offset(eb, slot);
        ref_end = ref_ptr + btrfs_item_size_nr(eb, slot);
@@ -821,7 +838,7 @@ again:
        read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen);
 
        /* if we already have a perfect match, we're done */
-       if (inode_in_dir(root, path, dir->i_ino, inode->i_ino,
+       if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
                         btrfs_inode_ref_index(eb, ref),
                         name, namelen)) {
                goto out;
@@ -834,7 +851,10 @@ again:
         * existing back reference, and we don't want to create
         * dangling pointers in the directory.
         */
-conflict_again:
+
+       if (search_done)
+               goto insert;
+
        ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
        if (ret == 0) {
                char *victim_name;
@@ -870,42 +890,26 @@ conflict_again:
                        if (!backref_in_log(log, key, victim_name,
                                            victim_name_len)) {
                                btrfs_inc_nlink(inode);
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
 
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
                                                         victim_name_len);
-                               kfree(victim_name);
-                               btrfs_release_path(root, path);
-                               goto conflict_again;
                        }
                        kfree(victim_name);
                        ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
                }
                BUG_ON(ret);
-       }
-       btrfs_release_path(root, path);
-
-       /* look for a conflicting sequence number */
-       di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
-                                        btrfs_inode_ref_index(eb, ref),
-                                        name, namelen, 0);
-       if (di && !IS_ERR(di)) {
-               ret = drop_one_dir_item(trans, root, path, dir, di);
-               BUG_ON(ret);
-       }
-       btrfs_release_path(root, path);
 
-
-       /* look for a conflicting name */
-       di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
-                                  name, namelen, 0);
-       if (di && !IS_ERR(di)) {
-               ret = drop_one_dir_item(trans, root, path, dir, di);
-               BUG_ON(ret);
+               /*
+                * NOTE: we have searched root tree and checked the
+                * coresponding ref, it does not need to check again.
+                */
+               search_done = 1;
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
+insert:
        /* insert our name */
        ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
                             btrfs_inode_ref_index(eb, ref));
@@ -924,12 +928,23 @@ out:
        BUG_ON(ret);
 
 out_nowrite:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        iput(dir);
        iput(inode);
        return 0;
 }
 
+static int insert_orphan_item(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root, u64 offset)
+{
+       int ret;
+       ret = btrfs_find_orphan_item(root, offset);
+       if (ret > 0)
+               ret = btrfs_insert_orphan_item(trans, root, offset);
+       return ret;
+}
+
+
 /*
  * There are a few corners where the link count of the file can't
  * be properly maintained during replay.  So, instead of adding
@@ -951,12 +966,15 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        unsigned long ptr;
        unsigned long ptr_end;
        int name_len;
+       u64 ino = btrfs_ino(inode);
 
-       key.objectid = inode->i_ino;
+       key.objectid = ino;
        key.type = BTRFS_INODE_REF_KEY;
        key.offset = (u64)-1;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
 
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -969,7 +987,7 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                }
                btrfs_item_key_to_cpu(path->nodes[0], &key,
                                      path->slots[0]);
-               if (key.objectid != inode->i_ino ||
+               if (key.objectid != ino ||
                    key.type != BTRFS_INODE_REF_KEY)
                        break;
                ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
@@ -988,18 +1006,22 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
                if (key.offset == 0)
                        break;
                key.offset--;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        if (nlink != inode->i_nlink) {
                inode->i_nlink = nlink;
                btrfs_update_inode(trans, root, inode);
        }
        BTRFS_I(inode)->index_cnt = (u64)-1;
 
-       if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
-               ret = replay_dir_deletes(trans, root, NULL, path,
-                                        inode->i_ino, 1);
+       if (inode->i_nlink == 0) {
+               if (S_ISDIR(inode->i_mode)) {
+                       ret = replay_dir_deletes(trans, root, NULL, path,
+                                                ino, 1);
+                       BUG_ON(ret);
+               }
+               ret = insert_orphan_item(trans, root, ino);
                BUG_ON(ret);
        }
        btrfs_free_path(path);
@@ -1035,11 +1057,13 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
                        break;
 
                ret = btrfs_del_item(trans, root, path);
-               BUG_ON(ret);
+               if (ret)
+                       goto out;
 
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                inode = read_one_inode(root, key.offset);
-               BUG_ON(!inode);
+               if (!inode)
+                       return -EIO;
 
                ret = fixup_inode_link_count(trans, root, inode);
                BUG_ON(ret);
@@ -1053,8 +1077,10 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
                 */
                key.offset = (u64)-1;
        }
-       btrfs_release_path(root, path);
-       return 0;
+       ret = 0;
+out:
+       btrfs_release_path(path);
+       return ret;
 }
 
 
@@ -1073,7 +1099,8 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
        struct inode *inode;
 
        inode = read_one_inode(root, objectid);
-       BUG_ON(!inode);
+       if (!inode)
+               return -EIO;
 
        key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
        btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
@@ -1081,7 +1108,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
 
        ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
 
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        if (ret == 0) {
                btrfs_inc_nlink(inode);
                btrfs_update_inode(trans, root, inode);
@@ -1160,10 +1187,14 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        int ret;
 
        dir = read_one_inode(root, key->objectid);
-       BUG_ON(!dir);
+       if (!dir)
+               return -EIO;
 
        name_len = btrfs_dir_name_len(eb, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        log_type = btrfs_dir_type(eb, di);
        read_extent_buffer(eb, name, (unsigned long)(di + 1),
                   name_len);
@@ -1174,7 +1205,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
                exists = 1;
        else
                exists = 0;
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        if (key->type == BTRFS_DIR_ITEM_KEY) {
                dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
@@ -1187,7 +1218,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        } else {
                BUG();
        }
-       if (!dst_di || IS_ERR(dst_di)) {
+       if (IS_ERR_OR_NULL(dst_di)) {
                /* we need a sequence number to insert, so we only
                 * do inserts for the BTRFS_DIR_INDEX_KEY types
                 */
@@ -1218,13 +1249,13 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
        if (key->type == BTRFS_DIR_INDEX_KEY)
                goto insert;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        kfree(name);
        iput(dir);
        return 0;
 
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        ret = insert_one_name(trans, root, path, key->objectid, key->offset,
                              name, name_len, log_type, &log_key);
 
@@ -1255,6 +1286,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
        ptr_end = ptr + item_size;
        while (ptr < ptr_end) {
                di = (struct btrfs_dir_item *)ptr;
+               if (verify_dir_item(root, eb, di))
+                       return -EIO;
                name_len = btrfs_dir_name_len(eb, di);
                ret = replay_one_name(trans, root, path, eb, di, key);
                BUG_ON(ret);
@@ -1343,7 +1376,7 @@ next:
        *end_ret = found_end;
        ret = 0;
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        return ret;
 }
 
@@ -1381,6 +1414,11 @@ again:
        ptr_end = ptr + item_size;
        while (ptr < ptr_end) {
                di = (struct btrfs_dir_item *)ptr;
+               if (verify_dir_item(root, eb, di)) {
+                       ret = -EIO;
+                       goto out;
+               }
+
                name_len = btrfs_dir_name_len(eb, di);
                name = kmalloc(name_len, GFP_NOFS);
                if (!name) {
@@ -1401,12 +1439,15 @@ again:
                                                     dir_key->offset,
                                                     name, name_len, 0);
                }
-               if (!log_di || IS_ERR(log_di)) {
+               if (IS_ERR_OR_NULL(log_di)) {
                        btrfs_dir_item_key_to_cpu(eb, di, &location);
-                       btrfs_release_path(root, path);
-                       btrfs_release_path(log, log_path);
+                       btrfs_release_path(path);
+                       btrfs_release_path(log_path);
                        inode = read_one_inode(root, location.objectid);
-                       BUG_ON(!inode);
+                       if (!inode) {
+                               kfree(name);
+                               return -EIO;
+                       }
 
                        ret = link_to_fixup_dir(trans, root,
                                                path, location.objectid);
@@ -1428,7 +1469,7 @@ again:
                        ret = 0;
                        goto out;
                }
-               btrfs_release_path(log, log_path);
+               btrfs_release_path(log_path);
                kfree(name);
 
                ptr = (unsigned long)(di + 1);
@@ -1436,8 +1477,8 @@ again:
        }
        ret = 0;
 out:
-       btrfs_release_path(root, path);
-       btrfs_release_path(log, log_path);
+       btrfs_release_path(path);
+       btrfs_release_path(log_path);
        return ret;
 }
 
@@ -1525,7 +1566,7 @@ again:
                                break;
                        dir_key.offset = found_key.offset + 1;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                if (range_end == (u64)-1)
                        break;
                range_start = range_end + 1;
@@ -1536,11 +1577,11 @@ next_type:
        if (key_type == BTRFS_DIR_LOG_ITEM_KEY) {
                key_type = BTRFS_DIR_LOG_INDEX_KEY;
                dir_key.type = BTRFS_DIR_INDEX_KEY;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                goto again;
        }
 out:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        btrfs_free_path(log_path);
        iput(dir);
        return ret;
@@ -1564,7 +1605,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
        struct btrfs_path *path;
        struct btrfs_root *root = wc->replay_dest;
        struct btrfs_key key;
-       u32 item_size;
        int level;
        int i;
        int ret;
@@ -1577,17 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                return 0;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        nritems = btrfs_header_nritems(eb);
        for (i = 0; i < nritems; i++) {
                btrfs_item_key_to_cpu(eb, &key, i);
-               item_size = btrfs_item_size_nr(eb, i);
 
                /* inode keys are done during the first stage */
                if (key.type == BTRFS_INODE_ITEM_KEY &&
                    wc->stage == LOG_WALK_REPLAY_INODES) {
-                       struct inode *inode;
                        struct btrfs_inode_item *inode_item;
                        u32 mode;
 
@@ -1603,31 +1642,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
                                             eb, i, &key);
                        BUG_ON(ret);
 
-                       /* for regular files, truncate away
-                        * extents past the new EOF
+                       /* for regular files, make sure corresponding
+                        * orhpan item exist. extents past the new EOF
+                        * will be truncated later by orphan cleanup.
                         */
                        if (S_ISREG(mode)) {
-                               inode = read_one_inode(root,
-                                                      key.objectid);
-                               BUG_ON(!inode);
-
-                               ret = btrfs_truncate_inode_items(wc->trans,
-                                       root, inode, inode->i_size,
-                                       BTRFS_EXTENT_DATA_KEY);
+                               ret = insert_orphan_item(wc->trans, root,
+                                                        key.objectid);
                                BUG_ON(ret);
-
-                               /* if the nlink count is zero here, the iput
-                                * will free the inode.  We bump it to make
-                                * sure it doesn't get freed until the link
-                                * count fixup is done
-                                */
-                               if (inode->i_nlink == 0) {
-                                       btrfs_inc_nlink(inode);
-                                       btrfs_update_inode(wc->trans,
-                                                          root, inode);
-                               }
-                               iput(inode);
                        }
+
                        ret = link_to_fixup_dir(wc->trans, root,
                                                path, key.objectid);
                        BUG_ON(ret);
@@ -1665,7 +1689,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                   struct walk_control *wc)
 {
        u64 root_owner;
-       u64 root_gen;
        u64 bytenr;
        u64 ptr_gen;
        struct extent_buffer *next;
@@ -1695,20 +1718,23 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
 
                parent = path->nodes[*level];
                root_owner = btrfs_header_owner(parent);
-               root_gen = btrfs_header_generation(parent);
 
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
-
-               wc->process_func(root, next, wc, ptr_gen);
+               if (!next)
+                       return -ENOMEM;
 
                if (*level == 1) {
+                       ret = wc->process_func(root, next, wc, ptr_gen);
+                       if (ret)
+                               return ret;
+
                        path->slots[*level]++;
                        if (wc->free) {
                                btrfs_read_buffer(next, ptr_gen);
 
                                btrfs_tree_lock(next);
-                               clean_tree_block(trans, root, next);
                                btrfs_set_lock_blocking(next);
+                               clean_tree_block(trans, root, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
@@ -1734,35 +1760,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
 
-       if (path->nodes[*level] == root->node)
-               parent = path->nodes[*level];
-       else
-               parent = path->nodes[*level + 1];
-
-       bytenr = path->nodes[*level]->start;
-
-       blocksize = btrfs_level_size(root, *level);
-       root_owner = btrfs_header_owner(parent);
-       root_gen = btrfs_header_generation(parent);
-
-       wc->process_func(root, path->nodes[*level], wc,
-                        btrfs_header_generation(path->nodes[*level]));
-
-       if (wc->free) {
-               next = path->nodes[*level];
-               btrfs_tree_lock(next);
-               clean_tree_block(trans, root, next);
-               btrfs_set_lock_blocking(next);
-               btrfs_wait_tree_block_writeback(next);
-               btrfs_tree_unlock(next);
-
-               WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
-               ret = btrfs_free_reserved_extent(root, bytenr, blocksize);
-               BUG_ON(ret);
-       }
-       free_extent_buffer(path->nodes[*level]);
-       path->nodes[*level] = NULL;
-       *level += 1;
+       path->slots[*level] = btrfs_header_nritems(path->nodes[*level]);
 
        cond_resched();
        return 0;
@@ -1774,16 +1772,13 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                 struct walk_control *wc)
 {
        u64 root_owner;
-       u64 root_gen;
        int i;
        int slot;
        int ret;
 
        for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
                slot = path->slots[i];
-               if (slot < btrfs_header_nritems(path->nodes[i]) - 1) {
-                       struct extent_buffer *node;
-                       node = path->nodes[i];
+               if (slot + 1 < btrfs_header_nritems(path->nodes[i])) {
                        path->slots[i]++;
                        *level = i;
                        WARN_ON(*level == 0);
@@ -1796,17 +1791,19 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                parent = path->nodes[*level + 1];
 
                        root_owner = btrfs_header_owner(parent);
-                       root_gen = btrfs_header_generation(parent);
-                       wc->process_func(root, path->nodes[*level], wc,
+                       ret = wc->process_func(root, path->nodes[*level], wc,
                                 btrfs_header_generation(path->nodes[*level]));
+                       if (ret)
+                               return ret;
+
                        if (wc->free) {
                                struct extent_buffer *next;
 
                                next = path->nodes[*level];
 
                                btrfs_tree_lock(next);
-                               clean_tree_block(trans, root, next);
                                btrfs_set_lock_blocking(next);
+                               clean_tree_block(trans, root, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
@@ -1840,7 +1837,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
        int orig_level;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
 
        level = btrfs_header_level(log->node);
        orig_level = level;
@@ -1872,8 +1870,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                        next = path->nodes[orig_level];
 
                        btrfs_tree_lock(next);
-                       clean_tree_block(trans, log, next);
                        btrfs_set_lock_blocking(next);
+                       clean_tree_block(trans, log, next);
                        btrfs_wait_tree_block_writeback(next);
                        btrfs_tree_unlock(next);
 
@@ -1977,10 +1975,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 {
        int index1;
        int index2;
+       int mark;
        int ret;
        struct btrfs_root *log = root->log_root;
        struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
-       u64 log_transid = 0;
+       unsigned long log_transid = 0;
 
        mutex_lock(&root->log_mutex);
        index1 = root->log_transid % 2;
@@ -2014,24 +2013,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                goto out;
        }
 
+       log_transid = root->log_transid;
+       if (log_transid % 2 == 0)
+               mark = EXTENT_DIRTY;
+       else
+               mark = EXTENT_NEW;
+
        /* we start IO on  all the marked extents here, but we don't actually
         * wait for them until later.
         */
-       ret = btrfs_write_marked_extents(log, &log->dirty_log_pages);
+       ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
        BUG_ON(ret);
 
        btrfs_set_root_node(&log->root_item, log->node);
 
        root->log_batch = 0;
-       log_transid = root->log_transid;
        root->log_transid++;
        log->log_transid = root->log_transid;
        root->log_start_pid = 0;
        smp_mb();
        /*
-        * log tree has been flushed to disk, new modifications of
-        * the log will be written to new positions. so it's safe to
-        * allow log writers to go in.
+        * IO has been started, blocks of the log tree have WRITTEN flag set
+        * in their headers. new modifications of the log will be written to
+        * new positions. so it's safe to allow log writers to go in.
         */
        mutex_unlock(&root->log_mutex);
 
@@ -2041,7 +2045,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        mutex_unlock(&log_root_tree->log_mutex);
 
        ret = update_log_root(trans, log);
-       BUG_ON(ret);
 
        mutex_lock(&log_root_tree->log_mutex);
        if (atomic_dec_and_test(&log_root_tree->log_writers)) {
@@ -2050,12 +2053,22 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                        wake_up(&log_root_tree->log_writer_wait);
        }
 
+       if (ret) {
+               BUG_ON(ret != -ENOSPC);
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
+               mutex_unlock(&log_root_tree->log_mutex);
+               ret = -EAGAIN;
+               goto out;
+       }
+
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
-               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
                wait_log_commit(trans, log_root_tree,
                                log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
+               ret = 0;
                goto out;
        }
        atomic_set(&log_root_tree->log_commit[index2], 1);
@@ -2072,16 +2085,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * check the full commit flag again
         */
        if (root->fs_info->last_trans_log_full_commit == trans->transid) {
-               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
                mutex_unlock(&log_root_tree->log_mutex);
                ret = -EAGAIN;
                goto out_wake_log_root;
        }
 
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
-                               &log_root_tree->dirty_log_pages);
+                               &log_root_tree->dirty_log_pages,
+                               EXTENT_DIRTY | EXTENT_NEW);
        BUG_ON(ret);
-       btrfs_wait_marked_extents(log, &log->dirty_log_pages);
+       btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 
        btrfs_set_super_log_root(&root->fs_info->super_for_commit,
                                log_root_tree->node->start);
@@ -2101,7 +2115,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * the running transaction open, so a full commit can't hop
         * in and cause problems either.
         */
+       btrfs_scrub_pause_super(root);
        write_ctree_super(trans, root->fs_info->tree_root, 1);
+       btrfs_scrub_continue_super(root);
        ret = 0;
 
        mutex_lock(&root->log_mutex);
@@ -2119,18 +2135,13 @@ out:
        smp_mb();
        if (waitqueue_active(&root->log_commit_wait[index1]))
                wake_up(&root->log_commit_wait[index1]);
-       return 0;
+       return ret;
 }
 
-/*
- * free all the extents used by the tree log.  This should be called
- * at commit time of the full transaction
- */
-int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
+static void free_log_tree(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *log)
 {
        int ret;
-       struct btrfs_root *log;
-       struct key;
        u64 start;
        u64 end;
        struct walk_control wc = {
@@ -2138,31 +2149,43 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
                .process_func = process_one_buffer
        };
 
-       if (!root->log_root || root->fs_info->log_root_recovering)
-               return 0;
-
-       log = root->log_root;
        ret = walk_log_tree(trans, log, &wc);
        BUG_ON(ret);
 
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
-                                   0, &start, &end, EXTENT_DIRTY);
+                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
                if (ret)
                        break;
 
-               clear_extent_dirty(&log->dirty_log_pages,
-                                  start, end, GFP_NOFS);
+               clear_extent_bits(&log->dirty_log_pages, start, end,
+                                 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
        }
 
-       if (log->log_transid > 0) {
-               ret = btrfs_del_root(trans, root->fs_info->log_root_tree,
-                                    &log->root_key);
-               BUG_ON(ret);
-       }
-       root->log_root = NULL;
        free_extent_buffer(log->node);
        kfree(log);
+}
+
+/*
+ * free all the extents used by the tree log.  This should be called
+ * at commit time of the full transaction
+ */
+int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
+{
+       if (root->log_root) {
+               free_log_tree(trans, root->log_root);
+               root->log_root = NULL;
+       }
+       return 0;
+}
+
+int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
+                            struct btrfs_fs_info *fs_info)
+{
+       if (fs_info->log_root_tree) {
+               free_log_tree(trans, fs_info->log_root_tree);
+               fs_info->log_root_tree = NULL;
+       }
        return 0;
 }
 
@@ -2196,7 +2219,9 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        struct btrfs_dir_item *di;
        struct btrfs_path *path;
        int ret;
+       int err = 0;
        int bytes_del = 0;
+       u64 dir_ino = btrfs_ino(dir);
 
        if (BTRFS_I(dir)->logged_trans < trans->transid)
                return 0;
@@ -2209,17 +2234,30 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        log = root->log_root;
        path = btrfs_alloc_path();
-       di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
+       if (!path) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       di = btrfs_lookup_dir_item(trans, log, path, dir_ino,
                                   name, name_len, -1);
-       if (di && !IS_ERR(di)) {
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto fail;
+       }
+       if (di) {
                ret = btrfs_delete_one_dir_name(trans, log, path, di);
                bytes_del += name_len;
                BUG_ON(ret);
        }
-       btrfs_release_path(log, path);
-       di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino,
+       btrfs_release_path(path);
+       di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino,
                                         index, name, name_len, -1);
-       if (di && !IS_ERR(di)) {
+       if (IS_ERR(di)) {
+               err = PTR_ERR(di);
+               goto fail;
+       }
+       if (di) {
                ret = btrfs_delete_one_dir_name(trans, log, path, di);
                bytes_del += name_len;
                BUG_ON(ret);
@@ -2231,12 +2269,16 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
        if (bytes_del) {
                struct btrfs_key key;
 
-               key.objectid = dir->i_ino;
+               key.objectid = dir_ino;
                key.offset = 0;
                key.type = BTRFS_INODE_ITEM_KEY;
-               btrfs_release_path(log, path);
+               btrfs_release_path(path);
 
                ret = btrfs_search_slot(trans, log, &key, path, 0, 1);
+               if (ret < 0) {
+                       err = ret;
+                       goto fail;
+               }
                if (ret == 0) {
                        struct btrfs_inode_item *item;
                        u64 i_size;
@@ -2252,14 +2294,19 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
                        btrfs_mark_buffer_dirty(path->nodes[0]);
                } else
                        ret = 0;
-               btrfs_release_path(log, path);
+               btrfs_release_path(path);
        }
-
+fail:
        btrfs_free_path(path);
+out_unlock:
        mutex_unlock(&BTRFS_I(dir)->log_mutex);
+       if (ret == -ENOSPC) {
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 0;
+       }
        btrfs_end_log_trans(root);
 
-       return 0;
+       return err;
 }
 
 /* see comments for btrfs_del_dir_entries_in_log */
@@ -2281,9 +2328,13 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        log = root->log_root;
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
-       ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino,
+       ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode),
                                  dirid, &index);
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
+       if (ret == -ENOSPC) {
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 0;
+       }
        btrfs_end_log_trans(root);
 
        return ret;
@@ -2311,13 +2362,14 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
        else
                key.type = BTRFS_DIR_LOG_INDEX_KEY;
        ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item));
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                              struct btrfs_dir_log_item);
        btrfs_set_dir_log_end(path->nodes[0], item, last_offset);
        btrfs_mark_buffer_dirty(path->nodes[0]);
-       btrfs_release_path(log, path);
+       btrfs_release_path(path);
        return 0;
 }
 
@@ -2336,18 +2388,20 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        struct btrfs_key max_key;
        struct btrfs_root *log = root->log_root;
        struct extent_buffer *src;
+       int err = 0;
        int ret;
        int i;
        int nritems;
        u64 first_offset = min_offset;
        u64 last_offset = (u64)-1;
+       u64 ino = btrfs_ino(inode);
 
        log = root->log_root;
-       max_key.objectid = inode->i_ino;
+       max_key.objectid = ino;
        max_key.offset = (u64)-1;
        max_key.type = key_type;
 
-       min_key.objectid = inode->i_ino;
+       min_key.objectid = ino;
        min_key.type = key_type;
        min_key.offset = min_offset;
 
@@ -2360,18 +2414,17 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
         * we didn't find anything from this transaction, see if there
         * is anything at all
         */
-       if (ret != 0 || min_key.objectid != inode->i_ino ||
-           min_key.type != key_type) {
-               min_key.objectid = inode->i_ino;
+       if (ret != 0 || min_key.objectid != ino || min_key.type != key_type) {
+               min_key.objectid = ino;
                min_key.type = key_type;
                min_key.offset = (u64)-1;
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
                if (ret < 0) {
-                       btrfs_release_path(root, path);
+                       btrfs_release_path(path);
                        return ret;
                }
-               ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
+               ret = btrfs_previous_item(root, path, ino, key_type);
 
                /* if ret == 0 there are items for this type,
                 * create a range to tell us the last key of this type.
@@ -2389,7 +2442,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
        }
 
        /* go backward to find any previous key */
-       ret = btrfs_previous_item(root, path, inode->i_ino, key_type);
+       ret = btrfs_previous_item(root, path, ino, key_type);
        if (ret == 0) {
                struct btrfs_key tmp;
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
@@ -2398,9 +2451,13 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        ret = overwrite_item(trans, log, dst_path,
                                             path->nodes[0], path->slots[0],
                                             &tmp);
+                       if (ret) {
+                               err = ret;
+                               goto done;
+                       }
                }
        }
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
 
        /* find the first key from this transaction again */
        ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
@@ -2420,12 +2477,14 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                for (i = path->slots[0]; i < nritems; i++) {
                        btrfs_item_key_to_cpu(src, &min_key, i);
 
-                       if (min_key.objectid != inode->i_ino ||
-                           min_key.type != key_type)
+                       if (min_key.objectid != ino || min_key.type != key_type)
                                goto done;
                        ret = overwrite_item(trans, log, dst_path, src, i,
                                             &min_key);
-                       BUG_ON(ret);
+                       if (ret) {
+                               err = ret;
+                               goto done;
+                       }
                }
                path->slots[0] = nritems;
 
@@ -2439,7 +2498,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        goto done;
                }
                btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]);
-               if (tmp.objectid != inode->i_ino || tmp.type != key_type) {
+               if (tmp.objectid != ino || tmp.type != key_type) {
                        last_offset = (u64)-1;
                        goto done;
                }
@@ -2447,22 +2506,29 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                        ret = overwrite_item(trans, log, dst_path,
                                             path->nodes[0], path->slots[0],
                                             &tmp);
-
-                       BUG_ON(ret);
-                       last_offset = tmp.offset;
+                       if (ret)
+                               err = ret;
+                       else
+                               last_offset = tmp.offset;
                        goto done;
                }
        }
 done:
-       *last_offset_ret = last_offset;
-       btrfs_release_path(root, path);
-       btrfs_release_path(log, dst_path);
+       btrfs_release_path(path);
+       btrfs_release_path(dst_path);
 
-       /* insert the log range keys to indicate where the log is valid */
-       ret = insert_dir_log_key(trans, log, path, key_type, inode->i_ino,
-                                first_offset, last_offset);
-       BUG_ON(ret);
-       return 0;
+       if (err == 0) {
+               *last_offset_ret = last_offset;
+               /*
+                * insert the log range keys to indicate where the log
+                * is valid
+                */
+               ret = insert_dir_log_key(trans, log, path, key_type,
+                                        ino, first_offset, last_offset);
+               if (ret)
+                       err = ret;
+       }
+       return err;
 }
 
 /*
@@ -2494,7 +2560,8 @@ again:
                ret = log_dir_items(trans, root, inode, path,
                                    dst_path, key_type, min_key,
                                    &max_key);
-               BUG_ON(ret);
+               if (ret)
+                       return ret;
                if (max_key == (u64)-1)
                        break;
                min_key = max_key + 1;
@@ -2528,8 +2595,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
 
        while (1) {
                ret = btrfs_search_slot(trans, log, &key, path, -1, 1);
-
-               if (ret != 1)
+               BUG_ON(ret == 0);
+               if (ret < 0)
                        break;
 
                if (path->slots[0] == 0)
@@ -2543,11 +2610,12 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans,
                        break;
 
                ret = btrfs_del_item(trans, log, path);
-               BUG_ON(ret);
-               btrfs_release_path(log, path);
+               if (ret)
+                       break;
+               btrfs_release_path(path);
        }
-       btrfs_release_path(log, path);
-       return 0;
+       btrfs_release_path(path);
+       return ret;
 }
 
 static noinline int copy_items(struct btrfs_trans_handle *trans,
@@ -2571,6 +2639,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
 
        ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
                           nr * sizeof(u32), GFP_NOFS);
+       if (!ins_data)
+               return -ENOMEM;
+
        ins_sizes = (u32 *)ins_data;
        ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
@@ -2580,7 +2651,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        }
        ret = btrfs_insert_empty_items(trans, log, dst_path,
                                       ins_keys, ins_sizes, nr);
-       BUG_ON(ret);
+       if (ret) {
+               kfree(ins_data);
+               return ret;
+       }
 
        for (i = 0; i < nr; i++, dst_path->slots[0]++) {
                dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0],
@@ -2615,6 +2689,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                        extent = btrfs_item_ptr(src, start_slot + i,
                                                struct btrfs_file_extent_item);
 
+                       if (btrfs_file_extent_generation(src, extent) < trans->transid)
+                               continue;
+
                        found_type = btrfs_file_extent_type(src, extent);
                        if (found_type == BTRFS_FILE_EXTENT_REG ||
                            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
@@ -2629,7 +2706,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                                                                extent);
                                cs = btrfs_file_extent_offset(src, extent);
                                cl = btrfs_file_extent_num_bytes(src,
-                                                               extent);;
+                                                               extent);
                                if (btrfs_file_extent_compression(src,
                                                                  extent)) {
                                        cs = 0;
@@ -2639,30 +2716,31 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                                ret = btrfs_lookup_csums_range(
                                                log->fs_info->csum_root,
                                                ds + cs, ds + cs + cl - 1,
-                                               &ordered_sums);
+                                               &ordered_sums, 0);
                                BUG_ON(ret);
                        }
                }
        }
 
        btrfs_mark_buffer_dirty(dst_path->nodes[0]);
-       btrfs_release_path(log, dst_path);
+       btrfs_release_path(dst_path);
        kfree(ins_data);
 
        /*
         * we have to do this after the loop above to avoid changing the
         * log tree while trying to change the log tree.
         */
+       ret = 0;
        while (!list_empty(&ordered_sums)) {
                struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
                                                   struct btrfs_ordered_sum,
                                                   list);
-               ret = btrfs_csum_file_blocks(trans, log, sums);
-               BUG_ON(ret);
+               if (!ret)
+                       ret = btrfs_csum_file_blocks(trans, log, sums);
                list_del(&sums->list);
                kfree(sums);
        }
-       return 0;
+       return ret;
 }
 
 /* log a single inode in the tree log.
@@ -2689,22 +2767,29 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        struct btrfs_key max_key;
        struct btrfs_root *log = root->log_root;
        struct extent_buffer *src = NULL;
-       u32 size;
+       int err = 0;
        int ret;
        int nritems;
        int ins_start_slot = 0;
        int ins_nr;
+       u64 ino = btrfs_ino(inode);
 
        log = root->log_root;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        dst_path = btrfs_alloc_path();
+       if (!dst_path) {
+               btrfs_free_path(path);
+               return -ENOMEM;
+       }
 
-       min_key.objectid = inode->i_ino;
+       min_key.objectid = ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
        min_key.offset = 0;
 
-       max_key.objectid = inode->i_ino;
+       max_key.objectid = ino;
 
        /* today the code can only do partial logging of directories */
        if (!S_ISDIR(inode->i_mode))
@@ -2716,6 +2801,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                max_key.type = (u8)-1;
        max_key.offset = (u64)-1;
 
+       ret = btrfs_commit_inode_delayed_items(trans, inode);
+       if (ret) {
+               btrfs_free_path(path);
+               btrfs_free_path(dst_path);
+               return ret;
+       }
+
        mutex_lock(&BTRFS_I(inode)->log_mutex);
 
        /*
@@ -2727,12 +2819,14 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 
                if (inode_only == LOG_INODE_EXISTS)
                        max_key_type = BTRFS_XATTR_ITEM_KEY;
-               ret = drop_objectid_items(trans, log, path,
-                                         inode->i_ino, max_key_type);
+               ret = drop_objectid_items(trans, log, path, ino, max_key_type);
        } else {
                ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0);
        }
-       BUG_ON(ret);
+       if (ret) {
+               err = ret;
+               goto out_unlock;
+       }
        path->keep_locks = 1;
 
        while (1) {
@@ -2743,13 +2837,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                        break;
 again:
                /* note, ins_nr might be > 0 here, cleanup outside the loop */
-               if (min_key.objectid != inode->i_ino)
+               if (min_key.objectid != ino)
                        break;
                if (min_key.type > max_key.type)
                        break;
 
                src = path->nodes[0];
-               size = btrfs_item_size_nr(src, path->slots[0]);
                if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
                        ins_nr++;
                        goto next_slot;
@@ -2761,7 +2854,10 @@ again:
 
                ret = copy_items(trans, log, dst_path, src, ins_start_slot,
                                 ins_nr, inode_only);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
                ins_nr = 1;
                ins_start_slot = path->slots[0];
 next_slot:
@@ -2777,10 +2873,13 @@ next_slot:
                        ret = copy_items(trans, log, dst_path, src,
                                         ins_start_slot,
                                         ins_nr, inode_only);
-                       BUG_ON(ret);
+                       if (ret) {
+                               err = ret;
+                               goto out_unlock;
+                       }
                        ins_nr = 0;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
 
                if (min_key.offset < (u64)-1)
                        min_key.offset++;
@@ -2795,22 +2894,29 @@ next_slot:
                ret = copy_items(trans, log, dst_path, src,
                                 ins_start_slot,
                                 ins_nr, inode_only);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
                ins_nr = 0;
        }
        WARN_ON(ins_nr);
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
-               btrfs_release_path(root, path);
-               btrfs_release_path(log, dst_path);
+               btrfs_release_path(path);
+               btrfs_release_path(dst_path);
                ret = log_directory_changes(trans, root, inode, path, dst_path);
-               BUG_ON(ret);
+               if (ret) {
+                       err = ret;
+                       goto out_unlock;
+               }
        }
        BTRFS_I(inode)->logged_trans = trans->transid;
+out_unlock:
        mutex_unlock(&BTRFS_I(inode)->log_mutex);
 
        btrfs_free_path(path);
        btrfs_free_path(dst_path);
-       return 0;
+       return err;
 }
 
 /*
@@ -2827,6 +2933,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
 {
        int ret = 0;
        struct btrfs_root *root;
+       struct dentry *old_parent = NULL;
 
        /*
         * for regular files, if its inode is already on disk, we don't
@@ -2868,10 +2975,13 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
                if (IS_ROOT(parent))
                        break;
 
-               parent = parent->d_parent;
+               parent = dget_parent(parent);
+               dput(old_parent);
+               old_parent = parent;
                inode = parent->d_inode;
 
        }
+       dput(old_parent);
 out:
        return ret;
 }
@@ -2903,6 +3013,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 {
        int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
        struct super_block *sb;
+       struct dentry *old_parent = NULL;
        int ret = 0;
        u64 last_committed = root->fs_info->last_trans_committed;
 
@@ -2935,10 +3046,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
                goto end_no_trans;
        }
 
-       start_log_trans(trans, root);
+       ret = start_log_trans(trans, root);
+       if (ret)
+               goto end_trans;
 
        ret = btrfs_log_inode(trans, root, inode, inode_only);
-       BUG_ON(ret);
+       if (ret)
+               goto end_trans;
 
        /*
         * for regular files, if its inode is already on disk, we don't
@@ -2948,8 +3062,10 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
         */
        if (S_ISREG(inode->i_mode) &&
            BTRFS_I(inode)->generation <= last_committed &&
-           BTRFS_I(inode)->last_unlink_trans <= last_committed)
-                       goto no_parent;
+           BTRFS_I(inode)->last_unlink_trans <= last_committed) {
+               ret = 0;
+               goto end_trans;
+       }
 
        inode_only = LOG_INODE_EXISTS;
        while (1) {
@@ -2963,15 +3079,24 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
                if (BTRFS_I(inode)->generation >
                    root->fs_info->last_trans_committed) {
                        ret = btrfs_log_inode(trans, root, inode, inode_only);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto end_trans;
                }
                if (IS_ROOT(parent))
                        break;
 
-               parent = parent->d_parent;
+               parent = dget_parent(parent);
+               dput(old_parent);
+               old_parent = parent;
        }
-no_parent:
        ret = 0;
+end_trans:
+       dput(old_parent);
+       if (ret < 0) {
+               BUG_ON(ret != -ENOSPC);
+               root->fs_info->last_trans_log_full_commit = trans->transid;
+               ret = 1;
+       }
        btrfs_end_log_trans(root);
 end_no_trans:
        return ret;
@@ -2986,8 +3111,13 @@ end_no_trans:
 int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct dentry *dentry)
 {
-       return btrfs_log_inode_parent(trans, root, dentry->d_inode,
-                                     dentry->d_parent, 0);
+       struct dentry *parent = dget_parent(dentry);
+       int ret;
+
+       ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0);
+       dput(parent);
+
+       return ret;
 }
 
 /*
@@ -3009,16 +3139,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
                .stage = 0,
        };
 
-       fs_info->log_root_recovering = 1;
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
+
+       fs_info->log_root_recovering = 1;
 
-       trans = btrfs_start_transaction(fs_info->tree_root, 1);
+       trans = btrfs_start_transaction(fs_info->tree_root, 0);
+       BUG_ON(IS_ERR(trans));
 
        wc.trans = trans;
        wc.pin = 1;
 
-       walk_log_tree(trans, log_root_tree, &wc);
+       ret = walk_log_tree(trans, log_root_tree, &wc);
+       BUG_ON(ret);
 
 again:
        key.objectid = BTRFS_TREE_LOG_OBJECTID;
@@ -3036,21 +3170,20 @@ again:
                }
                btrfs_item_key_to_cpu(path->nodes[0], &found_key,
                                      path->slots[0]);
-               btrfs_release_path(log_root_tree, path);
+               btrfs_release_path(path);
                if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID)
                        break;
 
                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;
                tmp_key.type = BTRFS_ROOT_ITEM_KEY;
                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_OR_NULL(wc.replay_dest));
 
                wc.replay_dest->log_root = log;
                btrfs_record_root_in_trans(trans, wc.replay_dest);
@@ -3072,7 +3205,7 @@ again:
                if (found_key.offset == 0)
                        break;
        }
-       btrfs_release_path(log_root_tree, path);
+       btrfs_release_path(path);
 
        /* step one is to pin it all, step two is to replay just inodes */
        if (wc.pin) {