btrfs: remove no longer needed logic for replaying directory deletes
authorFilipe Manana <fdmanana@suse.com>
Mon, 25 Oct 2021 16:31:54 +0000 (17:31 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 3 Jan 2022 14:09:42 +0000 (15:09 +0100)
Now that we log only dir index keys when logging a directory, we no longer
need to deal with dir item keys in the log replay code for replaying
directory deletes. This is also true for the case when we replay a log
tree created by a kernel that still logs dir items.

So remove the remaining code of the replay of directory deletes algorithm
that deals with dir item keys.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/tree-log.c
include/uapi/linux/btrfs_tree.h

index 06defcd559a0db08e83b6262cd84adac925f8853..3da8452f682cca60840ff7dce725b58bec0ecf63 100644 (file)
@@ -2203,7 +2203,7 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
  */
 static noinline int find_dir_range(struct btrfs_root *root,
                                   struct btrfs_path *path,
-                                  u64 dirid, int key_type,
+                                  u64 dirid,
                                   u64 *start_ret, u64 *end_ret)
 {
        struct btrfs_key key;
@@ -2216,7 +2216,7 @@ static noinline int find_dir_range(struct btrfs_root *root,
                return 1;
 
        key.objectid = dirid;
-       key.type = key_type;
+       key.type = BTRFS_DIR_LOG_INDEX_KEY;
        key.offset = *start_ret;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -2230,7 +2230,7 @@ static noinline int find_dir_range(struct btrfs_root *root,
        if (ret != 0)
                btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 
-       if (key.type != key_type || key.objectid != dirid) {
+       if (key.type != BTRFS_DIR_LOG_INDEX_KEY || key.objectid != dirid) {
                ret = 1;
                goto next;
        }
@@ -2257,7 +2257,7 @@ next:
 
        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 
-       if (key.type != key_type || key.objectid != dirid) {
+       if (key.type != BTRFS_DIR_LOG_INDEX_KEY || key.objectid != dirid) {
                ret = 1;
                goto out;
        }
@@ -2288,95 +2288,82 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
        int ret;
        struct extent_buffer *eb;
        int slot;
-       u32 item_size;
        struct btrfs_dir_item *di;
-       struct btrfs_dir_item *log_di;
        int name_len;
-       unsigned long ptr;
-       unsigned long ptr_end;
        char *name;
-       struct inode *inode;
+       struct inode *inode = NULL;
        struct btrfs_key location;
 
-again:
+       /*
+        * Currenly we only log dir index keys. Even if we replay a log created
+        * by an older kernel that logged both dir index and dir item keys, all
+        * we need to do is process the dir index keys, we (and our caller) can
+        * safely ignore dir item keys (key type BTRFS_DIR_ITEM_KEY).
+        */
+       ASSERT(dir_key->type == BTRFS_DIR_INDEX_KEY);
+
        eb = path->nodes[0];
        slot = path->slots[0];
-       item_size = btrfs_item_size_nr(eb, slot);
-       ptr = btrfs_item_ptr_offset(eb, slot);
-       ptr_end = ptr + item_size;
-       while (ptr < ptr_end) {
-               di = (struct btrfs_dir_item *)ptr;
-               name_len = btrfs_dir_name_len(eb, di);
-               name = kmalloc(name_len, GFP_NOFS);
-               if (!name) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               read_extent_buffer(eb, name, (unsigned long)(di + 1),
-                                 name_len);
-               log_di = NULL;
-               if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) {
-                       log_di = btrfs_lookup_dir_item(trans, log, log_path,
-                                                      dir_key->objectid,
-                                                      name, name_len, 0);
-               } else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) {
-                       log_di = btrfs_lookup_dir_index_item(trans, log,
-                                                    log_path,
-                                                    dir_key->objectid,
-                                                    dir_key->offset,
-                                                    name, name_len, 0);
-               }
-               if (!log_di) {
-                       btrfs_dir_item_key_to_cpu(eb, di, &location);
-                       btrfs_release_path(path);
-                       btrfs_release_path(log_path);
-                       inode = read_one_inode(root, location.objectid);
-                       if (!inode) {
-                               kfree(name);
-                               return -EIO;
-                       }
+       di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
+       name_len = btrfs_dir_name_len(eb, di);
+       name = kmalloc(name_len, GFP_NOFS);
+       if (!name) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
-                       ret = link_to_fixup_dir(trans, root,
-                                               path, location.objectid);
-                       if (ret) {
-                               kfree(name);
-                               iput(inode);
-                               goto out;
-                       }
+       read_extent_buffer(eb, name, (unsigned long)(di + 1), name_len);
 
-                       inc_nlink(inode);
-                       ret = btrfs_unlink_inode(trans, BTRFS_I(dir),
-                                       BTRFS_I(inode), name, name_len);
-                       if (!ret)
-                               ret = btrfs_run_delayed_items(trans);
-                       kfree(name);
-                       iput(inode);
-                       if (ret)
-                               goto out;
+       if (log) {
+               struct btrfs_dir_item *log_di;
 
-                       /* there might still be more names under this key
-                        * check and repeat if required
-                        */
-                       ret = btrfs_search_slot(NULL, root, dir_key, path,
-                                               0, 0);
-                       if (ret == 0)
-                               goto again;
+               log_di = btrfs_lookup_dir_index_item(trans, log, log_path,
+                                                    dir_key->objectid,
+                                                    dir_key->offset,
+                                                    name, name_len, 0);
+               if (IS_ERR(log_di)) {
+                       ret = PTR_ERR(log_di);
+                       goto out;
+               } else if (log_di) {
+                       /* The dentry exists in the log, we have nothing to do. */
                        ret = 0;
                        goto out;
-               } else if (IS_ERR(log_di)) {
-                       kfree(name);
-                       return PTR_ERR(log_di);
                }
-               btrfs_release_path(log_path);
-               kfree(name);
+       }
 
-               ptr = (unsigned long)(di + 1);
-               ptr += name_len;
+       btrfs_dir_item_key_to_cpu(eb, di, &location);
+       btrfs_release_path(path);
+       btrfs_release_path(log_path);
+       inode = read_one_inode(root, location.objectid);
+       if (!inode) {
+               ret = -EIO;
+               goto out;
        }
-       ret = 0;
+
+       ret = link_to_fixup_dir(trans, root, path, location.objectid);
+       if (ret)
+               goto out;
+
+       inc_nlink(inode);
+       ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(inode), name,
+                                name_len);
+       if (ret)
+               goto out;
+
+       ret = btrfs_run_delayed_items(trans);
+       if (ret)
+               goto out;
+
+       /*
+        * Unlike dir item keys, dir index keys can only have one name (entry) in
+        * them, as there are no key collisions since each key has a unique offset
+        * (an index number), so we're done.
+        */
 out:
        btrfs_release_path(path);
        btrfs_release_path(log_path);
+       kfree(name);
+       iput(inode);
        return ret;
 }
 
@@ -2496,7 +2483,6 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
 {
        u64 range_start;
        u64 range_end;
-       int key_type = BTRFS_DIR_LOG_ITEM_KEY;
        int ret = 0;
        struct btrfs_key dir_key;
        struct btrfs_key found_key;
@@ -2504,7 +2490,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
        struct inode *dir;
 
        dir_key.objectid = dirid;
-       dir_key.type = BTRFS_DIR_ITEM_KEY;
+       dir_key.type = BTRFS_DIR_INDEX_KEY;
        log_path = btrfs_alloc_path();
        if (!log_path)
                return -ENOMEM;
@@ -2518,14 +2504,14 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
                btrfs_free_path(log_path);
                return 0;
        }
-again:
+
        range_start = 0;
        range_end = 0;
        while (1) {
                if (del_all)
                        range_end = (u64)-1;
                else {
-                       ret = find_dir_range(log, path, dirid, key_type,
+                       ret = find_dir_range(log, path, dirid,
                                             &range_start, &range_end);
                        if (ret < 0)
                                goto out;
@@ -2552,8 +2538,10 @@ again:
                        btrfs_item_key_to_cpu(path->nodes[0], &found_key,
                                              path->slots[0]);
                        if (found_key.objectid != dirid ||
-                           found_key.type != dir_key.type)
-                               goto next_type;
+                           found_key.type != dir_key.type) {
+                               ret = 0;
+                               goto out;
+                       }
 
                        if (found_key.offset > range_end)
                                break;
@@ -2572,15 +2560,7 @@ again:
                        break;
                range_start = range_end + 1;
        }
-
-next_type:
        ret = 0;
-       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(path);
-               goto again;
-       }
 out:
        btrfs_release_path(path);
        btrfs_free_path(log_path);
index e1c4c732aabac20140cfb2924745b9a67448966c..5416f1f1a77a859bdd444461a325788385f081e9 100644 (file)
 
 /*
  * dir items are the name -> inode pointers in a directory.  There is one
- * for every name in a directory.
+ * for every name in a directory.  BTRFS_DIR_LOG_ITEM_KEY is no longer used
+ * but it's still defined here for documentation purposes and to help avoid
+ * having its numerical value reused in the future.
  */
 #define BTRFS_DIR_LOG_ITEM_KEY  60
 #define BTRFS_DIR_LOG_INDEX_KEY 72