btrfs: unify lookup return value when dir entry is missing
authorFilipe Manana <fdmanana@suse.com>
Fri, 1 Oct 2021 12:52:33 +0000 (13:52 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 7 Oct 2021 20:06:32 +0000 (22:06 +0200)
btrfs_lookup_dir_index_item() and btrfs_lookup_dir_item() lookup for dir
entries and both are used during log replay or when updating a log tree
during an unlink.

However when the dir item does not exists, btrfs_lookup_dir_item() returns
NULL while btrfs_lookup_dir_index_item() returns PTR_ERR(-ENOENT), and if
the dir item exists but there is no matching entry for a given name or
index, both return NULL. This makes the call sites during log replay to
be more verbose than necessary and it makes it easy to miss this slight
difference. Since we don't need to distinguish between those two cases,
make btrfs_lookup_dir_index_item() always return NULL when there is no
matching directory entry - either because there isn't any dir entry or
because there is one but it does not match the given name and index.

Also rename the argument 'objectid' of btrfs_lookup_dir_index_item() to
'index' since it is supposed to match an index number, and the name
'objectid' is not very good because it can easily be confused with an
inode number (like the inode number a dir entry points to).

CC: stable@vger.kernel.org # 4.14+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/dir-item.c
fs/btrfs/tree-log.c

index f07c82f..852a49d 100644 (file)
@@ -3030,7 +3030,7 @@ struct btrfs_dir_item *
 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root,
                            struct btrfs_path *path, u64 dir,
-                           u64 objectid, const char *name, int name_len,
+                           u64 index, const char *name, int name_len,
                            int mod);
 struct btrfs_dir_item *
 btrfs_search_dir_index_item(struct btrfs_root *root,
index f1274d5..7721ce0 100644 (file)
@@ -190,9 +190,20 @@ static struct btrfs_dir_item *btrfs_lookup_match_dir(
 }
 
 /*
- * lookup a directory item based on name.  'dir' is the objectid
- * we're searching in, and 'mod' tells us if you plan on deleting the
- * item (use mod < 0) or changing the options (use mod > 0)
+ * Lookup for a directory item by name.
+ *
+ * @trans:     The transaction handle to use. Can be NULL if @mod is 0.
+ * @root:      The root of the target tree.
+ * @path:      Path to use for the search.
+ * @dir:       The inode number (objectid) of the directory.
+ * @name:      The name associated to the directory entry we are looking for.
+ * @name_len:  The length of the name.
+ * @mod:       Used to indicate if the tree search is meant for a read only
+ *             lookup, for a modification lookup or for a deletion lookup, so
+ *             its value should be 0, 1 or -1, respectively.
+ *
+ * Returns: NULL if the dir item does not exists, an error pointer if an error
+ * happened, or a pointer to a dir item if a dir item exists for the given name.
  */
 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
                                             struct btrfs_root *root,
@@ -273,27 +284,42 @@ out:
 }
 
 /*
- * lookup a directory item based on index.  'dir' is the objectid
- * we're searching in, and 'mod' tells us if you plan on deleting the
- * item (use mod < 0) or changing the options (use mod > 0)
+ * Lookup for a directory index item by name and index number.
  *
- * The name is used to make sure the index really points to the name you were
- * looking for.
+ * @trans:     The transaction handle to use. Can be NULL if @mod is 0.
+ * @root:      The root of the target tree.
+ * @path:      Path to use for the search.
+ * @dir:       The inode number (objectid) of the directory.
+ * @index:     The index number.
+ * @name:      The name associated to the directory entry we are looking for.
+ * @name_len:  The length of the name.
+ * @mod:       Used to indicate if the tree search is meant for a read only
+ *             lookup, for a modification lookup or for a deletion lookup, so
+ *             its value should be 0, 1 or -1, respectively.
+ *
+ * Returns: NULL if the dir index item does not exists, an error pointer if an
+ * error happened, or a pointer to a dir item if the dir index item exists and
+ * matches the criteria (name and index number).
  */
 struct btrfs_dir_item *
 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root,
                            struct btrfs_path *path, u64 dir,
-                           u64 objectid, const char *name, int name_len,
+                           u64 index, const char *name, int name_len,
                            int mod)
 {
+       struct btrfs_dir_item *di;
        struct btrfs_key key;
 
        key.objectid = dir;
        key.type = BTRFS_DIR_INDEX_KEY;
-       key.offset = objectid;
+       key.offset = index;
 
-       return btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
+       di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
+       if (di == ERR_PTR(-ENOENT))
+               return NULL;
+
+       return di;
 }
 
 struct btrfs_dir_item *
index 1b60082..1bb5ebf 100644 (file)
@@ -957,8 +957,7 @@ static noinline int inode_in_dir(struct btrfs_root *root,
        di = btrfs_lookup_dir_index_item(NULL, root, path, dirid,
                                         index, name, name_len, 0);
        if (IS_ERR(di)) {
-               if (PTR_ERR(di) != -ENOENT)
-                       ret = PTR_ERR(di);
+               ret = PTR_ERR(di);
                goto out;
        } else if (di) {
                btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
@@ -1191,8 +1190,7 @@ next:
        di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir),
                                         ref_index, name, namelen, 0);
        if (IS_ERR(di)) {
-               if (PTR_ERR(di) != -ENOENT)
-                       return PTR_ERR(di);
+               return PTR_ERR(di);
        } else if (di) {
                ret = drop_one_dir_item(trans, root, path, dir, di);
                if (ret)
@@ -1994,9 +1992,6 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
                goto out;
        }
 
-       if (dst_di == ERR_PTR(-ENOENT))
-               dst_di = NULL;
-
        if (IS_ERR(dst_di)) {
                ret = PTR_ERR(dst_di);
                goto out;
@@ -2304,7 +2299,7 @@ again:
                                                     dir_key->offset,
                                                     name, name_len, 0);
                }
-               if (!log_di || log_di == ERR_PTR(-ENOENT)) {
+               if (!log_di) {
                        btrfs_dir_item_key_to_cpu(eb, di, &location);
                        btrfs_release_path(path);
                        btrfs_release_path(log_path);
@@ -3563,8 +3558,7 @@ out_unlock:
        if (err == -ENOSPC) {
                btrfs_set_log_full_commit(trans);
                err = 0;
-       } else if (err < 0 && err != -ENOENT) {
-               /* ENOENT can be returned if the entry hasn't been fsynced yet */
+       } else if (err < 0) {
                btrfs_abort_transaction(trans, err);
        }