diff --git a/scst/src/dev_handlers/kunit/vdisk/suites/scst_vdisk_sync_test.c b/scst/src/dev_handlers/kunit/vdisk/suites/scst_vdisk_sync_test.c index a24eca388..2793dd67c 100644 --- a/scst/src/dev_handlers/kunit/vdisk/suites/scst_vdisk_sync_test.c +++ b/scst/src/dev_handlers/kunit/vdisk/suites/scst_vdisk_sync_test.c @@ -205,12 +205,6 @@ static void vdisk_backend_test(struct kunit *test) struct vdisk_test_fixture *f = test->priv; int ret; - /* Avoid dereferencing a closed backend until its lifetime is fixed. */ - if (p->closed && !p->nullio) { - kunit_skip(test, "closed-backend sync needs a separate lifetime fix"); - return; - } - f->vdev.dev_active = !p->inactive; f->vdev.nullio = p->nullio; f->vdev.blockio = p->blockio; @@ -221,9 +215,9 @@ static void vdisk_backend_test(struct kunit *test) f->block_flush_result = p->error; f->sysfs_sync = true; - /* Exercise the existing store callback with an unregistered private device. */ - ret = vdisk_sysfs_sync_store(&f->dev.dev_kobj, NULL, "1", 1); - KUNIT_EXPECT_EQ(test, ret, p->expected ? p->expected : 1); + /* Keep task-scoped backend stubs in the test thread on this private device. */ + ret = vdisk_flush_backend(&f->dev); + KUNIT_EXPECT_EQ(test, ret, p->expected); /* Empty files may still need metadata synchronization. */ if (!p->empty) KUNIT_EXPECT_EQ(test, f->flush_count, p->files); diff --git a/scst/src/dev_handlers/scst_vdisk_main.c b/scst/src/dev_handlers/scst_vdisk_main.c index 3d7007c75..da454d624 100644 --- a/scst/src/dev_handlers/scst_vdisk_main.c +++ b/scst/src/dev_handlers/scst_vdisk_main.c @@ -7492,24 +7492,72 @@ out_e_unlock: goto out_resume; } +/* + * For a live device, the caller must suspend activity and hold scst_mutex + * and the ALUA lock to prevent the backend from being closed or reopened. + */ SCST_KUNIT_VISIBLE -ssize_t vdisk_sysfs_sync_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) +int vdisk_flush_backend(struct scst_device *dev) { - struct scst_device *dev = - container_of(kobj, struct scst_device, dev_kobj); struct scst_vdisk_dev *virt_dev = dev->dh_priv; + + /* Queued work can outlive removal of the handler's sysfs files. */ + if (!virt_dev) + return -ENODEV; + if (virt_dev->nullio) + return 0; + if (!vdisk_is_open(virt_dev)) + return -ENOMEDIUM; + if (virt_dev->blockio) + return vdisk_blockio_flush(virt_dev->bdev_desc.bdev, GFP_KERNEL, false, + NULL, false); + + return __vdisk_fsync_fileio(0, i_size_read(file_inode(virt_dev->fd)), + dev, NULL, virt_dev->fd); +} + +static int vdisk_sysfs_process_sync_store(struct scst_sysfs_work_item *work) +{ + struct scst_device *dev = work->dev; int res; - if (virt_dev->nullio) - res = 0; - else if (virt_dev->blockio) - res = vdisk_blockio_flush(virt_dev->bdev_desc.bdev, GFP_KERNEL, false, NULL, - false); - else - res = __vdisk_fsync_fileio(0, i_size_read(file_inode(virt_dev->fd)), - dev, NULL, virt_dev->fd); + /* MODE SELECT and task management can also reopen the backing file. */ + res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); + if (res) + goto out; + res = mutex_lock_interruptible(&scst_mutex); + if (res) + goto resume; + + /* Serialize with target detach, activation and ALUA state changes. */ + scst_alua_lock(); + res = vdisk_flush_backend(dev); + scst_alua_unlock(); + mutex_unlock(&scst_mutex); +resume: + scst_resume_activity(); +out: + kobject_put(&dev->dev_kobj); + return res; +} + +static ssize_t vdisk_sysfs_sync_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, dev_kobj); + struct scst_sysfs_work_item *work; + int res; + + res = scst_alloc_sysfs_work(vdisk_sysfs_process_sync_store, false, &work); + if (res) + return res; + + work->dev = dev; + SCST_SET_DEP_MAP(work, &scst_dev_dep_map); + kobject_get(&dev->dev_kobj); + + res = scst_sysfs_queue_wait_work(work); return res ? : count; } diff --git a/scst/src/dev_handlers/scst_vdisk_test.h b/scst/src/dev_handlers/scst_vdisk_test.h index d4327c605..902e07fe1 100644 --- a/scst/src/dev_handlers/scst_vdisk_test.h +++ b/scst/src/dev_handlers/scst_vdisk_test.h @@ -19,8 +19,7 @@ void vdisk_on_free_cmd_params(const struct vdisk_cmd_params *p); enum compl_status_e vdisk_exec_sai_16(struct vdisk_cmd_params *p); enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p); enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p); -ssize_t vdisk_sysfs_sync_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count); +int vdisk_flush_backend(struct scst_device *dev); #endif /* SCST_KUNIT_ENABLED */ #endif /* SCST_VDISK_TEST_H */