fb76ffc4431e3d1367f174b02b6a2abc9e158252
[openwrt/staging/wigyori.git] /
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
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 Signed-off-by: Richard Weinberger <richard@nod.at>
16 ---
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(-)
23
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);
29
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);
33
34 /* "Show" method for files in '/<sysfs>/class/ubi/' */
35 @@ -259,6 +259,9 @@ struct ubi_device *ubi_get_device(int ub
36
37 spin_lock(&ubi_devices_lock);
38 ubi = ubi_devices[ubi_num];
39 + if (ubi && ubi->is_dead)
40 + ubi = NULL;
41 +
42 if (ubi) {
43 ubi_assert(ubi->ref_count >= 0);
44 ubi->ref_count += 1;
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++) {
48 ubi = ubi_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);
52 ubi->ref_count += 1;
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];
57
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;
61 break;
62 }
63 @@ -512,7 +515,7 @@ static void ubi_free_volumes_from(struct
64 int i;
65
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)
69 continue;
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
73 return -EINVAL;
74
75 spin_lock(&ubi_devices_lock);
76 - put_device(&ubi->dev);
77 ubi->ref_count -= 1;
78 if (ubi->ref_count) {
79 if (!anyway) {
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);
83 }
84 + ubi->is_dead = true;
85 + spin_unlock(&ubi_devices_lock);
86 +
87 + ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
88 +
89 + spin_lock(&ubi_devices_lock);
90 + put_device(&ubi->dev);
91 ubi_devices[ubi_num] = NULL;
92 spin_unlock(&ubi_devices_lock);
93
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(
97
98 spin_lock(&ubi->volumes_lock);
99 vol = ubi->volumes[vol_id];
100 - if (!vol)
101 + if (!vol || vol->is_dead)
102 goto out_unlock;
103
104 err = -EBUSY;
105 --- a/drivers/mtd/ubi/ubi.h
106 +++ b/drivers/mtd/ubi/ubi.h
107 @@ -345,6 +345,7 @@ struct ubi_volume {
108 int writers;
109 int exclusive;
110 int metaonly;
111 + bool is_dead;
112
113 int reserved_pebs;
114 int vol_type;
115 @@ -564,6 +565,7 @@ struct ubi_device {
116 spinlock_t volumes_lock;
117 int ref_count;
118 int image_seq;
119 + bool is_dead;
120
121 int rsvd_pebs;
122 int avail_pebs;
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;
127
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);
132 return -ENODEV;
133 }
134 @@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
135
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_
144 err = -EBUSY;
145 goto out_unlock;
146 }
147 +
148 + /*
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.
153 + */
154 + vol->is_dead = true;
155 + spin_unlock(&ubi->volumes_lock);
156 +
157 + ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
158 +
159 + spin_lock(&ubi->volumes_lock);
160 ubi->volumes[vol_id] = NULL;
161 spin_unlock(&ubi->volumes_lock);
162
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
171 *
172 * These constants define which type of event has happened when a volume
173 @@ -202,6 +203,7 @@ enum {
174 UBI_VOLUME_REMOVED,
175 UBI_VOLUME_RESIZED,
176 UBI_VOLUME_RENAMED,
177 + UBI_VOLUME_SHUTDOWN,
178 UBI_VOLUME_UPDATED,
179 };
180