@@ -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;
@@ -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;
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(-)