kernel: nvmem: correctly assign fwnode to MMC block device
[openwrt/openwrt.git] / target / linux / generic / pending-6.1 / 450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch
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
5 volumes
6
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).
13
14 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
15 ---
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(-)
23
24 --- a/drivers/mtd/ubi/block.c
25 +++ b/drivers/mtd/ubi/block.c
26 @@ -568,6 +568,29 @@ static int ubiblock_resize(struct ubi_vo
27 return 0;
28 }
29
30 +static int ubiblock_shutdown(struct ubi_volume_info *vi)
31 +{
32 + struct ubiblock *dev;
33 + struct gendisk *disk;
34 + int ret = 0;
35 +
36 + mutex_lock(&devices_mutex);
37 + dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
38 + if (!dev) {
39 + ret = -ENODEV;
40 + goto out_unlock;
41 + }
42 + disk = dev->gd;
43 +
44 +out_unlock:
45 + mutex_unlock(&devices_mutex);
46 +
47 + if (!ret)
48 + blk_mark_disk_dead(disk);
49 +
50 + return ret;
51 +};
52 +
53 static bool
54 match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
55 {
56 @@ -659,6 +682,9 @@ static int ubiblock_notify(struct notifi
57 case UBI_VOLUME_REMOVED:
58 ubiblock_remove(&nt->vi);
59 break;
60 + case UBI_VOLUME_SHUTDOWN:
61 + ubiblock_shutdown(&nt->vi);
62 + break;
63 case UBI_VOLUME_RESIZED:
64 ubiblock_resize(&nt->vi);
65 break;
66 --- a/drivers/mtd/ubi/build.c
67 +++ b/drivers/mtd/ubi/build.c
68 @@ -89,7 +89,7 @@ static struct ubi_device *ubi_devices[UB
69 /* Serializes UBI devices creations and removals */
70 DEFINE_MUTEX(ubi_devices_mutex);
71
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);
75
76 /* "Show" method for files in '/<sysfs>/class/ubi/' */
77 @@ -258,6 +258,9 @@ struct ubi_device *ubi_get_device(int ub
78
79 spin_lock(&ubi_devices_lock);
80 ubi = ubi_devices[ubi_num];
81 + if (ubi && ubi->is_dead)
82 + ubi = NULL;
83 +
84 if (ubi) {
85 ubi_assert(ubi->ref_count >= 0);
86 ubi->ref_count += 1;
87 @@ -295,7 +298,7 @@ struct ubi_device *ubi_get_by_major(int
88 spin_lock(&ubi_devices_lock);
89 for (i = 0; i < UBI_MAX_DEVICES; i++) {
90 ubi = ubi_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);
94 ubi->ref_count += 1;
95 get_device(&ubi->dev);
96 @@ -324,7 +327,7 @@ int ubi_major2num(int major)
97 for (i = 0; i < UBI_MAX_DEVICES; i++) {
98 struct ubi_device *ubi = ubi_devices[i];
99
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;
103 break;
104 }
105 @@ -511,7 +514,7 @@ static void ubi_free_volumes_from(struct
106 int i;
107
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)
111 continue;
112 ubi_eba_replace_table(ubi->volumes[i], NULL);
113 ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
114 @@ -1094,10 +1097,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
115 return -EINVAL;
116
117 spin_lock(&ubi_devices_lock);
118 - put_device(&ubi->dev);
119 ubi->ref_count -= 1;
120 if (ubi->ref_count) {
121 if (!anyway) {
122 + ubi->ref_count += 1;
123 spin_unlock(&ubi_devices_lock);
124 return -EBUSY;
125 }
126 @@ -1105,6 +1108,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);
129 }
130 + ubi->is_dead = true;
131 + spin_unlock(&ubi_devices_lock);
132 +
133 + ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
134 +
135 + spin_lock(&ubi_devices_lock);
136 + put_device(&ubi->dev);
137 ubi_devices[ubi_num] = NULL;
138 spin_unlock(&ubi_devices_lock);
139
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(
143
144 spin_lock(&ubi->volumes_lock);
145 vol = ubi->volumes[vol_id];
146 - if (!vol)
147 + if (!vol || vol->is_dead)
148 goto out_unlock;
149
150 err = -EBUSY;
151 --- a/drivers/mtd/ubi/ubi.h
152 +++ b/drivers/mtd/ubi/ubi.h
153 @@ -345,6 +345,7 @@ struct ubi_volume {
154 int writers;
155 int exclusive;
156 int metaonly;
157 + bool is_dead;
158
159 int reserved_pebs;
160 int vol_type;
161 @@ -564,6 +565,7 @@ struct ubi_device {
162 spinlock_t volumes_lock;
163 int ref_count;
164 int image_seq;
165 + bool is_dead;
166
167 int rsvd_pebs;
168 int avail_pebs;
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;
173
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);
178 return -ENODEV;
179 }
180 @@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
181
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_
190 err = -EBUSY;
191 goto out_unlock;
192 }
193 +
194 + /*
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.
199 + */
200 + vol->is_dead = true;
201 + spin_unlock(&ubi->volumes_lock);
202 +
203 + ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
204 +
205 + spin_lock(&ubi->volumes_lock);
206 ubi->volumes[vol_id] = NULL;
207 spin_unlock(&ubi->volumes_lock);
208
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
217 *
218 * These constants define which type of event has happened when a volume
219 @@ -202,6 +203,7 @@ enum {
220 UBI_VOLUME_REMOVED,
221 UBI_VOLUME_RESIZED,
222 UBI_VOLUME_RENAMED,
223 + UBI_VOLUME_SHUTDOWN,
224 UBI_VOLUME_UPDATED,
225 };
226