diff mbox series

[10/11] btrfs: introduce mapping function from location to inum

Message ID 162742546557.32498.956193040064011710.stgit@noble.brown (mailing list archive)
State New, archived
Headers show
Series expose btrfs subvols in mount table correctly | expand

Commit Message

NeilBrown July 27, 2021, 10:37 p.m. UTC
A btrfs directory entry can refer to two different sorts of objects

 BTRFS_INODE_ITEM_KEY - a regular fs object (file, dir, etc)
 BTRFS_ROOT_ITEM_KEY  - a reference to a subvol.

The 'objectid' numbers for these two are independent, so it is possible
(and common) for an INODE and a ROOT to have the same objectid.

As readdir reports the objectid as the inode number, if two such are in
the same directory, a tool which examines the inode numbers in getdents
results could think they are links.

As the BTRFS_ROOT_ITEM_KEY objectid is not visible via stat() (only
getdents), this is rarely if ever a problem.  However a future patch
will expose this number as the i_ino of an automount point.  This will
cause problems if the objectid is used as-is.

So: create a simple mapping function to reduce (or eliminate?) the
possibility of conflict.  The objectid of BTRFS_ROOT_ITEM_KEY is
subtracted from ULONG_MAX to make an inode number.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 fs/btrfs/btrfs_inode.h |   10 ++++++++++
 fs/btrfs/inode.c       |    3 ++-
 2 files changed, 12 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index c652e19ad74e..a4b5f38196e6 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -328,6 +328,16 @@  static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation)
 	return ret;
 }
 
+static inline unsigned long btrfs_location_to_ino(struct btrfs_key *location)
+{
+	if (location->type == BTRFS_INODE_ITEM_KEY)
+		return location->objectid;
+	/* Probably BTRFS_ROOT_ITEM_KEY, try to keep the inode
+	 * numbers separate.
+	 */
+	return ULONG_MAX - location->objectid;
+}
+
 struct btrfs_dio_private {
 	struct inode *inode;
 	u64 logical_offset;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8f60314c36c5..02537c1a9763 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6136,7 +6136,8 @@  static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
 		put_unaligned(fs_ftype_to_dtype(btrfs_dir_type(leaf, di)),
 				&entry->type);
 		btrfs_dir_item_key_to_cpu(leaf, di, &location);
-		put_unaligned(location.objectid, &entry->ino);
+		put_unaligned(btrfs_location_to_ino(&location),
+			      &entry->ino);
 		put_unaligned(found_key.offset, &entry->offset);
 		entries++;
 		addr += sizeof(struct dir_entry) + name_len;