gluebi.c (13761B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) International Business Machines Corp., 2006 4 * 5 * Author: Artem Bityutskiy (Битюцкий Артём), Joern Engel 6 */ 7 8/* 9 * This is a small driver which implements fake MTD devices on top of UBI 10 * volumes. This sounds strange, but it is in fact quite useful to make 11 * MTD-oriented software (including all the legacy software) work on top of 12 * UBI. 13 * 14 * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit 15 * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The 16 * eraseblock size is equivalent to the logical eraseblock size of the volume. 17 */ 18 19#include <linux/err.h> 20#include <linux/list.h> 21#include <linux/slab.h> 22#include <linux/sched.h> 23#include <linux/math64.h> 24#include <linux/module.h> 25#include <linux/mutex.h> 26#include <linux/mtd/ubi.h> 27#include <linux/mtd/mtd.h> 28#include "ubi-media.h" 29 30#define err_msg(fmt, ...) \ 31 pr_err("gluebi (pid %d): %s: " fmt "\n", \ 32 current->pid, __func__, ##__VA_ARGS__) 33 34/** 35 * struct gluebi_device - a gluebi device description data structure. 36 * @mtd: emulated MTD device description object 37 * @refcnt: gluebi device reference count 38 * @desc: UBI volume descriptor 39 * @ubi_num: UBI device number this gluebi device works on 40 * @vol_id: ID of UBI volume this gluebi device works on 41 * @list: link in a list of gluebi devices 42 */ 43struct gluebi_device { 44 struct mtd_info mtd; 45 int refcnt; 46 struct ubi_volume_desc *desc; 47 int ubi_num; 48 int vol_id; 49 struct list_head list; 50}; 51 52/* List of all gluebi devices */ 53static LIST_HEAD(gluebi_devices); 54static DEFINE_MUTEX(devices_mutex); 55 56/** 57 * find_gluebi_nolock - find a gluebi device. 58 * @ubi_num: UBI device number 59 * @vol_id: volume ID 60 * 61 * This function seraches for gluebi device corresponding to UBI device 62 * @ubi_num and UBI volume @vol_id. Returns the gluebi device description 63 * object in case of success and %NULL in case of failure. The caller has to 64 * have the &devices_mutex locked. 65 */ 66static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id) 67{ 68 struct gluebi_device *gluebi; 69 70 list_for_each_entry(gluebi, &gluebi_devices, list) 71 if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id) 72 return gluebi; 73 return NULL; 74} 75 76/** 77 * gluebi_get_device - get MTD device reference. 78 * @mtd: the MTD device description object 79 * 80 * This function is called every time the MTD device is being opened and 81 * implements the MTD get_device() operation. Returns zero in case of success 82 * and a negative error code in case of failure. 83 */ 84static int gluebi_get_device(struct mtd_info *mtd) 85{ 86 struct gluebi_device *gluebi; 87 int ubi_mode = UBI_READONLY; 88 89 if (mtd->flags & MTD_WRITEABLE) 90 ubi_mode = UBI_READWRITE; 91 92 gluebi = container_of(mtd, struct gluebi_device, mtd); 93 mutex_lock(&devices_mutex); 94 if (gluebi->refcnt > 0) { 95 /* 96 * The MTD device is already referenced and this is just one 97 * more reference. MTD allows many users to open the same 98 * volume simultaneously and do not distinguish between 99 * readers/writers/exclusive/meta openers as UBI does. So we do 100 * not open the UBI volume again - just increase the reference 101 * counter and return. 102 */ 103 gluebi->refcnt += 1; 104 mutex_unlock(&devices_mutex); 105 return 0; 106 } 107 108 /* 109 * This is the first reference to this UBI volume via the MTD device 110 * interface. Open the corresponding volume in read-write mode. 111 */ 112 gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id, 113 ubi_mode); 114 if (IS_ERR(gluebi->desc)) { 115 mutex_unlock(&devices_mutex); 116 return PTR_ERR(gluebi->desc); 117 } 118 gluebi->refcnt += 1; 119 mutex_unlock(&devices_mutex); 120 return 0; 121} 122 123/** 124 * gluebi_put_device - put MTD device reference. 125 * @mtd: the MTD device description object 126 * 127 * This function is called every time the MTD device is being put. Returns 128 * zero in case of success and a negative error code in case of failure. 129 */ 130static void gluebi_put_device(struct mtd_info *mtd) 131{ 132 struct gluebi_device *gluebi; 133 134 gluebi = container_of(mtd, struct gluebi_device, mtd); 135 mutex_lock(&devices_mutex); 136 gluebi->refcnt -= 1; 137 if (gluebi->refcnt == 0) 138 ubi_close_volume(gluebi->desc); 139 mutex_unlock(&devices_mutex); 140} 141 142/** 143 * gluebi_read - read operation of emulated MTD devices. 144 * @mtd: MTD device description object 145 * @from: absolute offset from where to read 146 * @len: how many bytes to read 147 * @retlen: count of read bytes is returned here 148 * @buf: buffer to store the read data 149 * 150 * This function returns zero in case of success and a negative error code in 151 * case of failure. 152 */ 153static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, 154 size_t *retlen, unsigned char *buf) 155{ 156 int err = 0, lnum, offs, bytes_left; 157 struct gluebi_device *gluebi; 158 159 gluebi = container_of(mtd, struct gluebi_device, mtd); 160 lnum = div_u64_rem(from, mtd->erasesize, &offs); 161 bytes_left = len; 162 while (bytes_left) { 163 size_t to_read = mtd->erasesize - offs; 164 165 if (to_read > bytes_left) 166 to_read = bytes_left; 167 168 err = ubi_read(gluebi->desc, lnum, buf, offs, to_read); 169 if (err) 170 break; 171 172 lnum += 1; 173 offs = 0; 174 bytes_left -= to_read; 175 buf += to_read; 176 } 177 178 *retlen = len - bytes_left; 179 return err; 180} 181 182/** 183 * gluebi_write - write operation of emulated MTD devices. 184 * @mtd: MTD device description object 185 * @to: absolute offset where to write 186 * @len: how many bytes to write 187 * @retlen: count of written bytes is returned here 188 * @buf: buffer with data to write 189 * 190 * This function returns zero in case of success and a negative error code in 191 * case of failure. 192 */ 193static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, 194 size_t *retlen, const u_char *buf) 195{ 196 int err = 0, lnum, offs, bytes_left; 197 struct gluebi_device *gluebi; 198 199 gluebi = container_of(mtd, struct gluebi_device, mtd); 200 lnum = div_u64_rem(to, mtd->erasesize, &offs); 201 202 if (len % mtd->writesize || offs % mtd->writesize) 203 return -EINVAL; 204 205 bytes_left = len; 206 while (bytes_left) { 207 size_t to_write = mtd->erasesize - offs; 208 209 if (to_write > bytes_left) 210 to_write = bytes_left; 211 212 err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write); 213 if (err) 214 break; 215 216 lnum += 1; 217 offs = 0; 218 bytes_left -= to_write; 219 buf += to_write; 220 } 221 222 *retlen = len - bytes_left; 223 return err; 224} 225 226/** 227 * gluebi_erase - erase operation of emulated MTD devices. 228 * @mtd: the MTD device description object 229 * @instr: the erase operation description 230 * 231 * This function calls the erase callback when finishes. Returns zero in case 232 * of success and a negative error code in case of failure. 233 */ 234static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) 235{ 236 int err, i, lnum, count; 237 struct gluebi_device *gluebi; 238 239 if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) 240 return -EINVAL; 241 242 lnum = mtd_div_by_eb(instr->addr, mtd); 243 count = mtd_div_by_eb(instr->len, mtd); 244 gluebi = container_of(mtd, struct gluebi_device, mtd); 245 246 for (i = 0; i < count - 1; i++) { 247 err = ubi_leb_unmap(gluebi->desc, lnum + i); 248 if (err) 249 goto out_err; 250 } 251 /* 252 * MTD erase operations are synchronous, so we have to make sure the 253 * physical eraseblock is wiped out. 254 * 255 * Thus, perform leb_erase instead of leb_unmap operation - leb_erase 256 * will wait for the end of operations 257 */ 258 err = ubi_leb_erase(gluebi->desc, lnum + i); 259 if (err) 260 goto out_err; 261 262 return 0; 263 264out_err: 265 instr->fail_addr = (long long)lnum * mtd->erasesize; 266 return err; 267} 268 269/** 270 * gluebi_create - create a gluebi device for an UBI volume. 271 * @di: UBI device description object 272 * @vi: UBI volume description object 273 * 274 * This function is called when a new UBI volume is created in order to create 275 * corresponding fake MTD device. Returns zero in case of success and a 276 * negative error code in case of failure. 277 */ 278static int gluebi_create(struct ubi_device_info *di, 279 struct ubi_volume_info *vi) 280{ 281 struct gluebi_device *gluebi, *g; 282 struct mtd_info *mtd; 283 284 gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL); 285 if (!gluebi) 286 return -ENOMEM; 287 288 mtd = &gluebi->mtd; 289 mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL); 290 if (!mtd->name) { 291 kfree(gluebi); 292 return -ENOMEM; 293 } 294 295 gluebi->vol_id = vi->vol_id; 296 gluebi->ubi_num = vi->ubi_num; 297 mtd->type = MTD_UBIVOLUME; 298 if (!di->ro_mode) 299 mtd->flags = MTD_WRITEABLE; 300 mtd->owner = THIS_MODULE; 301 mtd->writesize = di->min_io_size; 302 mtd->erasesize = vi->usable_leb_size; 303 mtd->_read = gluebi_read; 304 mtd->_write = gluebi_write; 305 mtd->_erase = gluebi_erase; 306 mtd->_get_device = gluebi_get_device; 307 mtd->_put_device = gluebi_put_device; 308 309 /* 310 * In case of dynamic a volume, MTD device size is just volume size. In 311 * case of a static volume the size is equivalent to the amount of data 312 * bytes. 313 */ 314 if (vi->vol_type == UBI_DYNAMIC_VOLUME) 315 mtd->size = (unsigned long long)vi->usable_leb_size * vi->size; 316 else 317 mtd->size = vi->used_bytes; 318 319 /* Just a sanity check - make sure this gluebi device does not exist */ 320 mutex_lock(&devices_mutex); 321 g = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 322 if (g) 323 err_msg("gluebi MTD device %d form UBI device %d volume %d already exists", 324 g->mtd.index, vi->ubi_num, vi->vol_id); 325 mutex_unlock(&devices_mutex); 326 327 if (mtd_device_register(mtd, NULL, 0)) { 328 err_msg("cannot add MTD device"); 329 kfree(mtd->name); 330 kfree(gluebi); 331 return -ENFILE; 332 } 333 334 mutex_lock(&devices_mutex); 335 list_add_tail(&gluebi->list, &gluebi_devices); 336 mutex_unlock(&devices_mutex); 337 return 0; 338} 339 340/** 341 * gluebi_remove - remove a gluebi device. 342 * @vi: UBI volume description object 343 * 344 * This function is called when an UBI volume is removed and it removes 345 * corresponding fake MTD device. Returns zero in case of success and a 346 * negative error code in case of failure. 347 */ 348static int gluebi_remove(struct ubi_volume_info *vi) 349{ 350 int err = 0; 351 struct mtd_info *mtd; 352 struct gluebi_device *gluebi; 353 354 mutex_lock(&devices_mutex); 355 gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 356 if (!gluebi) { 357 err_msg("got remove notification for unknown UBI device %d volume %d", 358 vi->ubi_num, vi->vol_id); 359 err = -ENOENT; 360 } else if (gluebi->refcnt) 361 err = -EBUSY; 362 else 363 list_del(&gluebi->list); 364 mutex_unlock(&devices_mutex); 365 if (err) 366 return err; 367 368 mtd = &gluebi->mtd; 369 err = mtd_device_unregister(mtd); 370 if (err) { 371 err_msg("cannot remove fake MTD device %d, UBI device %d, volume %d, error %d", 372 mtd->index, gluebi->ubi_num, gluebi->vol_id, err); 373 mutex_lock(&devices_mutex); 374 list_add_tail(&gluebi->list, &gluebi_devices); 375 mutex_unlock(&devices_mutex); 376 return err; 377 } 378 379 kfree(mtd->name); 380 kfree(gluebi); 381 return 0; 382} 383 384/** 385 * gluebi_updated - UBI volume was updated notifier. 386 * @vi: volume info structure 387 * 388 * This function is called every time an UBI volume is updated. It does nothing 389 * if te volume @vol is dynamic, and changes MTD device size if the 390 * volume is static. This is needed because static volumes cannot be read past 391 * data they contain. This function returns zero in case of success and a 392 * negative error code in case of error. 393 */ 394static int gluebi_updated(struct ubi_volume_info *vi) 395{ 396 struct gluebi_device *gluebi; 397 398 mutex_lock(&devices_mutex); 399 gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 400 if (!gluebi) { 401 mutex_unlock(&devices_mutex); 402 err_msg("got update notification for unknown UBI device %d volume %d", 403 vi->ubi_num, vi->vol_id); 404 return -ENOENT; 405 } 406 407 if (vi->vol_type == UBI_STATIC_VOLUME) 408 gluebi->mtd.size = vi->used_bytes; 409 mutex_unlock(&devices_mutex); 410 return 0; 411} 412 413/** 414 * gluebi_resized - UBI volume was re-sized notifier. 415 * @vi: volume info structure 416 * 417 * This function is called every time an UBI volume is re-size. It changes the 418 * corresponding fake MTD device size. This function returns zero in case of 419 * success and a negative error code in case of error. 420 */ 421static int gluebi_resized(struct ubi_volume_info *vi) 422{ 423 struct gluebi_device *gluebi; 424 425 mutex_lock(&devices_mutex); 426 gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); 427 if (!gluebi) { 428 mutex_unlock(&devices_mutex); 429 err_msg("got update notification for unknown UBI device %d volume %d", 430 vi->ubi_num, vi->vol_id); 431 return -ENOENT; 432 } 433 gluebi->mtd.size = vi->used_bytes; 434 mutex_unlock(&devices_mutex); 435 return 0; 436} 437 438/** 439 * gluebi_notify - UBI notification handler. 440 * @nb: registered notifier block 441 * @l: notification type 442 * @ns_ptr: pointer to the &struct ubi_notification object 443 */ 444static int gluebi_notify(struct notifier_block *nb, unsigned long l, 445 void *ns_ptr) 446{ 447 struct ubi_notification *nt = ns_ptr; 448 449 switch (l) { 450 case UBI_VOLUME_ADDED: 451 gluebi_create(&nt->di, &nt->vi); 452 break; 453 case UBI_VOLUME_REMOVED: 454 gluebi_remove(&nt->vi); 455 break; 456 case UBI_VOLUME_RESIZED: 457 gluebi_resized(&nt->vi); 458 break; 459 case UBI_VOLUME_UPDATED: 460 gluebi_updated(&nt->vi); 461 break; 462 default: 463 break; 464 } 465 return NOTIFY_OK; 466} 467 468static struct notifier_block gluebi_notifier = { 469 .notifier_call = gluebi_notify, 470}; 471 472static int __init ubi_gluebi_init(void) 473{ 474 return ubi_register_volume_notifier(&gluebi_notifier, 0); 475} 476 477static void __exit ubi_gluebi_exit(void) 478{ 479 struct gluebi_device *gluebi, *g; 480 481 list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) { 482 int err; 483 struct mtd_info *mtd = &gluebi->mtd; 484 485 err = mtd_device_unregister(mtd); 486 if (err) 487 err_msg("error %d while removing gluebi MTD device %d, UBI device %d, volume %d - ignoring", 488 err, mtd->index, gluebi->ubi_num, 489 gluebi->vol_id); 490 kfree(mtd->name); 491 kfree(gluebi); 492 } 493 ubi_unregister_volume_notifier(&gluebi_notifier); 494} 495 496module_init(ubi_gluebi_init); 497module_exit(ubi_gluebi_exit); 498MODULE_DESCRIPTION("MTD emulation layer over UBI volumes"); 499MODULE_AUTHOR("Artem Bityutskiy, Joern Engel"); 500MODULE_LICENSE("GPL");