bcache: add pendings_cleanup to stop pending bcache device
If a bcache device is in dirty state and its cache set is not registered, this bcache device 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@suse.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
944a4f340a
commit
0c277e211a
|
@ -2273,9 +2273,13 @@ err:
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -2400,6 +2404,56 @@ err:
|
|||
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 ||
|
||||
|
@ -2518,6 +2572,7 @@ static int __init bcache_init(void)
|
|||
static const struct attribute *files[] = {
|
||||
&ksysfs_register.attr,
|
||||
&ksysfs_register_quiet.attr,
|
||||
&ksysfs_pendings_cleanup.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue