Skip to content

Commit

Permalink
btrfs: sysfs, add devid/dev_state kobject and device attributes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
asj authored and kdave committed Jan 23, 2020
1 parent 1776ad1 commit 668e48a
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 23 deletions.
1 change: 1 addition & 0 deletions fs/btrfs/dev-replace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
155 changes: 132 additions & 23 deletions fs/btrfs/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1152,52 +1152,149 @@ 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);

if (one_device)
return 0;
}

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;
list_for_each_entry(one_device, &fs_devices->devices, dev_list) {

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)
{
int error = 0;
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;

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;
}

error = sysfs_create_link(fs_devices->devices_kobj,
disk_kobj, disk_kobj->name);
if (error)
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;
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/*
Expand Down

0 comments on commit 668e48a

Please sign in to comment.