mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	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
					
				
					 4 changed files with 138 additions and 23 deletions
				
			
		|  | @ -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 a new issue
	
	 Anand Jain
						Anand Jain