]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
btrfs: sysfs, add devid/dev_state kobject and device attributes
authorAnand Jain <anand.jain@oracle.com>
Mon, 6 Jan 2020 11:38:31 +0000 (19:38 +0800)
committerDavid Sterba <dsterba@suse.com>
Thu, 23 Jan 2020 16:24:36 +0000 (17:24 +0100)
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>
fs/btrfs/dev-replace.c
fs/btrfs/sysfs.c
fs/btrfs/sysfs.h
fs/btrfs/volumes.h

index f639dde2a679036d6d150264158d46986b6981ec..8600beb9c086ed81ecfd27e204fa74123fd71d94 100644 (file)
@@ -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 */
index 55e4ed1af29cf9b5a5ae72732cf910d6530a926f..7436422194da32503d87aea85cf3d116f16eb78a 100644 (file)
@@ -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);
 
-       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)
 {
@@ -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;
+
+                       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;
@@ -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;
 
index 3d27b39eaf9459fbd1e32c8b87ee631752081109..c68582add92ed95c9d3b612c10a31d6c35516ade 100644 (file)
@@ -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
index 9c7d4fe5c39a6d1dd83ba0cbe6a614258535e285..690d4f5a065368e9a2ca2a6d60796cd999839230 100644 (file)
@@ -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;
 };
 
 /*