diff --git a/scst/include/scst.h b/scst/include/scst.h index 3f6a2e1d1..120df2299 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2892,6 +2892,9 @@ struct scst_device { */ struct percpu_ref refcnt; + /* Triggered when refcnt drops to zero. */ + struct completion *remove_completion; + struct work_struct free_work; /* diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 2ce642255..31c8cb443 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4218,7 +4218,10 @@ static void scst_free_device(struct work_struct *work) static void scst_release_device(struct percpu_ref *ref) { struct scst_device *dev = container_of(ref, typeof(*dev), refcnt); + struct completion *c = dev->remove_completion; + if (c) + complete(c); schedule_work(&dev->free_work); } diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index afc5f9184..b3a00f745 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -1179,6 +1179,7 @@ static void scst_unregister_device(struct scsi_device *scsidp) { struct scst_device *dev; struct scst_acg_dev *acg_dev, *aa; + DECLARE_COMPLETION_ONSTACK(c); TRACE_ENTRY(); @@ -1207,6 +1208,8 @@ static void scst_unregister_device(struct scsi_device *scsidp) scst_acg_del_lun(acg_dev->acg, acg_dev->lun, true); } + dev->remove_completion = &c; + mutex_unlock(&scst_mutex); scst_dev_sysfs_del(dev); @@ -1218,6 +1221,8 @@ static void scst_unregister_device(struct scsi_device *scsidp) percpu_ref_kill(&dev->refcnt); percpu_ref_put(&dev->refcnt); + wait_for_completion(&c); + out: TRACE_EXIT(); return; @@ -1441,6 +1446,7 @@ void scst_unregister_virtual_device(int id, { struct scst_device *d, *dev = NULL; struct scst_acg_dev *acg_dev, *aa; + DECLARE_COMPLETION_ONSTACK(c); TRACE_ENTRY(); @@ -1473,6 +1479,8 @@ void scst_unregister_virtual_device(int id, scst_acg_del_lun(acg_dev->acg, acg_dev->lun, true); } + dev->remove_completion = &c; + mutex_unlock(&scst_mutex); scst_dev_sysfs_del(dev); @@ -1486,6 +1494,8 @@ void scst_unregister_virtual_device(int id, percpu_ref_kill(&dev->refcnt); percpu_ref_put(&dev->refcnt); + wait_for_completion(&c); + out: TRACE_EXIT(); return; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 65a1aa9f6..251587150 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1972,6 +1972,8 @@ static ssize_t __scst_acg_cpu_mask_show(struct scst_acg *acg, char *buf) #endif if (!cpumask_equal(&acg->acg_cpu_mask, &default_cpu_mask)) res += sprintf(&buf[res], "\n%s\n", SCST_SYSFS_KEY_MARK); + else + res += sprintf(&buf[res], "\n"); return res; }