btrfs: sysfs, add devid/dev_state kobject and device attributes
New sysfs attributes that track the filesystem status of devices, stored in the per-filesystem directory in /sys/fs/btrfs/FSID/devinfo . There's a directory for each device, with name corresponding to the numerical device id. in_fs_metadata - device is in the list of fs metadata missing - device is missing (no device node or block device) replace_target - device is target of replace writeable - writes from fs are allowed These attributes reflect the state of the device::dev_state and created at mount time. Sample output: $ pwd /sys/fs/btrfs/6e1961f1-5918-4ecc-a22f-948897b409f7/devinfo/1/ $ ls in_fs_metadata missing replace_target writeable $ cat missing 0 The output from these attributes are 0 or 1. 0 indicates unset and 1 indicates set. These attributes are readonly. It is observed that the device delete thread and sysfs read thread will not race because the delete thread calls sysfs kobject_put() which in turn waits for existing sysfs read to complete. Note for device replace devid swap: During the replace the target device temporarily assumes devid 0 before assigning the devid of the soruce device. In btrfs_dev_replace_finishing() we remove source sysfs devid using the function btrfs_sysfs_remove_devices_attr(), so after that call kobject_rename() to update the devid in the sysfs. This adds and calls btrfs_sysfs_update_devid() helper function to update the device id. Signed-off-by: Anand Jain <anand.jain@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> [ update changelog ] Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
1776ad172e
commit
668e48af7a
|
@ -707,6 +707,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
|||
|
||||
/* replace the sysfs entry */
|
||||
btrfs_sysfs_rm_device_link(fs_info->fs_devices, src_device);
|
||||
btrfs_sysfs_update_devid(tgt_device);
|
||||
btrfs_rm_dev_replace_free_srcdev(src_device);
|
||||
|
||||
/* write back the superblocks */
|
||||
|
|
155
fs/btrfs/sysfs.c
155
fs/btrfs/sysfs.c
|
@ -1152,29 +1152,117 @@ int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices,
|
|||
if (!fs_devices->devices_kobj)
|
||||
return -EINVAL;
|
||||
|
||||
if (one_device && one_device->bdev) {
|
||||
disk = one_device->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
if (one_device) {
|
||||
if (one_device->bdev) {
|
||||
disk = one_device->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
sysfs_remove_link(fs_devices->devices_kobj,
|
||||
disk_kobj->name);
|
||||
}
|
||||
|
||||
sysfs_remove_link(fs_devices->devices_kobj, disk_kobj->name);
|
||||
kobject_del(&one_device->devid_kobj);
|
||||
kobject_put(&one_device->devid_kobj);
|
||||
|
||||
wait_for_completion(&one_device->kobj_unregister);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (one_device)
|
||||
return 0;
|
||||
list_for_each_entry(one_device, &fs_devices->devices, dev_list) {
|
||||
|
||||
list_for_each_entry(one_device,
|
||||
&fs_devices->devices, dev_list) {
|
||||
if (!one_device->bdev)
|
||||
continue;
|
||||
disk = one_device->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
if (one_device->bdev) {
|
||||
disk = one_device->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
sysfs_remove_link(fs_devices->devices_kobj,
|
||||
disk_kobj->name);
|
||||
}
|
||||
kobject_del(&one_device->devid_kobj);
|
||||
kobject_put(&one_device->devid_kobj);
|
||||
|
||||
sysfs_remove_link(fs_devices->devices_kobj, disk_kobj->name);
|
||||
wait_for_completion(&one_device->kobj_unregister);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj,
|
||||
struct kobj_attribute *a,
|
||||
char *buf)
|
||||
{
|
||||
int val;
|
||||
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
|
||||
devid_kobj);
|
||||
|
||||
val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show);
|
||||
|
||||
static ssize_t btrfs_sysfs_missing_show(struct kobject *kobj,
|
||||
struct kobj_attribute *a, char *buf)
|
||||
{
|
||||
int val;
|
||||
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
|
||||
devid_kobj);
|
||||
|
||||
val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
BTRFS_ATTR(devid, missing, btrfs_sysfs_missing_show);
|
||||
|
||||
static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
|
||||
struct kobj_attribute *a,
|
||||
char *buf)
|
||||
{
|
||||
int val;
|
||||
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
|
||||
devid_kobj);
|
||||
|
||||
val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
|
||||
|
||||
static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *a, char *buf)
|
||||
{
|
||||
int val;
|
||||
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
|
||||
devid_kobj);
|
||||
|
||||
val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
|
||||
|
||||
static struct attribute *devid_attrs[] = {
|
||||
BTRFS_ATTR_PTR(devid, in_fs_metadata),
|
||||
BTRFS_ATTR_PTR(devid, missing),
|
||||
BTRFS_ATTR_PTR(devid, replace_target),
|
||||
BTRFS_ATTR_PTR(devid, writeable),
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(devid);
|
||||
|
||||
static void btrfs_release_devid_kobj(struct kobject *kobj)
|
||||
{
|
||||
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
|
||||
devid_kobj);
|
||||
|
||||
memset(&device->devid_kobj, 0, sizeof(struct kobject));
|
||||
complete(&device->kobj_unregister);
|
||||
}
|
||||
|
||||
static struct kobj_type devid_ktype = {
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.default_groups = devid_groups,
|
||||
.release = btrfs_release_devid_kobj,
|
||||
};
|
||||
|
||||
int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices,
|
||||
struct btrfs_device *one_device)
|
||||
{
|
||||
|
@ -1182,22 +1270,31 @@ int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices,
|
|||
struct btrfs_device *dev;
|
||||
|
||||
list_for_each_entry(dev, &fs_devices->devices, dev_list) {
|
||||
struct hd_struct *disk;
|
||||
struct kobject *disk_kobj;
|
||||
|
||||
if (!dev->bdev)
|
||||
continue;
|
||||
|
||||
if (one_device && one_device != dev)
|
||||
continue;
|
||||
|
||||
disk = dev->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
if (dev->bdev) {
|
||||
struct hd_struct *disk;
|
||||
struct kobject *disk_kobj;
|
||||
|
||||
error = sysfs_create_link(fs_devices->devices_kobj,
|
||||
disk_kobj, disk_kobj->name);
|
||||
if (error)
|
||||
disk = dev->bdev->bd_part;
|
||||
disk_kobj = &part_to_dev(disk)->kobj;
|
||||
|
||||
error = sysfs_create_link(fs_devices->devices_kobj,
|
||||
disk_kobj, disk_kobj->name);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
init_completion(&dev->kobj_unregister);
|
||||
error = kobject_init_and_add(&dev->devid_kobj, &devid_ktype,
|
||||
fs_devices->devices_kobj, "%llu",
|
||||
dev->devid);
|
||||
if (error) {
|
||||
kobject_put(&dev->devid_kobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -1229,6 +1326,18 @@ void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices,
|
|||
"sysfs: failed to create fsid for sprout");
|
||||
}
|
||||
|
||||
void btrfs_sysfs_update_devid(struct btrfs_device *device)
|
||||
{
|
||||
char tmp[24];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%llu", device->devid);
|
||||
|
||||
if (kobject_rename(&device->devid_kobj, tmp))
|
||||
btrfs_warn(device->fs_devices->fs_info,
|
||||
"sysfs: failed to update devid for %llu",
|
||||
device->devid);
|
||||
}
|
||||
|
||||
/* /sys/fs/btrfs/ entry */
|
||||
static struct kset *btrfs_kset;
|
||||
|
||||
|
|
|
@ -34,5 +34,6 @@ void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache);
|
|||
int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_space_info *space_info);
|
||||
void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info);
|
||||
void btrfs_sysfs_update_devid(struct btrfs_device *device);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -136,6 +136,10 @@ struct btrfs_device {
|
|||
atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
|
||||
|
||||
struct extent_io_tree alloc_state;
|
||||
|
||||
struct completion kobj_unregister;
|
||||
/* For sysfs/FSID/devinfo/devid/ */
|
||||
struct kobject devid_kobj;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue
Block a user