mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
fc153aa8d9
Similar to supporting nvmem-layouts on MTD devices, also allow referencing UBI and MMC devices in DT. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
227 lines
6.5 KiB
Diff
227 lines
6.5 KiB
Diff
From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Thu, 8 Jun 2023 17:18:09 +0100
|
|
Subject: [PATCH 05/15] mtd: ubi: introduce pre-removal notification for UBI
|
|
volumes
|
|
|
|
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 | 20 +++++++++++++++-----
|
|
drivers/mtd/ubi/kapi.c | 2 +-
|
|
drivers/mtd/ubi/ubi.h | 2 ++
|
|
drivers/mtd/ubi/vmt.c | 17 +++++++++++++++--
|
|
include/linux/mtd/ubi.h | 2 ++
|
|
6 files changed, 61 insertions(+), 8 deletions(-)
|
|
|
|
--- a/drivers/mtd/ubi/block.c
|
|
+++ b/drivers/mtd/ubi/block.c
|
|
@@ -568,6 +568,29 @@ static int ubiblock_resize(struct ubi_vo
|
|
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)
|
|
{
|
|
@@ -659,6 +682,9 @@ static int ubiblock_notify(struct notifi
|
|
case UBI_VOLUME_REMOVED:
|
|
ubiblock_remove(&nt->vi);
|
|
break;
|
|
+ case UBI_VOLUME_SHUTDOWN:
|
|
+ ubiblock_shutdown(&nt->vi);
|
|
+ break;
|
|
case UBI_VOLUME_RESIZED:
|
|
ubiblock_resize(&nt->vi);
|
|
break;
|
|
--- a/drivers/mtd/ubi/build.c
|
|
+++ b/drivers/mtd/ubi/build.c
|
|
@@ -89,7 +89,7 @@ static struct ubi_device *ubi_devices[UB
|
|
/* Serializes UBI devices creations and removals */
|
|
DEFINE_MUTEX(ubi_devices_mutex);
|
|
|
|
-/* Protects @ubi_devices and @ubi->ref_count */
|
|
+/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
|
|
static DEFINE_SPINLOCK(ubi_devices_lock);
|
|
|
|
/* "Show" method for files in '/<sysfs>/class/ubi/' */
|
|
@@ -258,6 +258,9 @@ struct ubi_device *ubi_get_device(int ub
|
|
|
|
spin_lock(&ubi_devices_lock);
|
|
ubi = ubi_devices[ubi_num];
|
|
+ if (ubi && ubi->is_dead)
|
|
+ ubi = NULL;
|
|
+
|
|
if (ubi) {
|
|
ubi_assert(ubi->ref_count >= 0);
|
|
ubi->ref_count += 1;
|
|
@@ -295,7 +298,7 @@ struct ubi_device *ubi_get_by_major(int
|
|
spin_lock(&ubi_devices_lock);
|
|
for (i = 0; i < UBI_MAX_DEVICES; i++) {
|
|
ubi = ubi_devices[i];
|
|
- if (ubi && MAJOR(ubi->cdev.dev) == major) {
|
|
+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
|
|
ubi_assert(ubi->ref_count >= 0);
|
|
ubi->ref_count += 1;
|
|
get_device(&ubi->dev);
|
|
@@ -324,7 +327,7 @@ int ubi_major2num(int major)
|
|
for (i = 0; i < UBI_MAX_DEVICES; i++) {
|
|
struct ubi_device *ubi = ubi_devices[i];
|
|
|
|
- if (ubi && MAJOR(ubi->cdev.dev) == major) {
|
|
+ if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
|
|
ubi_num = ubi->ubi_num;
|
|
break;
|
|
}
|
|
@@ -511,7 +514,7 @@ static void ubi_free_volumes_from(struct
|
|
int i;
|
|
|
|
for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
|
|
- if (!ubi->volumes[i])
|
|
+ if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
|
|
continue;
|
|
ubi_eba_replace_table(ubi->volumes[i], NULL);
|
|
ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
|
|
@@ -1094,10 +1097,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
|
return -EINVAL;
|
|
|
|
spin_lock(&ubi_devices_lock);
|
|
- put_device(&ubi->dev);
|
|
ubi->ref_count -= 1;
|
|
if (ubi->ref_count) {
|
|
if (!anyway) {
|
|
+ ubi->ref_count += 1;
|
|
spin_unlock(&ubi_devices_lock);
|
|
return -EBUSY;
|
|
}
|
|
@@ -1105,6 +1108,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
|
ubi_err(ubi, "%s reference count %d, destroy anyway",
|
|
ubi->ubi_name, ubi->ref_count);
|
|
}
|
|
+ ubi->is_dead = true;
|
|
+ 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);
|
|
|
|
--- a/drivers/mtd/ubi/kapi.c
|
|
+++ b/drivers/mtd/ubi/kapi.c
|
|
@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
|
|
|
|
spin_lock(&ubi->volumes_lock);
|
|
vol = ubi->volumes[vol_id];
|
|
- if (!vol)
|
|
+ if (!vol || vol->is_dead)
|
|
goto out_unlock;
|
|
|
|
err = -EBUSY;
|
|
--- a/drivers/mtd/ubi/ubi.h
|
|
+++ b/drivers/mtd/ubi/ubi.h
|
|
@@ -345,6 +345,7 @@ struct ubi_volume {
|
|
int writers;
|
|
int exclusive;
|
|
int metaonly;
|
|
+ bool is_dead;
|
|
|
|
int reserved_pebs;
|
|
int vol_type;
|
|
@@ -564,6 +565,7 @@ struct ubi_device {
|
|
spinlock_t volumes_lock;
|
|
int ref_count;
|
|
int image_seq;
|
|
+ bool is_dead;
|
|
|
|
int rsvd_pebs;
|
|
int avail_pebs;
|
|
--- a/drivers/mtd/ubi/vmt.c
|
|
+++ b/drivers/mtd/ubi/vmt.c
|
|
@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
|
|
struct ubi_device *ubi = vol->ubi;
|
|
|
|
spin_lock(&ubi->volumes_lock);
|
|
- if (!ubi->volumes[vol->vol_id]) {
|
|
+ if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
|
|
spin_unlock(&ubi->volumes_lock);
|
|
return -ENODEV;
|
|
}
|
|
@@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
|
|
|
|
/* Ensure that the name is unique */
|
|
for (i = 0; i < ubi->vtbl_slots; i++)
|
|
- if (ubi->volumes[i] &&
|
|
+ if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
|
|
ubi->volumes[i]->name_len == req->name_len &&
|
|
!strcmp(ubi->volumes[i]->name, req->name)) {
|
|
ubi_err(ubi, "volume \"%s\" exists (ID %d)",
|
|
@@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
|
|
err = -EBUSY;
|
|
goto out_unlock;
|
|
}
|
|
+
|
|
+ /*
|
|
+ * Mark volume as dead at this point to prevent that anyone
|
|
+ * can take a reference to the volume from now on.
|
|
+ * This is necessary as we have to release the spinlock before
|
|
+ * calling ubi_volume_notify.
|
|
+ */
|
|
+ vol->is_dead = true;
|
|
+ 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);
|
|
|
|
--- a/include/linux/mtd/ubi.h
|
|
+++ b/include/linux/mtd/ubi.h
|
|
@@ -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,
|
|
};
|
|
|