1 From 924731fbed3247e3b82b8ab17db587ee28c2e781 Mon Sep 17 00:00:00 2001
2 From: Daniel Golle <daniel@makrotopia.org>
3 Date: Tue, 19 Dec 2023 02:33:24 +0000
4 Subject: [PATCH 5/8] mtd: ubi: introduce pre-removal notification for UBI
7 Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
8 that a volume is just about to be removed.
9 This is needed because users (such as the NVMEM subsystem) expect that
10 at the time their removal function is called, the parenting device is
11 still available (for removal of sysfs nodes, for example, in case of
12 NVMEM which otherwise WARNs on volume removal).
14 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
15 Signed-off-by: Richard Weinberger <richard@nod.at>
17 drivers/mtd/ubi/build.c | 19 ++++++++++++++-----
18 drivers/mtd/ubi/kapi.c | 2 +-
19 drivers/mtd/ubi/ubi.h | 2 ++
20 drivers/mtd/ubi/vmt.c | 17 +++++++++++++++--
21 include/linux/mtd/ubi.h | 2 ++
22 5 files changed, 34 insertions(+), 8 deletions(-)
24 --- a/drivers/mtd/ubi/build.c
25 +++ b/drivers/mtd/ubi/build.c
26 @@ -91,7 +91,7 @@ static struct ubi_device *ubi_devices[UB
27 /* Serializes UBI devices creations and removals */
28 DEFINE_MUTEX(ubi_devices_mutex);
30 -/* Protects @ubi_devices and @ubi->ref_count */
31 +/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
32 static DEFINE_SPINLOCK(ubi_devices_lock);
34 /* "Show" method for files in '/<sysfs>/class/ubi/' */
35 @@ -259,6 +259,9 @@ struct ubi_device *ubi_get_device(int ub
37 spin_lock(&ubi_devices_lock);
38 ubi = ubi_devices[ubi_num];
39 + if (ubi && ubi->is_dead)
43 ubi_assert(ubi->ref_count >= 0);
45 @@ -296,7 +299,7 @@ struct ubi_device *ubi_get_by_major(int
46 spin_lock(&ubi_devices_lock);
47 for (i = 0; i < UBI_MAX_DEVICES; i++) {
49 - if (ubi && MAJOR(ubi->cdev.dev) == major) {
50 + if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
51 ubi_assert(ubi->ref_count >= 0);
53 get_device(&ubi->dev);
54 @@ -325,7 +328,7 @@ int ubi_major2num(int major)
55 for (i = 0; i < UBI_MAX_DEVICES; i++) {
56 struct ubi_device *ubi = ubi_devices[i];
58 - if (ubi && MAJOR(ubi->cdev.dev) == major) {
59 + if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
60 ubi_num = ubi->ubi_num;
63 @@ -512,7 +515,7 @@ static void ubi_free_volumes_from(struct
66 for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
67 - if (!ubi->volumes[i])
68 + if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
70 ubi_eba_replace_table(ubi->volumes[i], NULL);
71 ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
72 @@ -1094,7 +1097,6 @@ int ubi_detach_mtd_dev(int ubi_num, int
75 spin_lock(&ubi_devices_lock);
76 - put_device(&ubi->dev);
80 @@ -1105,6 +1107,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
81 ubi_err(ubi, "%s reference count %d, destroy anyway",
82 ubi->ubi_name, ubi->ref_count);
84 + ubi->is_dead = true;
85 + spin_unlock(&ubi_devices_lock);
87 + ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
89 + spin_lock(&ubi_devices_lock);
90 + put_device(&ubi->dev);
91 ubi_devices[ubi_num] = NULL;
92 spin_unlock(&ubi_devices_lock);
94 --- a/drivers/mtd/ubi/kapi.c
95 +++ b/drivers/mtd/ubi/kapi.c
96 @@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
98 spin_lock(&ubi->volumes_lock);
99 vol = ubi->volumes[vol_id];
101 + if (!vol || vol->is_dead)
105 --- a/drivers/mtd/ubi/ubi.h
106 +++ b/drivers/mtd/ubi/ubi.h
107 @@ -345,6 +345,7 @@ struct ubi_volume {
115 @@ -564,6 +565,7 @@ struct ubi_device {
116 spinlock_t volumes_lock;
123 --- a/drivers/mtd/ubi/vmt.c
124 +++ b/drivers/mtd/ubi/vmt.c
125 @@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
126 struct ubi_device *ubi = vol->ubi;
128 spin_lock(&ubi->volumes_lock);
129 - if (!ubi->volumes[vol->vol_id]) {
130 + if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
131 spin_unlock(&ubi->volumes_lock);
134 @@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
136 /* Ensure that the name is unique */
137 for (i = 0; i < ubi->vtbl_slots; i++)
138 - if (ubi->volumes[i] &&
139 + if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
140 ubi->volumes[i]->name_len == req->name_len &&
141 !strcmp(ubi->volumes[i]->name, req->name)) {
142 ubi_err(ubi, "volume \"%s\" exists (ID %d)",
143 @@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
149 + * Mark volume as dead at this point to prevent that anyone
150 + * can take a reference to the volume from now on.
151 + * This is necessary as we have to release the spinlock before
152 + * calling ubi_volume_notify.
154 + vol->is_dead = true;
155 + spin_unlock(&ubi->volumes_lock);
157 + ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
159 + spin_lock(&ubi->volumes_lock);
160 ubi->volumes[vol_id] = NULL;
161 spin_unlock(&ubi->volumes_lock);
163 --- a/include/linux/mtd/ubi.h
164 +++ b/include/linux/mtd/ubi.h
165 @@ -192,6 +192,7 @@ struct ubi_device_info {
166 * or a volume was removed)
167 * @UBI_VOLUME_RESIZED: a volume has been re-sized
168 * @UBI_VOLUME_RENAMED: a volume has been re-named
169 + * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
170 * @UBI_VOLUME_UPDATED: data has been written to a volume
172 * These constants define which type of event has happened when a volume
173 @@ -202,6 +203,7 @@ enum {
177 + UBI_VOLUME_SHUTDOWN,