1 From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001
2 From: Daniel Golle <daniel@makrotopia.org>
3 Date: Thu, 8 Jun 2023 17:18:09 +0100
4 Subject: [PATCH 05/15] 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>
16 drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
17 drivers/mtd/ubi/build.c | 20 +++++++++++++++-----
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 6 files changed, 61 insertions(+), 8 deletions(-)
24 --- a/drivers/mtd/ubi/block.c
25 +++ b/drivers/mtd/ubi/block.c
26 @@ -533,6 +533,29 @@ static int ubiblock_resize(struct ubi_vo
30 +static int ubiblock_shutdown(struct ubi_volume_info *vi)
32 + struct ubiblock *dev;
33 + struct gendisk *disk;
36 + mutex_lock(&devices_mutex);
37 + dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
45 + mutex_unlock(&devices_mutex);
48 + blk_mark_disk_dead(disk);
54 match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
56 @@ -624,6 +647,9 @@ static int ubiblock_notify(struct notifi
57 case UBI_VOLUME_REMOVED:
58 ubiblock_remove(&nt->vi);
60 + case UBI_VOLUME_SHUTDOWN:
61 + ubiblock_shutdown(&nt->vi);
63 case UBI_VOLUME_RESIZED:
64 ubiblock_resize(&nt->vi);
66 --- a/drivers/mtd/ubi/build.c
67 +++ b/drivers/mtd/ubi/build.c
68 @@ -91,7 +91,7 @@ static struct ubi_device *ubi_devices[UB
69 /* Serializes UBI devices creations and removals */
70 DEFINE_MUTEX(ubi_devices_mutex);
72 -/* Protects @ubi_devices and @ubi->ref_count */
73 +/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
74 static DEFINE_SPINLOCK(ubi_devices_lock);
76 /* "Show" method for files in '/<sysfs>/class/ubi/' */
77 @@ -259,6 +259,9 @@ struct ubi_device *ubi_get_device(int ub
79 spin_lock(&ubi_devices_lock);
80 ubi = ubi_devices[ubi_num];
81 + if (ubi && ubi->is_dead)
85 ubi_assert(ubi->ref_count >= 0);
87 @@ -296,7 +299,7 @@ struct ubi_device *ubi_get_by_major(int
88 spin_lock(&ubi_devices_lock);
89 for (i = 0; i < UBI_MAX_DEVICES; i++) {
91 - if (ubi && MAJOR(ubi->cdev.dev) == major) {
92 + if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
93 ubi_assert(ubi->ref_count >= 0);
95 get_device(&ubi->dev);
96 @@ -325,7 +328,7 @@ int ubi_major2num(int major)
97 for (i = 0; i < UBI_MAX_DEVICES; i++) {
98 struct ubi_device *ubi = ubi_devices[i];
100 - if (ubi && MAJOR(ubi->cdev.dev) == major) {
101 + if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
102 ubi_num = ubi->ubi_num;
105 @@ -512,7 +515,7 @@ static void ubi_free_volumes_from(struct
108 for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
109 - if (!ubi->volumes[i])
110 + if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
112 ubi_eba_replace_table(ubi->volumes[i], NULL);
113 ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
114 @@ -1095,10 +1098,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
117 spin_lock(&ubi_devices_lock);
118 - put_device(&ubi->dev);
120 if (ubi->ref_count) {
122 + ubi->ref_count += 1;
123 spin_unlock(&ubi_devices_lock);
126 @@ -1106,6 +1109,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
127 ubi_err(ubi, "%s reference count %d, destroy anyway",
128 ubi->ubi_name, ubi->ref_count);
130 + ubi->is_dead = true;
131 + spin_unlock(&ubi_devices_lock);
133 + ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
135 + spin_lock(&ubi_devices_lock);
136 + put_device(&ubi->dev);
137 ubi_devices[ubi_num] = NULL;
138 spin_unlock(&ubi_devices_lock);
140 --- a/drivers/mtd/ubi/kapi.c
141 +++ b/drivers/mtd/ubi/kapi.c
142 @@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
144 spin_lock(&ubi->volumes_lock);
145 vol = ubi->volumes[vol_id];
147 + if (!vol || vol->is_dead)
151 --- a/drivers/mtd/ubi/ubi.h
152 +++ b/drivers/mtd/ubi/ubi.h
153 @@ -345,6 +345,7 @@ struct ubi_volume {
161 @@ -564,6 +565,7 @@ struct ubi_device {
162 spinlock_t volumes_lock;
169 --- a/drivers/mtd/ubi/vmt.c
170 +++ b/drivers/mtd/ubi/vmt.c
171 @@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
172 struct ubi_device *ubi = vol->ubi;
174 spin_lock(&ubi->volumes_lock);
175 - if (!ubi->volumes[vol->vol_id]) {
176 + if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
177 spin_unlock(&ubi->volumes_lock);
180 @@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
182 /* Ensure that the name is unique */
183 for (i = 0; i < ubi->vtbl_slots; i++)
184 - if (ubi->volumes[i] &&
185 + if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
186 ubi->volumes[i]->name_len == req->name_len &&
187 !strcmp(ubi->volumes[i]->name, req->name)) {
188 ubi_err(ubi, "volume \"%s\" exists (ID %d)",
189 @@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
195 + * Mark volume as dead at this point to prevent that anyone
196 + * can take a reference to the volume from now on.
197 + * This is necessary as we have to release the spinlock before
198 + * calling ubi_volume_notify.
200 + vol->is_dead = true;
201 + spin_unlock(&ubi->volumes_lock);
203 + ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
205 + spin_lock(&ubi->volumes_lock);
206 ubi->volumes[vol_id] = NULL;
207 spin_unlock(&ubi->volumes_lock);
209 --- a/include/linux/mtd/ubi.h
210 +++ b/include/linux/mtd/ubi.h
211 @@ -192,6 +192,7 @@ struct ubi_device_info {
212 * or a volume was removed)
213 * @UBI_VOLUME_RESIZED: a volume has been re-sized
214 * @UBI_VOLUME_RENAMED: a volume has been re-named
215 + * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
216 * @UBI_VOLUME_UPDATED: data has been written to a volume
218 * These constants define which type of event has happened when a volume
219 @@ -202,6 +203,7 @@ enum {
223 + UBI_VOLUME_SHUTDOWN,