diff options
author | Dmitry Pervushin <dpervushin@embeddedalley.com> | 2009-05-31 10:32:59 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-06-03 10:45:23 -0400 |
commit | 2ba3d76a1e29f2ba64fbc762875cf9fb2d4ba2ba (patch) | |
tree | 633d48cb740534827b2a764c74e7b423415c0774 /drivers/mtd | |
parent | 518ceef0c9ca97023e45ae46aedaefa240c690a6 (diff) |
UBI: make gluebi a separate module
[Artem: re-worked the patch: made it release resources when the
module is unloaded, made it do module referencing, made it really
independent on UBI, tested it with the UBI test-suite which can
be found in ubi-2.6.git/tests/ubi-tests, re-named most of the
funcs/variables to get rid of the "ubi" word and make names
consistent.]
Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mtd/ubi/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/gluebi.c | 378 |
3 files changed, 295 insertions, 98 deletions
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 3f063108e95f..b1cd7a1a2191 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig | |||
@@ -49,15 +49,16 @@ config MTD_UBI_BEB_RESERVE | |||
49 | reserved. Leave the default value if unsure. | 49 | reserved. Leave the default value if unsure. |
50 | 50 | ||
51 | config MTD_UBI_GLUEBI | 51 | config MTD_UBI_GLUEBI |
52 | bool "Emulate MTD devices" | 52 | tristate "MTD devices emulation driver (gluebi)" |
53 | default n | 53 | default n |
54 | depends on MTD_UBI | 54 | depends on MTD_UBI |
55 | help | 55 | help |
56 | This option enables MTD devices emulation on top of UBI volumes: for | 56 | This option enables gluebi - an additional driver which emulates MTD |
57 | each UBI volumes an MTD device is created, and all I/O to this MTD | 57 | devices on top of UBI volumes: for each UBI volumes an MTD device is |
58 | device is redirected to the UBI volume. This is handy to make | 58 | created, and all I/O to this MTD device is redirected to the UBI |
59 | MTD-oriented software (like JFFS2) work on top of UBI. Do not enable | 59 | volume. This is handy to make MTD-oriented software (like JFFS2) |
60 | this if no legacy software will be used. | 60 | work on top of UBI. Do not enable this unless you use legacy |
61 | software. | ||
61 | 62 | ||
62 | source "drivers/mtd/ubi/Kconfig.debug" | 63 | source "drivers/mtd/ubi/Kconfig.debug" |
63 | endmenu | 64 | endmenu |
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index dd834e04151b..c9302a5452b0 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile | |||
@@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o | |||
4 | ubi-y += misc.o | 4 | ubi-y += misc.o |
5 | 5 | ||
6 | ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o | 6 | ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o |
7 | ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o | 7 | obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o |
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 49cd55ade9c8..95aaac03f938 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c | |||
@@ -19,17 +19,71 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * This file includes implementation of fake MTD devices for each UBI volume. | 22 | * This is a small driver which implements fake MTD devices on top of UBI |
23 | * This sounds strange, but it is in fact quite useful to make MTD-oriented | 23 | * volumes. This sounds strange, but it is in fact quite useful to make |
24 | * software (including all the legacy software) to work on top of UBI. | 24 | * MTD-oriented software (including all the legacy software) work on top of |
25 | * UBI. | ||
25 | * | 26 | * |
26 | * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit | 27 | * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit |
27 | * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The | 28 | * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The |
28 | * eraseblock size is equivalent to the logical eraseblock size of the volume. | 29 | * eraseblock size is equivalent to the logical eraseblock size of the volume. |
29 | */ | 30 | */ |
30 | 31 | ||
32 | #include <linux/err.h> | ||
33 | #include <linux/list.h> | ||
34 | #include <linux/sched.h> | ||
31 | #include <linux/math64.h> | 35 | #include <linux/math64.h> |
32 | #include "ubi.h" | 36 | #include <linux/module.h> |
37 | #include <linux/mutex.h> | ||
38 | #include <linux/mtd/ubi.h> | ||
39 | #include <linux/mtd/mtd.h> | ||
40 | #include "ubi-media.h" | ||
41 | |||
42 | #define err_msg(fmt, ...) \ | ||
43 | printk(KERN_DEBUG "gluebi (pid %d): %s: " fmt "\n", \ | ||
44 | current->pid, __func__, ##__VA_ARGS__) | ||
45 | |||
46 | /** | ||
47 | * struct gluebi_device - a gluebi device description data structure. | ||
48 | * @mtd: emulated MTD device description object | ||
49 | * @refcnt: gluebi device reference count | ||
50 | * @desc: UBI volume descriptor | ||
51 | * @ubi_num: UBI device number this gluebi device works on | ||
52 | * @vol_id: ID of UBI volume this gluebi device works on | ||
53 | * @list: link in a list of gluebi devices | ||
54 | */ | ||
55 | struct gluebi_device { | ||
56 | struct mtd_info mtd; | ||
57 | int refcnt; | ||
58 | struct ubi_volume_desc *desc; | ||
59 | int ubi_num; | ||
60 | int vol_id; | ||
61 | struct list_head list; | ||
62 | }; | ||
63 | |||
64 | /* List of all gluebi devices */ | ||
65 | static LIST_HEAD(gluebi_devices); | ||
66 | static DEFINE_MUTEX(devices_mutex); | ||
67 | |||
68 | /** | ||
69 | * find_gluebi_nolock - find a gluebi device. | ||
70 | * @ubi_num: UBI device number | ||
71 | * @vol_id: volume ID | ||
72 | * | ||
73 | * This function seraches for gluebi device corresponding to UBI device | ||
74 | * @ubi_num and UBI volume @vol_id. Returns the gluebi device description | ||
75 | * object in case of success and %NULL in case of failure. The caller has to | ||
76 | * have the &devices_mutex locked. | ||
77 | */ | ||
78 | static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id) | ||
79 | { | ||
80 | struct gluebi_device *gluebi; | ||
81 | |||
82 | list_for_each_entry(gluebi, &gluebi_devices, list) | ||
83 | if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id) | ||
84 | return gluebi; | ||
85 | return NULL; | ||
86 | } | ||
33 | 87 | ||
34 | /** | 88 | /** |
35 | * gluebi_get_device - get MTD device reference. | 89 | * gluebi_get_device - get MTD device reference. |
@@ -41,15 +95,18 @@ | |||
41 | */ | 95 | */ |
42 | static int gluebi_get_device(struct mtd_info *mtd) | 96 | static int gluebi_get_device(struct mtd_info *mtd) |
43 | { | 97 | { |
44 | struct ubi_volume *vol; | 98 | struct gluebi_device *gluebi; |
99 | int ubi_mode = UBI_READONLY; | ||
45 | 100 | ||
46 | vol = container_of(mtd, struct ubi_volume, gluebi_mtd); | 101 | if (!try_module_get(THIS_MODULE)) |
102 | return -ENODEV; | ||
47 | 103 | ||
48 | /* | 104 | if (mtd->flags & MTD_WRITEABLE) |
49 | * We do not introduce locks for gluebi reference count because the | 105 | ubi_mode = UBI_READWRITE; |
50 | * get_device()/put_device() calls are already serialized at MTD. | 106 | |
51 | */ | 107 | gluebi = container_of(mtd, struct gluebi_device, mtd); |
52 | if (vol->gluebi_refcount > 0) { | 108 | mutex_lock(&devices_mutex); |
109 | if (gluebi->refcnt > 0) { | ||
53 | /* | 110 | /* |
54 | * The MTD device is already referenced and this is just one | 111 | * The MTD device is already referenced and this is just one |
55 | * more reference. MTD allows many users to open the same | 112 | * more reference. MTD allows many users to open the same |
@@ -58,7 +115,8 @@ static int gluebi_get_device(struct mtd_info *mtd) | |||
58 | * open the UBI volume again - just increase the reference | 115 | * open the UBI volume again - just increase the reference |
59 | * counter and return. | 116 | * counter and return. |
60 | */ | 117 | */ |
61 | vol->gluebi_refcount += 1; | 118 | gluebi->refcnt += 1; |
119 | mutex_unlock(&devices_mutex); | ||
62 | return 0; | 120 | return 0; |
63 | } | 121 | } |
64 | 122 | ||
@@ -66,11 +124,15 @@ static int gluebi_get_device(struct mtd_info *mtd) | |||
66 | * This is the first reference to this UBI volume via the MTD device | 124 | * This is the first reference to this UBI volume via the MTD device |
67 | * interface. Open the corresponding volume in read-write mode. | 125 | * interface. Open the corresponding volume in read-write mode. |
68 | */ | 126 | */ |
69 | vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id, | 127 | gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id, |
70 | UBI_READWRITE); | 128 | ubi_mode); |
71 | if (IS_ERR(vol->gluebi_desc)) | 129 | if (IS_ERR(gluebi->desc)) { |
72 | return PTR_ERR(vol->gluebi_desc); | 130 | mutex_unlock(&devices_mutex); |
73 | vol->gluebi_refcount += 1; | 131 | module_put(THIS_MODULE); |
132 | return PTR_ERR(gluebi->desc); | ||
133 | } | ||
134 | gluebi->refcnt += 1; | ||
135 | mutex_unlock(&devices_mutex); | ||
74 | return 0; | 136 | return 0; |
75 | } | 137 | } |
76 | 138 | ||
@@ -83,13 +145,15 @@ static int gluebi_get_device(struct mtd_info *mtd) | |||
83 | */ | 145 | */ |
84 | static void gluebi_put_device(struct mtd_info *mtd) | 146 | static void gluebi_put_device(struct mtd_info *mtd) |
85 | { | 147 | { |
86 | struct ubi_volume *vol; | 148 | struct gluebi_device *gluebi; |
87 | 149 | ||
88 | vol = container_of(mtd, struct ubi_volume, gluebi_mtd); | 150 | gluebi = container_of(mtd, struct gluebi_device, mtd); |
89 | vol->gluebi_refcount -= 1; | 151 | mutex_lock(&devices_mutex); |
90 | ubi_assert(vol->gluebi_refcount >= 0); | 152 | gluebi->refcnt -= 1; |
91 | if (vol->gluebi_refcount == 0) | 153 | if (gluebi->refcnt == 0) |
92 | ubi_close_volume(vol->gluebi_desc); | 154 | ubi_close_volume(gluebi->desc); |
155 | module_put(THIS_MODULE); | ||
156 | mutex_unlock(&devices_mutex); | ||
93 | } | 157 | } |
94 | 158 | ||
95 | /** | 159 | /** |
@@ -107,16 +171,12 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
107 | size_t *retlen, unsigned char *buf) | 171 | size_t *retlen, unsigned char *buf) |
108 | { | 172 | { |
109 | int err = 0, lnum, offs, total_read; | 173 | int err = 0, lnum, offs, total_read; |
110 | struct ubi_volume *vol; | 174 | struct gluebi_device *gluebi; |
111 | struct ubi_device *ubi; | ||
112 | |||
113 | dbg_gen("read %zd bytes from offset %lld", len, from); | ||
114 | 175 | ||
115 | if (len < 0 || from < 0 || from + len > mtd->size) | 176 | if (len < 0 || from < 0 || from + len > mtd->size) |
116 | return -EINVAL; | 177 | return -EINVAL; |
117 | 178 | ||
118 | vol = container_of(mtd, struct ubi_volume, gluebi_mtd); | 179 | gluebi = container_of(mtd, struct gluebi_device, mtd); |
119 | ubi = vol->ubi; | ||
120 | 180 | ||
121 | lnum = div_u64_rem(from, mtd->erasesize, &offs); | 181 | lnum = div_u64_rem(from, mtd->erasesize, &offs); |
122 | total_read = len; | 182 | total_read = len; |
@@ -126,7 +186,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
126 | if (to_read > total_read) | 186 | if (to_read > total_read) |
127 | to_read = total_read; | 187 | to_read = total_read; |
128 | 188 | ||
129 | err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); | 189 | err = ubi_read(gluebi->desc, lnum, buf, offs, to_read); |
130 | if (err) | 190 | if (err) |
131 | break; | 191 | break; |
132 | 192 | ||
@@ -152,21 +212,17 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
152 | * case of failure. | 212 | * case of failure. |
153 | */ | 213 | */ |
154 | static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, | 214 | static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, |
155 | size_t *retlen, const u_char *buf) | 215 | size_t *retlen, const u_char *buf) |
156 | { | 216 | { |
157 | int err = 0, lnum, offs, total_written; | 217 | int err = 0, lnum, offs, total_written; |
158 | struct ubi_volume *vol; | 218 | struct gluebi_device *gluebi; |
159 | struct ubi_device *ubi; | ||
160 | |||
161 | dbg_gen("write %zd bytes to offset %lld", len, to); | ||
162 | 219 | ||
163 | if (len < 0 || to < 0 || len + to > mtd->size) | 220 | if (len < 0 || to < 0 || len + to > mtd->size) |
164 | return -EINVAL; | 221 | return -EINVAL; |
165 | 222 | ||
166 | vol = container_of(mtd, struct ubi_volume, gluebi_mtd); | 223 | gluebi = container_of(mtd, struct gluebi_device, mtd); |
167 | ubi = vol->ubi; | ||
168 | 224 | ||
169 | if (ubi->ro_mode) | 225 | if (!(mtd->flags & MTD_WRITEABLE)) |
170 | return -EROFS; | 226 | return -EROFS; |
171 | 227 | ||
172 | lnum = div_u64_rem(to, mtd->erasesize, &offs); | 228 | lnum = div_u64_rem(to, mtd->erasesize, &offs); |
@@ -181,8 +237,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
181 | if (to_write > total_written) | 237 | if (to_write > total_written) |
182 | to_write = total_written; | 238 | to_write = total_written; |
183 | 239 | ||
184 | err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, | 240 | err = ubi_write(gluebi->desc, lnum, buf, offs, to_write); |
185 | UBI_UNKNOWN); | ||
186 | if (err) | 241 | if (err) |
187 | break; | 242 | break; |
188 | 243 | ||
@@ -207,41 +262,36 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
207 | static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) | 262 | static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) |
208 | { | 263 | { |
209 | int err, i, lnum, count; | 264 | int err, i, lnum, count; |
210 | struct ubi_volume *vol; | 265 | struct gluebi_device *gluebi; |
211 | struct ubi_device *ubi; | ||
212 | |||
213 | dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, | ||
214 | (unsigned long long)instr->addr); | ||
215 | 266 | ||
216 | if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) | 267 | if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) |
217 | return -EINVAL; | 268 | return -EINVAL; |
218 | |||
219 | if (instr->len < 0 || instr->addr + instr->len > mtd->size) | 269 | if (instr->len < 0 || instr->addr + instr->len > mtd->size) |
220 | return -EINVAL; | 270 | return -EINVAL; |
221 | |||
222 | if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) | 271 | if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) |
223 | return -EINVAL; | 272 | return -EINVAL; |
224 | 273 | ||
225 | lnum = mtd_div_by_eb(instr->addr, mtd); | 274 | lnum = mtd_div_by_eb(instr->addr, mtd); |
226 | count = mtd_div_by_eb(instr->len, mtd); | 275 | count = mtd_div_by_eb(instr->len, mtd); |
227 | 276 | ||
228 | vol = container_of(mtd, struct ubi_volume, gluebi_mtd); | 277 | gluebi = container_of(mtd, struct gluebi_device, mtd); |
229 | ubi = vol->ubi; | ||
230 | 278 | ||
231 | if (ubi->ro_mode) | 279 | if (!(mtd->flags & MTD_WRITEABLE)) |
232 | return -EROFS; | 280 | return -EROFS; |
233 | 281 | ||
234 | for (i = 0; i < count; i++) { | 282 | for (i = 0; i < count - 1; i++) { |
235 | err = ubi_eba_unmap_leb(ubi, vol, lnum + i); | 283 | err = ubi_leb_unmap(gluebi->desc, lnum + i); |
236 | if (err) | 284 | if (err) |
237 | goto out_err; | 285 | goto out_err; |
238 | } | 286 | } |
239 | |||
240 | /* | 287 | /* |
241 | * MTD erase operations are synchronous, so we have to make sure the | 288 | * MTD erase operations are synchronous, so we have to make sure the |
242 | * physical eraseblock is wiped out. | 289 | * physical eraseblock is wiped out. |
290 | * | ||
291 | * Thus, perform leb_erase instead of leb_unmap operation - leb_erase | ||
292 | * will wait for the end of operations | ||
243 | */ | 293 | */ |
244 | err = ubi_wl_flush(ubi); | 294 | err = ubi_leb_erase(gluebi->desc, lnum + i); |
245 | if (err) | 295 | if (err) |
246 | goto out_err; | 296 | goto out_err; |
247 | 297 | ||
@@ -256,28 +306,38 @@ out_err: | |||
256 | } | 306 | } |
257 | 307 | ||
258 | /** | 308 | /** |
259 | * ubi_create_gluebi - initialize gluebi for an UBI volume. | 309 | * gluebi_create - create a gluebi device for an UBI volume. |
260 | * @ubi: UBI device description object | 310 | * @di: UBI device description object |
261 | * @vol: volume description object | 311 | * @vi: UBI volume description object |
262 | * | 312 | * |
263 | * This function is called when an UBI volume is created in order to create | 313 | * This function is called when a new UBI volume is created in order to create |
264 | * corresponding fake MTD device. Returns zero in case of success and a | 314 | * corresponding fake MTD device. Returns zero in case of success and a |
265 | * negative error code in case of failure. | 315 | * negative error code in case of failure. |
266 | */ | 316 | */ |
267 | int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) | 317 | static int gluebi_create(struct ubi_device_info *di, |
318 | struct ubi_volume_info *vi) | ||
268 | { | 319 | { |
269 | struct mtd_info *mtd = &vol->gluebi_mtd; | 320 | struct gluebi_device *gluebi, *g; |
321 | struct mtd_info *mtd; | ||
270 | 322 | ||
271 | mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL); | 323 | gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL); |
272 | if (!mtd->name) | 324 | if (!gluebi) |
273 | return -ENOMEM; | 325 | return -ENOMEM; |
274 | 326 | ||
327 | mtd = &gluebi->mtd; | ||
328 | mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL); | ||
329 | if (!mtd->name) { | ||
330 | kfree(gluebi); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | |||
334 | gluebi->vol_id = vi->vol_id; | ||
275 | mtd->type = MTD_UBIVOLUME; | 335 | mtd->type = MTD_UBIVOLUME; |
276 | if (!ubi->ro_mode) | 336 | if (!di->ro_mode) |
277 | mtd->flags = MTD_WRITEABLE; | 337 | mtd->flags = MTD_WRITEABLE; |
278 | mtd->writesize = ubi->min_io_size; | ||
279 | mtd->owner = THIS_MODULE; | 338 | mtd->owner = THIS_MODULE; |
280 | mtd->erasesize = vol->usable_leb_size; | 339 | mtd->writesize = di->min_io_size; |
340 | mtd->erasesize = vi->usable_leb_size; | ||
281 | mtd->read = gluebi_read; | 341 | mtd->read = gluebi_read; |
282 | mtd->write = gluebi_write; | 342 | mtd->write = gluebi_write; |
283 | mtd->erase = gluebi_erase; | 343 | mtd->erase = gluebi_erase; |
@@ -285,60 +345,196 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) | |||
285 | mtd->put_device = gluebi_put_device; | 345 | mtd->put_device = gluebi_put_device; |
286 | 346 | ||
287 | /* | 347 | /* |
288 | * In case of dynamic volume, MTD device size is just volume size. In | 348 | * In case of dynamic a volume, MTD device size is just volume size. In |
289 | * case of a static volume the size is equivalent to the amount of data | 349 | * case of a static volume the size is equivalent to the amount of data |
290 | * bytes. | 350 | * bytes. |
291 | */ | 351 | */ |
292 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) | 352 | if (vi->vol_type == UBI_DYNAMIC_VOLUME) |
293 | mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs; | 353 | mtd->size = (unsigned long long)vi->usable_leb_size * vi->size; |
294 | else | 354 | else |
295 | mtd->size = vol->used_bytes; | 355 | mtd->size = vi->used_bytes; |
356 | |||
357 | /* Just a sanity check - make sure this gluebi device does not exist */ | ||
358 | mutex_lock(&devices_mutex); | ||
359 | g = find_gluebi_nolock(vi->ubi_num, vi->vol_id); | ||
360 | if (g) | ||
361 | err_msg("gluebi MTD device %d form UBI device %d volume %d " | ||
362 | "already exists", g->mtd.index, vi->ubi_num, | ||
363 | vi->vol_id); | ||
364 | mutex_unlock(&devices_mutex); | ||
296 | 365 | ||
297 | if (add_mtd_device(mtd)) { | 366 | if (add_mtd_device(mtd)) { |
298 | ubi_err("cannot not add MTD device"); | 367 | err_msg("cannot add MTD device"); |
299 | kfree(mtd->name); | 368 | kfree(mtd->name); |
369 | kfree(gluebi); | ||
300 | return -ENFILE; | 370 | return -ENFILE; |
301 | } | 371 | } |
302 | 372 | ||
303 | dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u", | 373 | mutex_lock(&devices_mutex); |
304 | mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize); | 374 | list_add_tail(&gluebi->list, &gluebi_devices); |
375 | mutex_unlock(&devices_mutex); | ||
305 | return 0; | 376 | return 0; |
306 | } | 377 | } |
307 | 378 | ||
308 | /** | 379 | /** |
309 | * ubi_destroy_gluebi - close gluebi for an UBI volume. | 380 | * gluebi_remove - remove a gluebi device. |
310 | * @vol: volume description object | 381 | * @vi: UBI volume description object |
311 | * | 382 | * |
312 | * This function is called when an UBI volume is removed in order to remove | 383 | * This function is called when an UBI volume is removed and it removes |
313 | * corresponding fake MTD device. Returns zero in case of success and a | 384 | * corresponding fake MTD device. Returns zero in case of success and a |
314 | * negative error code in case of failure. | 385 | * negative error code in case of failure. |
315 | */ | 386 | */ |
316 | int ubi_destroy_gluebi(struct ubi_volume *vol) | 387 | static int gluebi_remove(struct ubi_volume_info *vi) |
317 | { | 388 | { |
318 | int err; | 389 | int err = 0; |
319 | struct mtd_info *mtd = &vol->gluebi_mtd; | 390 | struct mtd_info *mtd; |
391 | struct gluebi_device *gluebi; | ||
392 | |||
393 | mutex_lock(&devices_mutex); | ||
394 | gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); | ||
395 | if (!gluebi) { | ||
396 | err_msg("got remove notification for unknown UBI device %d " | ||
397 | "volume %d", vi->ubi_num, vi->vol_id); | ||
398 | err = -ENOENT; | ||
399 | } else if (gluebi->refcnt) | ||
400 | err = -EBUSY; | ||
401 | else | ||
402 | list_del(&gluebi->list); | ||
403 | mutex_unlock(&devices_mutex); | ||
404 | if (err) | ||
405 | return err; | ||
320 | 406 | ||
321 | dbg_gen("remove mtd%d", mtd->index); | 407 | mtd = &gluebi->mtd; |
322 | err = del_mtd_device(mtd); | 408 | err = del_mtd_device(mtd); |
323 | if (err) | 409 | if (err) { |
410 | err_msg("cannot remove fake MTD device %d, UBI device %d, " | ||
411 | "volume %d, error %d", mtd->index, gluebi->ubi_num, | ||
412 | gluebi->vol_id, err); | ||
413 | mutex_lock(&devices_mutex); | ||
414 | list_add_tail(&gluebi->list, &gluebi_devices); | ||
415 | mutex_unlock(&devices_mutex); | ||
324 | return err; | 416 | return err; |
417 | } | ||
418 | |||
325 | kfree(mtd->name); | 419 | kfree(mtd->name); |
420 | kfree(gluebi); | ||
326 | return 0; | 421 | return 0; |
327 | } | 422 | } |
328 | 423 | ||
329 | /** | 424 | /** |
330 | * ubi_gluebi_updated - UBI volume was updated notifier. | 425 | * gluebi_updated - UBI volume was updated notifier. |
331 | * @vol: volume description object | 426 | * @vi: volume info structure |
332 | * | 427 | * |
333 | * This function is called every time an UBI volume is updated. This function | 428 | * This function is called every time an UBI volume is updated. It does nothing |
334 | * does nothing if volume @vol is dynamic, and changes MTD device size if the | 429 | * if te volume @vol is dynamic, and changes MTD device size if the |
335 | * volume is static. This is needed because static volumes cannot be read past | 430 | * volume is static. This is needed because static volumes cannot be read past |
336 | * data they contain. | 431 | * data they contain. This function returns zero in case of success and a |
432 | * negative error code in case of error. | ||
433 | */ | ||
434 | static int gluebi_updated(struct ubi_volume_info *vi) | ||
435 | { | ||
436 | struct gluebi_device *gluebi; | ||
437 | |||
438 | mutex_lock(&devices_mutex); | ||
439 | gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); | ||
440 | if (!gluebi) { | ||
441 | mutex_unlock(&devices_mutex); | ||
442 | err_msg("got update notification for unknown UBI device %d " | ||
443 | "volume %d", vi->ubi_num, vi->vol_id); | ||
444 | return -ENOENT; | ||
445 | } | ||
446 | |||
447 | if (vi->vol_type == UBI_STATIC_VOLUME) | ||
448 | gluebi->mtd.size = vi->used_bytes; | ||
449 | mutex_unlock(&devices_mutex); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | /** | ||
454 | * gluebi_resized - UBI volume was re-sized notifier. | ||
455 | * @vi: volume info structure | ||
456 | * | ||
457 | * This function is called every time an UBI volume is re-size. It changes the | ||
458 | * corresponding fake MTD device size. This function returns zero in case of | ||
459 | * success and a negative error code in case of error. | ||
460 | */ | ||
461 | static int gluebi_resized(struct ubi_volume_info *vi) | ||
462 | { | ||
463 | struct gluebi_device *gluebi; | ||
464 | |||
465 | mutex_lock(&devices_mutex); | ||
466 | gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); | ||
467 | if (!gluebi) { | ||
468 | mutex_unlock(&devices_mutex); | ||
469 | err_msg("got update notification for unknown UBI device %d " | ||
470 | "volume %d", vi->ubi_num, vi->vol_id); | ||
471 | return -ENOENT; | ||
472 | } | ||
473 | gluebi->mtd.size = vi->used_bytes; | ||
474 | mutex_unlock(&devices_mutex); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | /** | ||
479 | * gluebi_notify - UBI notification handler. | ||
480 | * @nb: registered notifier block | ||
481 | * @l: notification type | ||
482 | * @ptr: pointer to the &struct ubi_notification object | ||
337 | */ | 483 | */ |
338 | void ubi_gluebi_updated(struct ubi_volume *vol) | 484 | static int gluebi_notify(struct notifier_block *nb, unsigned long l, |
485 | void *ns_ptr) | ||
339 | { | 486 | { |
340 | struct mtd_info *mtd = &vol->gluebi_mtd; | 487 | struct ubi_notification *nt = ns_ptr; |
488 | |||
489 | switch (l) { | ||
490 | case UBI_VOLUME_ADDED: | ||
491 | gluebi_create(&nt->di, &nt->vi); | ||
492 | break; | ||
493 | case UBI_VOLUME_REMOVED: | ||
494 | gluebi_remove(&nt->vi); | ||
495 | break; | ||
496 | case UBI_VOLUME_RESIZED: | ||
497 | gluebi_resized(&nt->vi); | ||
498 | break; | ||
499 | case UBI_VOLUME_UPDATED: | ||
500 | gluebi_updated(&nt->vi); | ||
501 | break; | ||
502 | default: | ||
503 | break; | ||
504 | } | ||
505 | return NOTIFY_OK; | ||
506 | } | ||
341 | 507 | ||
342 | if (vol->vol_type == UBI_STATIC_VOLUME) | 508 | static struct notifier_block gluebi_notifier = { |
343 | mtd->size = vol->used_bytes; | 509 | .notifier_call = gluebi_notify, |
510 | }; | ||
511 | |||
512 | static int __init ubi_gluebi_init(void) | ||
513 | { | ||
514 | return ubi_register_volume_notifier(&gluebi_notifier, 0); | ||
344 | } | 515 | } |
516 | |||
517 | static void __exit ubi_gluebi_exit(void) | ||
518 | { | ||
519 | struct gluebi_device *gluebi, *g; | ||
520 | |||
521 | list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) { | ||
522 | int err; | ||
523 | struct mtd_info *mtd = &gluebi->mtd; | ||
524 | |||
525 | err = del_mtd_device(mtd); | ||
526 | if (err) | ||
527 | err_msg("error %d while removing gluebi MTD device %d, " | ||
528 | "UBI device %d, volume %d - ignoring", err, | ||
529 | mtd->index, gluebi->ubi_num, gluebi->vol_id); | ||
530 | kfree(mtd->name); | ||
531 | kfree(gluebi); | ||
532 | } | ||
533 | ubi_unregister_volume_notifier(&gluebi_notifier); | ||
534 | } | ||
535 | |||
536 | module_init(ubi_gluebi_init); | ||
537 | module_exit(ubi_gluebi_exit); | ||
538 | MODULE_DESCRIPTION("MTD emulation layer over UBI volumes"); | ||
539 | MODULE_AUTHOR("Artem Bityutskiy, Joern Engel"); | ||
540 | MODULE_LICENSE("GPL"); | ||