Btrfs: Mixed back reference (FORWARD ROLLING FORMAT CHANGE)
[linux-3.10.git] / fs / btrfs / tree-log.c
index 1b7f04a..2b41fc0 100644 (file)
@@ -262,11 +262,9 @@ static int process_one_buffer(struct btrfs_root *log,
                              struct extent_buffer *eb,
                              struct walk_control *wc, u64 gen)
 {
-       if (wc->pin) {
-               mutex_lock(&log->fs_info->pinned_mutex);
+       if (wc->pin)
                btrfs_update_pinned_extents(log->fs_info->extent_root,
                                            eb->start, eb->len, 1);
-       }
 
        if (btrfs_buffer_uptodate(eb, gen)) {
                if (wc->write)
@@ -432,18 +430,16 @@ no_copy:
 static noinline struct inode *read_one_inode(struct btrfs_root *root,
                                             u64 objectid)
 {
+       struct btrfs_key key;
        struct inode *inode;
-       inode = btrfs_iget_locked(root->fs_info->sb, objectid, root);
-       if (inode->i_state & I_NEW) {
-               BTRFS_I(inode)->root = root;
-               BTRFS_I(inode)->location.objectid = objectid;
-               BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
-               BTRFS_I(inode)->location.offset = 0;
-               btrfs_read_locked_inode(inode);
-               unlock_new_inode(inode);
 
-       }
-       if (is_bad_inode(inode)) {
+       key.objectid = objectid;
+       key.type = BTRFS_INODE_ITEM_KEY;
+       key.offset = 0;
+       inode = btrfs_iget(root->fs_info->sb, &key, root);
+       if (IS_ERR(inode)) {
+               inode = NULL;
+       } else if (is_bad_inode(inode)) {
                iput(inode);
                inode = NULL;
        }
@@ -538,11 +534,12 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
        saved_nbytes = inode_get_bytes(inode);
        /* drop any overlapping extents */
        ret = btrfs_drop_extents(trans, root, inode,
-                        start, extent_end, start, &alloc_hint);
+                        start, extent_end, extent_end, start, &alloc_hint);
        BUG_ON(ret);
 
        if (found_type == BTRFS_FILE_EXTENT_REG ||
            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
+               u64 offset;
                unsigned long dest_offset;
                struct btrfs_key ins;
 
@@ -557,6 +554,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                ins.objectid = btrfs_file_extent_disk_bytenr(eb, item);
                ins.offset = btrfs_file_extent_disk_num_bytes(eb, item);
                ins.type = BTRFS_EXTENT_ITEM_KEY;
+               offset = key->offset - btrfs_file_extent_offset(eb, item);
 
                if (ins.objectid > 0) {
                        u64 csum_start;
@@ -571,19 +569,16 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                        if (ret == 0) {
                                ret = btrfs_inc_extent_ref(trans, root,
                                                ins.objectid, ins.offset,
-                                               path->nodes[0]->start,
-                                               root->root_key.objectid,
-                                               trans->transid, key->objectid);
+                                               0, root->root_key.objectid,
+                                               key->objectid, offset);
                        } else {
                                /*
                                 * insert the extent pointer in the extent
                                 * allocation tree
                                 */
-                               ret = btrfs_alloc_logged_extent(trans, root,
-                                               path->nodes[0]->start,
-                                               root->root_key.objectid,
-                                               trans->transid, key->objectid,
-                                               &ins);
+                               ret = btrfs_alloc_logged_file_extent(trans,
+                                               root, root->root_key.objectid,
+                                               key->objectid, offset, &ins);
                                BUG_ON(ret);
                        }
                        btrfs_release_path(root, path);
@@ -1224,8 +1219,7 @@ insert:
        ret = insert_one_name(trans, root, path, key->objectid, key->offset,
                              name, name_len, log_type, &log_key);
 
-       if (ret && ret != -ENOENT)
-               BUG();
+       BUG_ON(ret && ret != -ENOENT);
        goto out;
 }
 
@@ -1709,9 +1703,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
-                               ret = btrfs_drop_leaf_ref(trans, root, next);
-                               BUG_ON(ret);
-
                                WARN_ON(root_owner !=
                                        BTRFS_TREE_LOG_OBJECTID);
                                ret = btrfs_free_reserved_extent(root,
@@ -1756,10 +1747,6 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                btrfs_wait_tree_block_writeback(next);
                btrfs_tree_unlock(next);
 
-               if (*level == 0) {
-                       ret = btrfs_drop_leaf_ref(trans, root, next);
-                       BUG_ON(ret);
-               }
                WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
                ret = btrfs_free_reserved_extent(root, bytenr, blocksize);
                BUG_ON(ret);
@@ -1814,12 +1801,6 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
-                               if (*level == 0) {
-                                       ret = btrfs_drop_leaf_ref(trans, root,
-                                                                 next);
-                                       BUG_ON(ret);
-                               }
-
                                WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
                                ret = btrfs_free_reserved_extent(root,
                                                path->nodes[*level]->start,
@@ -1887,11 +1868,6 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                        btrfs_wait_tree_block_writeback(next);
                        btrfs_tree_unlock(next);
 
-                       if (orig_level == 0) {
-                               ret = btrfs_drop_leaf_ref(trans, log,
-                                                         next);
-                               BUG_ON(ret);
-                       }
                        WARN_ON(log->root_key.objectid !=
                                BTRFS_TREE_LOG_OBJECTID);
                        ret = btrfs_free_reserved_extent(log, next->start,
@@ -2030,9 +2006,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
        BUG_ON(ret);
 
-       btrfs_set_root_bytenr(&log->root_item, log->node->start);
-       btrfs_set_root_generation(&log->root_item, trans->transid);
-       btrfs_set_root_level(&log->root_item, btrfs_header_level(log->node));
+       btrfs_set_root_node(&log->root_item, log->node);
 
        root->log_batch = 0;
        root->log_transid++;
@@ -2584,7 +2558,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                                       ins_keys, ins_sizes, nr);
        BUG_ON(ret);
 
-       for (i = 0; i < nr; i++) {
+       for (i = 0; i < nr; i++, dst_path->slots[0]++) {
                dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0],
                                                   dst_path->slots[0]);
 
@@ -2620,36 +2594,31 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                        found_type = btrfs_file_extent_type(src, extent);
                        if (found_type == BTRFS_FILE_EXTENT_REG ||
                            found_type == BTRFS_FILE_EXTENT_PREALLOC) {
-                               u64 ds = btrfs_file_extent_disk_bytenr(src,
-                                                                  extent);
-                               u64 dl = btrfs_file_extent_disk_num_bytes(src,
-                                                                     extent);
-                               u64 cs = btrfs_file_extent_offset(src, extent);
-                               u64 cl = btrfs_file_extent_num_bytes(src,
-                                                                    extent);;
+                               u64 ds, dl, cs, cl;
+                               ds = btrfs_file_extent_disk_bytenr(src,
+                                                               extent);
+                               /* ds == 0 is a hole */
+                               if (ds == 0)
+                                       continue;
+
+                               dl = btrfs_file_extent_disk_num_bytes(src,
+                                                               extent);
+                               cs = btrfs_file_extent_offset(src, extent);
+                               cl = btrfs_file_extent_num_bytes(src,
+                                                               extent);;
                                if (btrfs_file_extent_compression(src,
                                                                  extent)) {
                                        cs = 0;
                                        cl = dl;
                                }
-                               /* ds == 0 is a hole */
-                               if (ds != 0) {
-                                       ret = btrfs_inc_extent_ref(trans, log,
-                                                  ds, dl,
-                                                  dst_path->nodes[0]->start,
-                                                  BTRFS_TREE_LOG_OBJECTID,
-                                                  trans->transid,
-                                                  ins_keys[i].objectid);
-                                       BUG_ON(ret);
-                                       ret = btrfs_lookup_csums_range(
-                                                  log->fs_info->csum_root,
-                                                  ds + cs, ds + cs + cl - 1,
-                                                  &ordered_sums);
-                                       BUG_ON(ret);
-                               }
+
+                               ret = btrfs_lookup_csums_range(
+                                               log->fs_info->csum_root,
+                                               ds + cs, ds + cs + cl - 1,
+                                               &ordered_sums);
+                               BUG_ON(ret);
                        }
                }
-               dst_path->slots[0]++;
        }
 
        btrfs_mark_buffer_dirty(dst_path->nodes[0]);
@@ -2835,6 +2804,17 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
        int ret = 0;
        struct btrfs_root *root;
 
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto out;
+
        if (!S_ISDIR(inode->i_mode)) {
                if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
                        goto out;
@@ -2889,6 +2869,11 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 
        sb = inode->i_sb;
 
+       if (btrfs_test_opt(root, NOTREELOG)) {
+               ret = 1;
+               goto end_no_trans;
+       }
+
        if (root->fs_info->last_trans_log_full_commit >
            root->fs_info->last_trans_committed) {
                ret = 1;
@@ -2904,8 +2889,19 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 
        ret = btrfs_log_inode(trans, root, inode, inode_only);
        BUG_ON(ret);
-       inode_only = LOG_INODE_EXISTS;
 
+       /*
+        * for regular files, if its inode is already on disk, we don't
+        * have to worry about the parents at all.  This is because
+        * we can use the last_unlink_trans field to record renames
+        * and other fun in this file.
+        */
+       if (S_ISREG(inode->i_mode) &&
+           BTRFS_I(inode)->generation <= last_committed &&
+           BTRFS_I(inode)->last_unlink_trans <= last_committed)
+                       goto no_parent;
+
+       inode_only = LOG_INODE_EXISTS;
        while (1) {
                if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb)
                        break;
@@ -2921,6 +2917,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 
                parent = parent->d_parent;
        }
+no_parent:
        ret = 0;
        btrfs_end_log_trans(root);
 end_no_trans:
@@ -3004,9 +3001,7 @@ again:
                BUG_ON(!wc.replay_dest);
 
                wc.replay_dest->log_root = log;
-               mutex_lock(&fs_info->trans_mutex);
-               btrfs_record_root_in_trans(wc.replay_dest);
-               mutex_unlock(&fs_info->trans_mutex);
+               btrfs_record_root_in_trans(trans, wc.replay_dest);
                ret = walk_log_tree(trans, log, &wc);
                BUG_ON(ret);
 
@@ -3070,6 +3065,19 @@ void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
                             int for_rename)
 {
        /*
+        * when we're logging a file, if it hasn't been renamed
+        * or unlinked, and its inode is fully committed on disk,
+        * we don't have to worry about walking up the directory chain
+        * to log its parents.
+        *
+        * So, we use the last_unlink_trans field to put this transid
+        * into the file.  When the file is logged we check it and
+        * don't log the parents if the file is fully on disk.
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
         * if this directory was already logged any new
         * names for this file/dir will get recorded
         */
@@ -3115,6 +3123,13 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
        struct btrfs_root * root = BTRFS_I(inode)->root;
 
        /*
+        * this will force the logging code to walk the dentry chain
+        * up for the file
+        */
+       if (S_ISREG(inode->i_mode))
+               BTRFS_I(inode)->last_unlink_trans = trans->transid;
+
+       /*
         * if this inode hasn't been logged and directory we're renaming it
         * from hasn't been logged, we don't need to log it
         */