Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dmitry Pervushin and committed by
Artem Bityutskiy
2ba3d76a 518ceef0

+294 -97
+7 -6
drivers/mtd/ubi/Kconfig
··· 49 49 reserved. Leave the default value if unsure. 50 50 51 51 config MTD_UBI_GLUEBI 52 - bool "Emulate MTD devices" 52 + tristate "MTD devices emulation driver (gluebi)" 53 53 default n 54 54 depends on MTD_UBI 55 55 help 56 - This option enables MTD devices emulation on top of UBI volumes: for 57 - each UBI volumes an MTD device is created, and all I/O to this MTD 58 - device is redirected to the UBI volume. This is handy to make 59 - MTD-oriented software (like JFFS2) work on top of UBI. Do not enable 60 - this if no legacy software will be used. 56 + This option enables gluebi - an additional driver which emulates MTD 57 + devices on top of UBI volumes: for each UBI volumes an MTD device is 58 + created, and all I/O to this MTD device is redirected to the UBI 59 + volume. This is handy to make MTD-oriented software (like JFFS2) 60 + work on top of UBI. Do not enable this unless you use legacy 61 + software. 61 62 62 63 source "drivers/mtd/ubi/Kconfig.debug" 63 64 endmenu
+1 -1
drivers/mtd/ubi/Makefile
··· 4 4 ubi-y += misc.o 5 5 6 6 ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o 7 - ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o 7 + obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+286 -90
drivers/mtd/ubi/gluebi.c
··· 19 19 */ 20 20 21 21 /* 22 - * This file includes implementation of fake MTD devices for each UBI volume. 23 - * This sounds strange, but it is in fact quite useful to make MTD-oriented 24 - * software (including all the legacy software) to work on top of UBI. 22 + * This is a small driver which implements fake MTD devices on top of UBI 23 + * volumes. This sounds strange, but it is in fact quite useful to make 24 + * MTD-oriented software (including all the legacy software) work on top of 25 + * UBI. 25 26 * 26 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 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 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 89 * gluebi_get_device - get MTD device reference. ··· 95 41 */ 96 42 static int gluebi_get_device(struct mtd_info *mtd) 97 43 { 98 - struct ubi_volume *vol; 44 + struct gluebi_device *gluebi; 45 + int ubi_mode = UBI_READONLY; 99 46 100 - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 47 + if (!try_module_get(THIS_MODULE)) 48 + return -ENODEV; 101 49 102 - /* 103 - * We do not introduce locks for gluebi reference count because the 104 - * get_device()/put_device() calls are already serialized at MTD. 105 - */ 106 - if (vol->gluebi_refcount > 0) { 50 + if (mtd->flags & MTD_WRITEABLE) 51 + ubi_mode = UBI_READWRITE; 52 + 53 + gluebi = container_of(mtd, struct gluebi_device, mtd); 54 + mutex_lock(&devices_mutex); 55 + if (gluebi->refcnt > 0) { 107 56 /* 108 57 * The MTD device is already referenced and this is just one 109 58 * more reference. MTD allows many users to open the same ··· 115 58 * open the UBI volume again - just increase the reference 116 59 * counter and return. 117 60 */ 118 - vol->gluebi_refcount += 1; 61 + gluebi->refcnt += 1; 62 + mutex_unlock(&devices_mutex); 119 63 return 0; 120 64 } 121 65 ··· 124 66 * This is the first reference to this UBI volume via the MTD device 125 67 * interface. Open the corresponding volume in read-write mode. 126 68 */ 127 - vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id, 128 - UBI_READWRITE); 129 - if (IS_ERR(vol->gluebi_desc)) 130 - return PTR_ERR(vol->gluebi_desc); 131 - vol->gluebi_refcount += 1; 69 + gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id, 70 + ubi_mode); 71 + if (IS_ERR(gluebi->desc)) { 72 + mutex_unlock(&devices_mutex); 73 + module_put(THIS_MODULE); 74 + return PTR_ERR(gluebi->desc); 75 + } 76 + gluebi->refcnt += 1; 77 + mutex_unlock(&devices_mutex); 132 78 return 0; 133 79 } 134 80 ··· 145 83 */ 146 84 static void gluebi_put_device(struct mtd_info *mtd) 147 85 { 148 - struct ubi_volume *vol; 86 + struct gluebi_device *gluebi; 149 87 150 - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 151 - vol->gluebi_refcount -= 1; 152 - ubi_assert(vol->gluebi_refcount >= 0); 153 - if (vol->gluebi_refcount == 0) 154 - ubi_close_volume(vol->gluebi_desc); 88 + gluebi = container_of(mtd, struct gluebi_device, mtd); 89 + mutex_lock(&devices_mutex); 90 + gluebi->refcnt -= 1; 91 + if (gluebi->refcnt == 0) 92 + ubi_close_volume(gluebi->desc); 93 + module_put(THIS_MODULE); 94 + mutex_unlock(&devices_mutex); 155 95 } 156 96 157 97 /** ··· 171 107 size_t *retlen, unsigned char *buf) 172 108 { 173 109 int err = 0, lnum, offs, total_read; 174 - struct ubi_volume *vol; 175 - struct ubi_device *ubi; 176 - 177 - dbg_gen("read %zd bytes from offset %lld", len, from); 110 + struct gluebi_device *gluebi; 178 111 179 112 if (len < 0 || from < 0 || from + len > mtd->size) 180 113 return -EINVAL; 181 114 182 - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 183 - ubi = vol->ubi; 115 + gluebi = container_of(mtd, struct gluebi_device, mtd); 184 116 185 117 lnum = div_u64_rem(from, mtd->erasesize, &offs); 186 118 total_read = len; ··· 186 126 if (to_read > total_read) 187 127 to_read = total_read; 188 128 189 - err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); 129 + err = ubi_read(gluebi->desc, lnum, buf, offs, to_read); 190 130 if (err) 191 131 break; 192 132 ··· 212 152 * case of failure. 213 153 */ 214 154 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, 215 - size_t *retlen, const u_char *buf) 155 + size_t *retlen, const u_char *buf) 216 156 { 217 157 int err = 0, lnum, offs, total_written; 218 - struct ubi_volume *vol; 219 - struct ubi_device *ubi; 220 - 221 - dbg_gen("write %zd bytes to offset %lld", len, to); 158 + struct gluebi_device *gluebi; 222 159 223 160 if (len < 0 || to < 0 || len + to > mtd->size) 224 161 return -EINVAL; 225 162 226 - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 227 - ubi = vol->ubi; 163 + gluebi = container_of(mtd, struct gluebi_device, mtd); 228 164 229 - if (ubi->ro_mode) 165 + if (!(mtd->flags & MTD_WRITEABLE)) 230 166 return -EROFS; 231 167 232 168 lnum = div_u64_rem(to, mtd->erasesize, &offs); ··· 237 181 if (to_write > total_written) 238 182 to_write = total_written; 239 183 240 - err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, 241 - UBI_UNKNOWN); 184 + err = ubi_write(gluebi->desc, lnum, buf, offs, to_write); 242 185 if (err) 243 186 break; 244 187 ··· 262 207 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) 263 208 { 264 209 int err, i, lnum, count; 265 - struct ubi_volume *vol; 266 - struct ubi_device *ubi; 267 - 268 - dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, 269 - (unsigned long long)instr->addr); 210 + struct gluebi_device *gluebi; 270 211 271 212 if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) 272 213 return -EINVAL; 273 - 274 214 if (instr->len < 0 || instr->addr + instr->len > mtd->size) 275 215 return -EINVAL; 276 - 277 216 if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) 278 217 return -EINVAL; 279 218 280 219 lnum = mtd_div_by_eb(instr->addr, mtd); 281 220 count = mtd_div_by_eb(instr->len, mtd); 282 221 283 - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 284 - ubi = vol->ubi; 222 + gluebi = container_of(mtd, struct gluebi_device, mtd); 285 223 286 - if (ubi->ro_mode) 224 + if (!(mtd->flags & MTD_WRITEABLE)) 287 225 return -EROFS; 288 226 289 - for (i = 0; i < count; i++) { 290 - err = ubi_eba_unmap_leb(ubi, vol, lnum + i); 227 + for (i = 0; i < count - 1; i++) { 228 + err = ubi_leb_unmap(gluebi->desc, lnum + i); 291 229 if (err) 292 230 goto out_err; 293 231 } 294 - 295 232 /* 296 233 * MTD erase operations are synchronous, so we have to make sure the 297 234 * physical eraseblock is wiped out. 235 + * 236 + * Thus, perform leb_erase instead of leb_unmap operation - leb_erase 237 + * will wait for the end of operations 298 238 */ 299 - err = ubi_wl_flush(ubi); 239 + err = ubi_leb_erase(gluebi->desc, lnum + i); 300 240 if (err) 301 241 goto out_err; 302 242 ··· 306 256 } 307 257 308 258 /** 309 - * ubi_create_gluebi - initialize gluebi for an UBI volume. 310 - * @ubi: UBI device description object 311 - * @vol: volume description object 259 + * gluebi_create - create a gluebi device for an UBI volume. 260 + * @di: UBI device description object 261 + * @vi: UBI volume description object 312 262 * 313 - * This function is called when an UBI volume is created in order to create 263 + * This function is called when a new UBI volume is created in order to create 314 264 * corresponding fake MTD device. Returns zero in case of success and a 315 265 * negative error code in case of failure. 316 266 */ 317 - int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) 267 + static int gluebi_create(struct ubi_device_info *di, 268 + struct ubi_volume_info *vi) 318 269 { 319 - struct mtd_info *mtd = &vol->gluebi_mtd; 270 + struct gluebi_device *gluebi, *g; 271 + struct mtd_info *mtd; 320 272 321 - mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL); 322 - if (!mtd->name) 273 + gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL); 274 + if (!gluebi) 323 275 return -ENOMEM; 324 276 277 + mtd = &gluebi->mtd; 278 + mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL); 279 + if (!mtd->name) { 280 + kfree(gluebi); 281 + return -ENOMEM; 282 + } 283 + 284 + gluebi->vol_id = vi->vol_id; 325 285 mtd->type = MTD_UBIVOLUME; 326 - if (!ubi->ro_mode) 286 + if (!di->ro_mode) 327 287 mtd->flags = MTD_WRITEABLE; 328 - mtd->writesize = ubi->min_io_size; 329 288 mtd->owner = THIS_MODULE; 330 - mtd->erasesize = vol->usable_leb_size; 289 + mtd->writesize = di->min_io_size; 290 + mtd->erasesize = vi->usable_leb_size; 331 291 mtd->read = gluebi_read; 332 292 mtd->write = gluebi_write; 333 293 mtd->erase = gluebi_erase; ··· 345 285 mtd->put_device = gluebi_put_device; 346 286 347 287 /* 348 - * In case of dynamic volume, MTD device size is just volume size. In 288 + * In case of dynamic a volume, MTD device size is just volume size. In 349 289 * case of a static volume the size is equivalent to the amount of data 350 290 * bytes. 351 291 */ 352 - if (vol->vol_type == UBI_DYNAMIC_VOLUME) 353 - mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs; 292 + if (vi->vol_type == UBI_DYNAMIC_VOLUME) 293 + mtd->size = (unsigned long long)vi->usable_leb_size * vi->size; 354 294 else 355 - mtd->size = vol->used_bytes; 295 + mtd->size = vi->used_bytes; 296 + 297 + /* Just a sanity check - make sure this gluebi device does not exist */ 298 + mutex_lock(&devices_mutex); 299 + g = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 300 + if (g) 301 + err_msg("gluebi MTD device %d form UBI device %d volume %d " 302 + "already exists", g->mtd.index, vi->ubi_num, 303 + vi->vol_id); 304 + mutex_unlock(&devices_mutex); 356 305 357 306 if (add_mtd_device(mtd)) { 358 - ubi_err("cannot not add MTD device"); 307 + err_msg("cannot add MTD device"); 359 308 kfree(mtd->name); 309 + kfree(gluebi); 360 310 return -ENFILE; 361 311 } 362 312 363 - dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u", 364 - mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize); 313 + mutex_lock(&devices_mutex); 314 + list_add_tail(&gluebi->list, &gluebi_devices); 315 + mutex_unlock(&devices_mutex); 365 316 return 0; 366 317 } 367 318 368 319 /** 369 - * ubi_destroy_gluebi - close gluebi for an UBI volume. 370 - * @vol: volume description object 320 + * gluebi_remove - remove a gluebi device. 321 + * @vi: UBI volume description object 371 322 * 372 - * This function is called when an UBI volume is removed in order to remove 323 + * This function is called when an UBI volume is removed and it removes 373 324 * corresponding fake MTD device. Returns zero in case of success and a 374 325 * negative error code in case of failure. 375 326 */ 376 - int ubi_destroy_gluebi(struct ubi_volume *vol) 327 + static int gluebi_remove(struct ubi_volume_info *vi) 377 328 { 378 - int err; 379 - struct mtd_info *mtd = &vol->gluebi_mtd; 329 + int err = 0; 330 + struct mtd_info *mtd; 331 + struct gluebi_device *gluebi; 380 332 381 - dbg_gen("remove mtd%d", mtd->index); 382 - err = del_mtd_device(mtd); 333 + mutex_lock(&devices_mutex); 334 + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 335 + if (!gluebi) { 336 + err_msg("got remove notification for unknown UBI device %d " 337 + "volume %d", vi->ubi_num, vi->vol_id); 338 + err = -ENOENT; 339 + } else if (gluebi->refcnt) 340 + err = -EBUSY; 341 + else 342 + list_del(&gluebi->list); 343 + mutex_unlock(&devices_mutex); 383 344 if (err) 384 345 return err; 346 + 347 + mtd = &gluebi->mtd; 348 + err = del_mtd_device(mtd); 349 + if (err) { 350 + err_msg("cannot remove fake MTD device %d, UBI device %d, " 351 + "volume %d, error %d", mtd->index, gluebi->ubi_num, 352 + gluebi->vol_id, err); 353 + mutex_lock(&devices_mutex); 354 + list_add_tail(&gluebi->list, &gluebi_devices); 355 + mutex_unlock(&devices_mutex); 356 + return err; 357 + } 358 + 385 359 kfree(mtd->name); 360 + kfree(gluebi); 386 361 return 0; 387 362 } 388 363 389 364 /** 390 - * ubi_gluebi_updated - UBI volume was updated notifier. 391 - * @vol: volume description object 365 + * gluebi_updated - UBI volume was updated notifier. 366 + * @vi: volume info structure 392 367 * 393 - * This function is called every time an UBI volume is updated. This function 394 - * does nothing if volume @vol is dynamic, and changes MTD device size if the 368 + * This function is called every time an UBI volume is updated. It does nothing 369 + * if te volume @vol is dynamic, and changes MTD device size if the 395 370 * volume is static. This is needed because static volumes cannot be read past 396 - * data they contain. 371 + * data they contain. This function returns zero in case of success and a 372 + * negative error code in case of error. 397 373 */ 398 - void ubi_gluebi_updated(struct ubi_volume *vol) 374 + static int gluebi_updated(struct ubi_volume_info *vi) 399 375 { 400 - struct mtd_info *mtd = &vol->gluebi_mtd; 376 + struct gluebi_device *gluebi; 401 377 402 - if (vol->vol_type == UBI_STATIC_VOLUME) 403 - mtd->size = vol->used_bytes; 378 + mutex_lock(&devices_mutex); 379 + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 380 + if (!gluebi) { 381 + mutex_unlock(&devices_mutex); 382 + err_msg("got update notification for unknown UBI device %d " 383 + "volume %d", vi->ubi_num, vi->vol_id); 384 + return -ENOENT; 385 + } 386 + 387 + if (vi->vol_type == UBI_STATIC_VOLUME) 388 + gluebi->mtd.size = vi->used_bytes; 389 + mutex_unlock(&devices_mutex); 390 + return 0; 404 391 } 392 + 393 + /** 394 + * gluebi_resized - UBI volume was re-sized notifier. 395 + * @vi: volume info structure 396 + * 397 + * This function is called every time an UBI volume is re-size. It changes the 398 + * corresponding fake MTD device size. This function returns zero in case of 399 + * success and a negative error code in case of error. 400 + */ 401 + static int gluebi_resized(struct ubi_volume_info *vi) 402 + { 403 + struct gluebi_device *gluebi; 404 + 405 + mutex_lock(&devices_mutex); 406 + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 407 + if (!gluebi) { 408 + mutex_unlock(&devices_mutex); 409 + err_msg("got update notification for unknown UBI device %d " 410 + "volume %d", vi->ubi_num, vi->vol_id); 411 + return -ENOENT; 412 + } 413 + gluebi->mtd.size = vi->used_bytes; 414 + mutex_unlock(&devices_mutex); 415 + return 0; 416 + } 417 + 418 + /** 419 + * gluebi_notify - UBI notification handler. 420 + * @nb: registered notifier block 421 + * @l: notification type 422 + * @ptr: pointer to the &struct ubi_notification object 423 + */ 424 + static int gluebi_notify(struct notifier_block *nb, unsigned long l, 425 + void *ns_ptr) 426 + { 427 + struct ubi_notification *nt = ns_ptr; 428 + 429 + switch (l) { 430 + case UBI_VOLUME_ADDED: 431 + gluebi_create(&nt->di, &nt->vi); 432 + break; 433 + case UBI_VOLUME_REMOVED: 434 + gluebi_remove(&nt->vi); 435 + break; 436 + case UBI_VOLUME_RESIZED: 437 + gluebi_resized(&nt->vi); 438 + break; 439 + case UBI_VOLUME_UPDATED: 440 + gluebi_updated(&nt->vi); 441 + break; 442 + default: 443 + break; 444 + } 445 + return NOTIFY_OK; 446 + } 447 + 448 + static struct notifier_block gluebi_notifier = { 449 + .notifier_call = gluebi_notify, 450 + }; 451 + 452 + static int __init ubi_gluebi_init(void) 453 + { 454 + return ubi_register_volume_notifier(&gluebi_notifier, 0); 455 + } 456 + 457 + static void __exit ubi_gluebi_exit(void) 458 + { 459 + struct gluebi_device *gluebi, *g; 460 + 461 + list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) { 462 + int err; 463 + struct mtd_info *mtd = &gluebi->mtd; 464 + 465 + err = del_mtd_device(mtd); 466 + if (err) 467 + err_msg("error %d while removing gluebi MTD device %d, " 468 + "UBI device %d, volume %d - ignoring", err, 469 + mtd->index, gluebi->ubi_num, gluebi->vol_id); 470 + kfree(mtd->name); 471 + kfree(gluebi); 472 + } 473 + ubi_unregister_volume_notifier(&gluebi_notifier); 474 + } 475 + 476 + module_init(ubi_gluebi_init); 477 + module_exit(ubi_gluebi_exit); 478 + MODULE_DESCRIPTION("MTD emulation layer over UBI volumes"); 479 + MODULE_AUTHOR("Artem Bityutskiy, Joern Engel"); 480 + MODULE_LICENSE("GPL");