Skip to content

Commit 42e48fd

Browse files
kakrakreijack
andcommitted
btrfs: change the DEV_ITEM 'type' field via sysfs
v2: Adds a check to prevent modification while the file system is still mounting. Todo: - Transactions should not be triggered from sysfw writes, see: https://lore.kernel.org/linux-btrfs/20251213200920.1808679-1-kai@kaishome.de/ Link: #36 (comment) Reported-by: Eli Venter <eli@genedx.com> Co-authored-by: Goffredo Baroncelli <kreijack@inwind.it> Signed-off-by: Kai Krakow <kai@kaishome.de>
1 parent 34ed0e4 commit 42e48fd

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

fs/btrfs/sysfs.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2149,7 +2149,69 @@ static ssize_t btrfs_devinfo_type_show(struct kobject *kobj,
21492149

21502150
return scnprintf(buf, PAGE_SIZE, "0x%08llx\n", device->type);
21512151
}
2152-
BTRFS_ATTR(devid, type, btrfs_devinfo_type_show);
2152+
2153+
static ssize_t btrfs_devinfo_type_store(struct kobject *kobj,
2154+
struct kobj_attribute *a,
2155+
const char *buf, size_t len)
2156+
{
2157+
struct btrfs_fs_info *fs_info;
2158+
struct btrfs_root *root;
2159+
struct btrfs_device *device;
2160+
int ret;
2161+
struct btrfs_trans_handle *trans;
2162+
2163+
u64 type, prev_type;
2164+
2165+
device = container_of(kobj, struct btrfs_device, devid_kobj);
2166+
fs_info = device->fs_info;
2167+
if (!fs_info)
2168+
return -EPERM;
2169+
2170+
/*
2171+
* Changing the type field requires starting a transaction which will cause a NULL derefernce in
2172+
* __reserve_bytes if the file system is not fully open. Thus, return EBUSY if the file system is not fully
2173+
* initialized.
2174+
*/
2175+
if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))
2176+
return -EBUSY;
2177+
2178+
root = fs_info->chunk_root;
2179+
if (sb_rdonly(fs_info->sb))
2180+
return -EROFS;
2181+
2182+
ret = kstrtou64(buf, 0, &type);
2183+
if (ret < 0)
2184+
return -EINVAL;
2185+
2186+
/* for now, only allow touching the 'allocation hint' bits */
2187+
if (type & ~((1 << BTRFS_DEV_ALLOCATION_MASK_BIT_COUNT) - 1))
2188+
return -EINVAL;
2189+
2190+
trans = btrfs_start_transaction(root, 1);
2191+
if (IS_ERR(trans))
2192+
return PTR_ERR(trans);
2193+
2194+
prev_type = device->type;
2195+
device->type = type;
2196+
2197+
ret = btrfs_update_device(trans, device);
2198+
2199+
if (ret < 0) {
2200+
btrfs_abort_transaction(trans, ret);
2201+
btrfs_end_transaction(trans);
2202+
goto abort;
2203+
}
2204+
2205+
ret = btrfs_commit_transaction(trans);
2206+
if (ret < 0)
2207+
goto abort;
2208+
2209+
return len;
2210+
abort:
2211+
device->type = prev_type;
2212+
return ret;
2213+
}
2214+
BTRFS_ATTR_RW(devid, type, btrfs_devinfo_type_show, btrfs_devinfo_type_store);
21532215
#endif
21542216

21552217
/*

fs/btrfs/volumes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2942,7 +2942,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
29422942
return ret;
29432943
}
29442944

2945-
static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
2945+
noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
29462946
struct btrfs_device *device)
29472947
{
29482948
int ret;

fs/btrfs/volumes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,8 @@ int btrfs_bg_type_to_factor(u64 flags);
890890
const char *btrfs_bg_type_to_raid_name(u64 flags);
891891
int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
892892
bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical);
893+
int btrfs_update_device(struct btrfs_trans_handle *trans,
894+
struct btrfs_device *device);
893895

894896
bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr);
895897
const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb);

0 commit comments

Comments
 (0)