On 2019/4/23 3:08 下午, Hannes Reinecke wrote: > On 4/19/19 6:05 PM, Coly Li wrote: >> If a bcache device is in dirty state and its cache set is not >> registered, this bcache deivce will not appear in /dev/bcache<N>, >> and there is no way to stop it or remove the bcache kernel module. >> >> This is an as-designed behavior, but sometimes people has to reboot >> whole system to release or stop the pending backing device. >> >> This sysfs interface may remove such pending bcache devices when >> write anything into the sysfs file manually. >> >> Signed-off-by: Coly Li <colyli@xxxxxxx> >> --- >> drivers/md/bcache/super.c | 55 >> +++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 55 insertions(+) >> >> diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c >> index 9b41e0b62cc0..e988e46a6479 100644 >> --- a/drivers/md/bcache/super.c >> +++ b/drivers/md/bcache/super.c >> @@ -2246,9 +2246,13 @@ static int register_cache(struct cache_sb *sb, >> struct page *sb_page, >> static ssize_t register_bcache(struct kobject *k, struct >> kobj_attribute *attr, >> const char *buffer, size_t size); >> +static ssize_t bch_pending_bdevs_cleanup(struct kobject *k, >> + struct kobj_attribute *attr, >> + const char *buffer, size_t size); >> kobj_attribute_write(register, register_bcache); >> kobj_attribute_write(register_quiet, register_bcache); >> +kobj_attribute_write(pendings_cleanup, bch_pending_bdevs_cleanup); >> static bool bch_is_open_backing(struct block_device *bdev) >> { >> @@ -2373,6 +2377,56 @@ static ssize_t register_bcache(struct kobject >> *k, struct kobj_attribute *attr, >> goto out; >> } >> + >> +struct pdev { >> + struct list_head list; >> + struct cached_dev *dc; >> +}; >> + >> +static ssize_t bch_pending_bdevs_cleanup(struct kobject *k, >> + struct kobj_attribute *attr, >> + const char *buffer, >> + size_t size) >> +{ >> + LIST_HEAD(pending_devs); >> + ssize_t ret = size; >> + struct cached_dev *dc, *tdc; >> + struct pdev *pdev, *tpdev; >> + struct cache_set *c, *tc; >> + >> + mutex_lock(&bch_register_lock); >> + list_for_each_entry_safe(dc, tdc, &uncached_devices, list) { >> + pdev = kmalloc(sizeof(struct pdev), GFP_KERNEL); >> + if (!pdev) >> + break; >> + pdev->dc = dc; >> + list_add(&pdev->list, &pending_devs); >> + } >> + >> + list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) { >> + list_for_each_entry_safe(c, tc, &bch_cache_sets, list) { >> + char *pdev_set_uuid = pdev->dc->sb.set_uuid; >> + char *set_uuid = c->sb.uuid; >> + >> + if (!memcmp(pdev_set_uuid, set_uuid, 16)) { >> + list_del(&pdev->list); >> + kfree(pdev); >> + break; >> + } >> + } >> + } >> + mutex_unlock(&bch_register_lock); >> + >> + list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) { >> + pr_info("delete pdev %p", pdev); >> + list_del(&pdev->list); >> + bcache_device_stop(&pdev->dc->disk); >> + kfree(pdev); >> + } >> + >> + return ret; >> +} >> + >> static int bcache_reboot(struct notifier_block *n, unsigned long >> code, void *x) >> { >> if (code == SYS_DOWN || >> @@ -2483,6 +2537,7 @@ static int __init bcache_init(void) >> static const struct attribute *files[] = { >> &ksysfs_register.attr, >> &ksysfs_register_quiet.attr, >> + &ksysfs_pendings_cleanup.attr, >> NULL >> }; >> > _Actually_ I would like it better if the bcache device would be present > in sysfs for these cases, too, albeit in a disabled state. > That would allow us to remove the device like normal and we wouldn't > need to worry about yet another interface. Hi Hannes, I see. The awkward condition is, - If only show up the bcache device in /sys/block/bcache<?>/ directory but not show up in /dev/bcache<?> node, it might be more confused for users. - If show up both bcache devices in /sys/block/bcache<?> and /dev/bcache<?>, it means such device can be read/written, but it is staled (there are dirty data on cache device), which may corrupt existing data. So I choose to not change current code behavior and just add a sysfs interface. -- Coly Li