Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
that a volume is just about to be removed.
This is needed because users (such as the NVMEM subsystem) expect that
at the time their removal function is called, the parenting device is
still available (for removal of sysfs nodes, for example, in case of
NVMEM which otherwise WARNs on volume removal).
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
drivers/mtd/ubi/build.c | 7 ++++++-
drivers/mtd/ubi/vmt.c | 5 +++++
include/linux/mtd/ubi.h | 2 ++
4 files changed, 39 insertions(+), 1 deletion(-)
@@ -533,6 +533,29 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
return 0;
}
+static int ubiblock_shutdown(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ struct gendisk *disk;
+ int ret = 0;
+
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+ disk = dev->gd;
+
+out_unlock:
+ mutex_unlock(&devices_mutex);
+
+ if (!ret)
+ blk_mark_disk_dead(disk);
+
+ return ret;
+};
+
static bool
match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
{
@@ -624,6 +647,9 @@ static int ubiblock_notify(struct notifier_block *nb,
case UBI_VOLUME_REMOVED:
ubiblock_remove(&nt->vi, true);
break;
+ case UBI_VOLUME_SHUTDOWN:
+ ubiblock_shutdown(&nt->vi);
+ break;
case UBI_VOLUME_RESIZED:
ubiblock_resize(&nt->vi);
break;
@@ -1088,7 +1088,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
return -EINVAL;
spin_lock(&ubi_devices_lock);
- put_device(&ubi->dev);
ubi->ref_count -= 1;
if (ubi->ref_count) {
if (!anyway) {
@@ -1099,6 +1098,12 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
ubi_err(ubi, "%s reference count %d, destroy anyway",
ubi->ubi_name, ubi->ref_count);
}
+ spin_unlock(&ubi_devices_lock);
+
+ ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
+
+ spin_lock(&ubi_devices_lock);
+ put_device(&ubi->dev);
ubi_devices[ubi_num] = NULL;
spin_unlock(&ubi_devices_lock);
@@ -352,6 +352,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
err = -EBUSY;
goto out_unlock;
}
+ spin_unlock(&ubi->volumes_lock);
+
+ ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
+
+ spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
@@ -192,6 +192,7 @@ struct ubi_device_info {
* or a volume was removed)
* @UBI_VOLUME_RESIZED: a volume has been re-sized
* @UBI_VOLUME_RENAMED: a volume has been re-named
+ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
* @UBI_VOLUME_UPDATED: data has been written to a volume
*
* These constants define which type of event has happened when a volume
@@ -202,6 +203,7 @@ enum {
UBI_VOLUME_REMOVED,
UBI_VOLUME_RESIZED,
UBI_VOLUME_RENAMED,
+ UBI_VOLUME_SHUTDOWN,
UBI_VOLUME_UPDATED,
};