2024-06-14 15:24:12 +00:00
|
|
|
From 924731fbed3247e3b82b8ab17db587ee28c2e781 Mon Sep 17 00:00:00 2001
|
2024-01-03 11:57:28 +00:00
|
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
2024-06-14 15:24:12 +00:00
|
|
|
Date: Tue, 19 Dec 2023 02:33:24 +0000
|
|
|
|
Subject: [PATCH 5/8] mtd: ubi: introduce pre-removal notification for UBI
|
2024-01-03 11:57:28 +00:00
|
|
|
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>
|
2024-06-14 15:24:12 +00:00
|
|
|
Signed-off-by: Richard Weinberger <richard@nod.at>
|
2024-01-03 11:57:28 +00:00
|
|
|
---
|
2024-06-14 15:24:12 +00:00
|
|
|
drivers/mtd/ubi/build.c | 19 ++++++++++++++-----
|
2024-01-03 11:57:28 +00:00
|
|
|
drivers/mtd/ubi/kapi.c | 2 +-
|
|
|
|
drivers/mtd/ubi/ubi.h | 2 ++
|
|
|
|
drivers/mtd/ubi/vmt.c | 17 +++++++++++++++--
|
|
|
|
include/linux/mtd/ubi.h | 2 ++
|
2024-06-14 15:24:12 +00:00
|
|
|
5 files changed, 34 insertions(+), 8 deletions(-)
|
2024-01-03 11:57:28 +00:00
|
|
|
|
|
|
|
--- a/drivers/mtd/ubi/build.c
|
|
|
|
+++ b/drivers/mtd/ubi/build.c
|
2024-03-08 14:04:14 +00:00
|
|
|
@@ -91,7 +91,7 @@ static struct ubi_device *ubi_devices[UB
|
2024-01-03 11:57:28 +00:00
|
|
|
/* 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/' */
|
2024-03-08 14:04:14 +00:00
|
|
|
@@ -259,6 +259,9 @@ struct ubi_device *ubi_get_device(int ub
|
2024-01-03 11:57:28 +00:00
|
|
|
|
|
|
|
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;
|
2024-03-08 14:04:14 +00:00
|
|
|
@@ -296,7 +299,7 @@ struct ubi_device *ubi_get_by_major(int
|
2024-01-03 11:57:28 +00:00
|
|
|
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);
|
2024-03-08 14:04:14 +00:00
|
|
|
@@ -325,7 +328,7 @@ int ubi_major2num(int major)
|
2024-01-03 11:57:28 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-03-08 14:04:14 +00:00
|
|
|
@@ -512,7 +515,7 @@ static void ubi_free_volumes_from(struct
|
2024-01-03 11:57:28 +00:00
|
|
|
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]);
|
2024-06-14 15:24:12 +00:00
|
|
|
@@ -1094,7 +1097,6 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
2024-01-03 11:57:28 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
spin_lock(&ubi_devices_lock);
|
|
|
|
- put_device(&ubi->dev);
|
|
|
|
ubi->ref_count -= 1;
|
|
|
|
if (ubi->ref_count) {
|
|
|
|
if (!anyway) {
|
2024-06-14 15:24:12 +00:00
|
|
|
@@ -1105,6 +1107,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
|
2024-01-03 11:57:28 +00:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|