mirror of
https://github.com/torvalds/linux.git
synced 2026-09-28 20:12:01 +02:00
btrfs: derive f_fsid from on-disk fsid and dev_t
The f_fsid was originally derived from fs_devices->fsid and the subvolume root ID. However, when temp_fsid is active, fs_devices->fsid is randomized, making the standard derivation inconsistent. Since metadata_uuid is optional, it is not a reliable alternative. This patch instead retrieves the on-disk UUID from fs_info->super_copy->fsid. To prevent f_fsid collisions between original and cloned filesystems, this implementation hashes the dev_t for single-device btrfs filesystems to ensure uniqueness. This is limited to single-device filesystems as cloned mounts are currently only supported for that configuration. Note that f_fsid will change if the device is replaced. Additionally, since the kernel cannot distinguish between the original and the cloned filesystem, this new f_fsid derivation is applied to both. Link: https://lore.kernel.org/linux-btrfs/cover.1772095546.git.asj@kernel.org/ Link: https://lore.kernel.org/linux-btrfs/cover.1774092915.git.asj@kernel.org/ Signed-off-by: Anand Jain <asj@kernel.org> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
df84f6c773
commit
c2a74ed049
|
|
@ -1732,12 +1732,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||||
u64 total_free_data = 0;
|
u64 total_free_data = 0;
|
||||||
u64 total_free_meta = 0;
|
u64 total_free_meta = 0;
|
||||||
u32 bits = fs_info->sectorsize_bits;
|
u32 bits = fs_info->sectorsize_bits;
|
||||||
__be32 *fsid = (__be32 *)fs_info->fs_devices->fsid;
|
__be32 *fsid;
|
||||||
unsigned factor = 1;
|
unsigned factor = 1;
|
||||||
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
|
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
|
||||||
int ret;
|
int ret;
|
||||||
u64 thresh = 0;
|
u64 thresh = 0;
|
||||||
int mixed = 0;
|
int mixed = 0;
|
||||||
|
__kernel_fsid_t f_fsid;
|
||||||
|
|
||||||
list_for_each_entry(found, &fs_info->space_info, list) {
|
list_for_each_entry(found, &fs_info->space_info, list) {
|
||||||
if (found->flags & BTRFS_BLOCK_GROUP_DATA &&
|
if (found->flags & BTRFS_BLOCK_GROUP_DATA &&
|
||||||
|
|
@ -1819,14 +1820,38 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||||
buf->f_bsize = fs_info->sectorsize;
|
buf->f_bsize = fs_info->sectorsize;
|
||||||
buf->f_namelen = BTRFS_NAME_LEN;
|
buf->f_namelen = BTRFS_NAME_LEN;
|
||||||
|
|
||||||
/* We treat it as constant endianness (it doesn't matter _which_)
|
/*
|
||||||
because we want the fsid to come out the same whether mounted
|
* fs_devices->fsid is dynamically generated when temp_fsid is active
|
||||||
on a big-endian or little-endian host */
|
* to support cloned filesystems. Use the original on-disk fsid instead,
|
||||||
buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]);
|
* as it remains consistent across mount cycles.
|
||||||
buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]);
|
*/
|
||||||
|
if (fs_info->fs_devices->temp_fsid)
|
||||||
|
fsid = (__be32 *)fs_info->super_copy->fsid;
|
||||||
|
else
|
||||||
|
fsid = (__be32 *)fs_info->fs_devices->fsid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We treat it as constant endianness (it doesn't matter _which_)
|
||||||
|
* because we want the fsid to come out the same whether mounted
|
||||||
|
* on a big-endian or little-endian host.
|
||||||
|
*/
|
||||||
|
f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]);
|
||||||
|
f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]);
|
||||||
|
|
||||||
/* Mask in the root object ID too, to disambiguate subvols */
|
/* Mask in the root object ID too, to disambiguate subvols */
|
||||||
buf->f_fsid.val[0] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root) >> 32;
|
f_fsid.val[0] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root) >> 32;
|
||||||
buf->f_fsid.val[1] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root);
|
f_fsid.val[1] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root);
|
||||||
|
|
||||||
|
/* Hash dev_t to avoid f_fsid collision with cloned filesystems. */
|
||||||
|
if (fs_info->fs_devices->total_devices == 1) {
|
||||||
|
__kernel_fsid_t dev_fsid =
|
||||||
|
u64_to_fsid(huge_encode_dev(fs_info->fs_devices->latest_dev->bdev->bd_dev));
|
||||||
|
|
||||||
|
f_fsid.val[0] ^= dev_fsid.val[1];
|
||||||
|
f_fsid.val[1] ^= dev_fsid.val[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&buf->f_fsid, &f_fsid, sizeof(f_fsid));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user