Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) International Business Machines Corp., 2006
0004  *
0005  * Author: Artem Bityutskiy (Битюцкий Артём), Joern Engel
0006  */
0007 
0008 /*
0009  * This is a small driver which implements fake MTD devices on top of UBI
0010  * volumes. This sounds strange, but it is in fact quite useful to make
0011  * MTD-oriented software (including all the legacy software) work on top of
0012  * UBI.
0013  *
0014  * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
0015  * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The
0016  * eraseblock size is equivalent to the logical eraseblock size of the volume.
0017  */
0018 
0019 #include <linux/err.h>
0020 #include <linux/list.h>
0021 #include <linux/slab.h>
0022 #include <linux/sched.h>
0023 #include <linux/math64.h>
0024 #include <linux/module.h>
0025 #include <linux/mutex.h>
0026 #include <linux/mtd/ubi.h>
0027 #include <linux/mtd/mtd.h>
0028 #include "ubi-media.h"
0029 
0030 #define err_msg(fmt, ...)                                   \
0031     pr_err("gluebi (pid %d): %s: " fmt "\n",            \
0032            current->pid, __func__, ##__VA_ARGS__)
0033 
0034 /**
0035  * struct gluebi_device - a gluebi device description data structure.
0036  * @mtd: emulated MTD device description object
0037  * @refcnt: gluebi device reference count
0038  * @desc: UBI volume descriptor
0039  * @ubi_num: UBI device number this gluebi device works on
0040  * @vol_id: ID of UBI volume this gluebi device works on
0041  * @list: link in a list of gluebi devices
0042  */
0043 struct gluebi_device {
0044     struct mtd_info mtd;
0045     int refcnt;
0046     struct ubi_volume_desc *desc;
0047     int ubi_num;
0048     int vol_id;
0049     struct list_head list;
0050 };
0051 
0052 /* List of all gluebi devices */
0053 static LIST_HEAD(gluebi_devices);
0054 static DEFINE_MUTEX(devices_mutex);
0055 
0056 /**
0057  * find_gluebi_nolock - find a gluebi device.
0058  * @ubi_num: UBI device number
0059  * @vol_id: volume ID
0060  *
0061  * This function seraches for gluebi device corresponding to UBI device
0062  * @ubi_num and UBI volume @vol_id. Returns the gluebi device description
0063  * object in case of success and %NULL in case of failure. The caller has to
0064  * have the &devices_mutex locked.
0065  */
0066 static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id)
0067 {
0068     struct gluebi_device *gluebi;
0069 
0070     list_for_each_entry(gluebi, &gluebi_devices, list)
0071         if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id)
0072             return gluebi;
0073     return NULL;
0074 }
0075 
0076 /**
0077  * gluebi_get_device - get MTD device reference.
0078  * @mtd: the MTD device description object
0079  *
0080  * This function is called every time the MTD device is being opened and
0081  * implements the MTD get_device() operation. Returns zero in case of success
0082  * and a negative error code in case of failure.
0083  */
0084 static int gluebi_get_device(struct mtd_info *mtd)
0085 {
0086     struct gluebi_device *gluebi;
0087     int ubi_mode = UBI_READONLY;
0088 
0089     if (mtd->flags & MTD_WRITEABLE)
0090         ubi_mode = UBI_READWRITE;
0091 
0092     gluebi = container_of(mtd, struct gluebi_device, mtd);
0093     mutex_lock(&devices_mutex);
0094     if (gluebi->refcnt > 0) {
0095         /*
0096          * The MTD device is already referenced and this is just one
0097          * more reference. MTD allows many users to open the same
0098          * volume simultaneously and do not distinguish between
0099          * readers/writers/exclusive/meta openers as UBI does. So we do
0100          * not open the UBI volume again - just increase the reference
0101          * counter and return.
0102          */
0103         gluebi->refcnt += 1;
0104         mutex_unlock(&devices_mutex);
0105         return 0;
0106     }
0107 
0108     /*
0109      * This is the first reference to this UBI volume via the MTD device
0110      * interface. Open the corresponding volume in read-write mode.
0111      */
0112     gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id,
0113                        ubi_mode);
0114     if (IS_ERR(gluebi->desc)) {
0115         mutex_unlock(&devices_mutex);
0116         return PTR_ERR(gluebi->desc);
0117     }
0118     gluebi->refcnt += 1;
0119     mutex_unlock(&devices_mutex);
0120     return 0;
0121 }
0122 
0123 /**
0124  * gluebi_put_device - put MTD device reference.
0125  * @mtd: the MTD device description object
0126  *
0127  * This function is called every time the MTD device is being put. Returns
0128  * zero in case of success and a negative error code in case of failure.
0129  */
0130 static void gluebi_put_device(struct mtd_info *mtd)
0131 {
0132     struct gluebi_device *gluebi;
0133 
0134     gluebi = container_of(mtd, struct gluebi_device, mtd);
0135     mutex_lock(&devices_mutex);
0136     gluebi->refcnt -= 1;
0137     if (gluebi->refcnt == 0)
0138         ubi_close_volume(gluebi->desc);
0139     mutex_unlock(&devices_mutex);
0140 }
0141 
0142 /**
0143  * gluebi_read - read operation of emulated MTD devices.
0144  * @mtd: MTD device description object
0145  * @from: absolute offset from where to read
0146  * @len: how many bytes to read
0147  * @retlen: count of read bytes is returned here
0148  * @buf: buffer to store the read data
0149  *
0150  * This function returns zero in case of success and a negative error code in
0151  * case of failure.
0152  */
0153 static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
0154                size_t *retlen, unsigned char *buf)
0155 {
0156     int err = 0, lnum, offs, bytes_left;
0157     struct gluebi_device *gluebi;
0158 
0159     gluebi = container_of(mtd, struct gluebi_device, mtd);
0160     lnum = div_u64_rem(from, mtd->erasesize, &offs);
0161     bytes_left = len;
0162     while (bytes_left) {
0163         size_t to_read = mtd->erasesize - offs;
0164 
0165         if (to_read > bytes_left)
0166             to_read = bytes_left;
0167 
0168         err = ubi_read(gluebi->desc, lnum, buf, offs, to_read);
0169         if (err)
0170             break;
0171 
0172         lnum += 1;
0173         offs = 0;
0174         bytes_left -= to_read;
0175         buf += to_read;
0176     }
0177 
0178     *retlen = len - bytes_left;
0179     return err;
0180 }
0181 
0182 /**
0183  * gluebi_write - write operation of emulated MTD devices.
0184  * @mtd: MTD device description object
0185  * @to: absolute offset where to write
0186  * @len: how many bytes to write
0187  * @retlen: count of written bytes is returned here
0188  * @buf: buffer with data to write
0189  *
0190  * This function returns zero in case of success and a negative error code in
0191  * case of failure.
0192  */
0193 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
0194             size_t *retlen, const u_char *buf)
0195 {
0196     int err = 0, lnum, offs, bytes_left;
0197     struct gluebi_device *gluebi;
0198 
0199     gluebi = container_of(mtd, struct gluebi_device, mtd);
0200     lnum = div_u64_rem(to, mtd->erasesize, &offs);
0201 
0202     if (len % mtd->writesize || offs % mtd->writesize)
0203         return -EINVAL;
0204 
0205     bytes_left = len;
0206     while (bytes_left) {
0207         size_t to_write = mtd->erasesize - offs;
0208 
0209         if (to_write > bytes_left)
0210             to_write = bytes_left;
0211 
0212         err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
0213         if (err)
0214             break;
0215 
0216         lnum += 1;
0217         offs = 0;
0218         bytes_left -= to_write;
0219         buf += to_write;
0220     }
0221 
0222     *retlen = len - bytes_left;
0223     return err;
0224 }
0225 
0226 /**
0227  * gluebi_erase - erase operation of emulated MTD devices.
0228  * @mtd: the MTD device description object
0229  * @instr: the erase operation description
0230  *
0231  * This function calls the erase callback when finishes. Returns zero in case
0232  * of success and a negative error code in case of failure.
0233  */
0234 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
0235 {
0236     int err, i, lnum, count;
0237     struct gluebi_device *gluebi;
0238 
0239     if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
0240         return -EINVAL;
0241 
0242     lnum = mtd_div_by_eb(instr->addr, mtd);
0243     count = mtd_div_by_eb(instr->len, mtd);
0244     gluebi = container_of(mtd, struct gluebi_device, mtd);
0245 
0246     for (i = 0; i < count - 1; i++) {
0247         err = ubi_leb_unmap(gluebi->desc, lnum + i);
0248         if (err)
0249             goto out_err;
0250     }
0251     /*
0252      * MTD erase operations are synchronous, so we have to make sure the
0253      * physical eraseblock is wiped out.
0254      *
0255      * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
0256      * will wait for the end of operations
0257      */
0258     err = ubi_leb_erase(gluebi->desc, lnum + i);
0259     if (err)
0260         goto out_err;
0261 
0262     return 0;
0263 
0264 out_err:
0265     instr->fail_addr = (long long)lnum * mtd->erasesize;
0266     return err;
0267 }
0268 
0269 /**
0270  * gluebi_create - create a gluebi device for an UBI volume.
0271  * @di: UBI device description object
0272  * @vi: UBI volume description object
0273  *
0274  * This function is called when a new UBI volume is created in order to create
0275  * corresponding fake MTD device. Returns zero in case of success and a
0276  * negative error code in case of failure.
0277  */
0278 static int gluebi_create(struct ubi_device_info *di,
0279              struct ubi_volume_info *vi)
0280 {
0281     struct gluebi_device *gluebi, *g;
0282     struct mtd_info *mtd;
0283 
0284     gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL);
0285     if (!gluebi)
0286         return -ENOMEM;
0287 
0288     mtd = &gluebi->mtd;
0289     mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL);
0290     if (!mtd->name) {
0291         kfree(gluebi);
0292         return -ENOMEM;
0293     }
0294 
0295     gluebi->vol_id = vi->vol_id;
0296     gluebi->ubi_num = vi->ubi_num;
0297     mtd->type = MTD_UBIVOLUME;
0298     if (!di->ro_mode)
0299         mtd->flags = MTD_WRITEABLE;
0300     mtd->owner      = THIS_MODULE;
0301     mtd->writesize  = di->min_io_size;
0302     mtd->erasesize  = vi->usable_leb_size;
0303     mtd->_read       = gluebi_read;
0304     mtd->_write      = gluebi_write;
0305     mtd->_erase      = gluebi_erase;
0306     mtd->_get_device = gluebi_get_device;
0307     mtd->_put_device = gluebi_put_device;
0308 
0309     /*
0310      * In case of dynamic a volume, MTD device size is just volume size. In
0311      * case of a static volume the size is equivalent to the amount of data
0312      * bytes.
0313      */
0314     if (vi->vol_type == UBI_DYNAMIC_VOLUME)
0315         mtd->size = (unsigned long long)vi->usable_leb_size * vi->size;
0316     else
0317         mtd->size = vi->used_bytes;
0318 
0319     /* Just a sanity check - make sure this gluebi device does not exist */
0320     mutex_lock(&devices_mutex);
0321     g = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
0322     if (g)
0323         err_msg("gluebi MTD device %d form UBI device %d volume %d already exists",
0324             g->mtd.index, vi->ubi_num, vi->vol_id);
0325     mutex_unlock(&devices_mutex);
0326 
0327     if (mtd_device_register(mtd, NULL, 0)) {
0328         err_msg("cannot add MTD device");
0329         kfree(mtd->name);
0330         kfree(gluebi);
0331         return -ENFILE;
0332     }
0333 
0334     mutex_lock(&devices_mutex);
0335     list_add_tail(&gluebi->list, &gluebi_devices);
0336     mutex_unlock(&devices_mutex);
0337     return 0;
0338 }
0339 
0340 /**
0341  * gluebi_remove - remove a gluebi device.
0342  * @vi: UBI volume description object
0343  *
0344  * This function is called when an UBI volume is removed and it removes
0345  * corresponding fake MTD device. Returns zero in case of success and a
0346  * negative error code in case of failure.
0347  */
0348 static int gluebi_remove(struct ubi_volume_info *vi)
0349 {
0350     int err = 0;
0351     struct mtd_info *mtd;
0352     struct gluebi_device *gluebi;
0353 
0354     mutex_lock(&devices_mutex);
0355     gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
0356     if (!gluebi) {
0357         err_msg("got remove notification for unknown UBI device %d volume %d",
0358             vi->ubi_num, vi->vol_id);
0359         err = -ENOENT;
0360     } else if (gluebi->refcnt)
0361         err = -EBUSY;
0362     else
0363         list_del(&gluebi->list);
0364     mutex_unlock(&devices_mutex);
0365     if (err)
0366         return err;
0367 
0368     mtd = &gluebi->mtd;
0369     err = mtd_device_unregister(mtd);
0370     if (err) {
0371         err_msg("cannot remove fake MTD device %d, UBI device %d, volume %d, error %d",
0372             mtd->index, gluebi->ubi_num, gluebi->vol_id, err);
0373         mutex_lock(&devices_mutex);
0374         list_add_tail(&gluebi->list, &gluebi_devices);
0375         mutex_unlock(&devices_mutex);
0376         return err;
0377     }
0378 
0379     kfree(mtd->name);
0380     kfree(gluebi);
0381     return 0;
0382 }
0383 
0384 /**
0385  * gluebi_updated - UBI volume was updated notifier.
0386  * @vi: volume info structure
0387  *
0388  * This function is called every time an UBI volume is updated. It does nothing
0389  * if te volume @vol is dynamic, and changes MTD device size if the
0390  * volume is static. This is needed because static volumes cannot be read past
0391  * data they contain. This function returns zero in case of success and a
0392  * negative error code in case of error.
0393  */
0394 static int gluebi_updated(struct ubi_volume_info *vi)
0395 {
0396     struct gluebi_device *gluebi;
0397 
0398     mutex_lock(&devices_mutex);
0399     gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
0400     if (!gluebi) {
0401         mutex_unlock(&devices_mutex);
0402         err_msg("got update notification for unknown UBI device %d volume %d",
0403             vi->ubi_num, vi->vol_id);
0404         return -ENOENT;
0405     }
0406 
0407     if (vi->vol_type == UBI_STATIC_VOLUME)
0408         gluebi->mtd.size = vi->used_bytes;
0409     mutex_unlock(&devices_mutex);
0410     return 0;
0411 }
0412 
0413 /**
0414  * gluebi_resized - UBI volume was re-sized notifier.
0415  * @vi: volume info structure
0416  *
0417  * This function is called every time an UBI volume is re-size. It changes the
0418  * corresponding fake MTD device size. This function returns zero in case of
0419  * success and a negative error code in case of error.
0420  */
0421 static int gluebi_resized(struct ubi_volume_info *vi)
0422 {
0423     struct gluebi_device *gluebi;
0424 
0425     mutex_lock(&devices_mutex);
0426     gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
0427     if (!gluebi) {
0428         mutex_unlock(&devices_mutex);
0429         err_msg("got update notification for unknown UBI device %d volume %d",
0430             vi->ubi_num, vi->vol_id);
0431         return -ENOENT;
0432     }
0433     gluebi->mtd.size = vi->used_bytes;
0434     mutex_unlock(&devices_mutex);
0435     return 0;
0436 }
0437 
0438 /**
0439  * gluebi_notify - UBI notification handler.
0440  * @nb: registered notifier block
0441  * @l: notification type
0442  * @ns_ptr: pointer to the &struct ubi_notification object
0443  */
0444 static int gluebi_notify(struct notifier_block *nb, unsigned long l,
0445              void *ns_ptr)
0446 {
0447     struct ubi_notification *nt = ns_ptr;
0448 
0449     switch (l) {
0450     case UBI_VOLUME_ADDED:
0451         gluebi_create(&nt->di, &nt->vi);
0452         break;
0453     case UBI_VOLUME_REMOVED:
0454         gluebi_remove(&nt->vi);
0455         break;
0456     case UBI_VOLUME_RESIZED:
0457         gluebi_resized(&nt->vi);
0458         break;
0459     case UBI_VOLUME_UPDATED:
0460         gluebi_updated(&nt->vi);
0461         break;
0462     default:
0463         break;
0464     }
0465     return NOTIFY_OK;
0466 }
0467 
0468 static struct notifier_block gluebi_notifier = {
0469     .notifier_call  = gluebi_notify,
0470 };
0471 
0472 static int __init ubi_gluebi_init(void)
0473 {
0474     return ubi_register_volume_notifier(&gluebi_notifier, 0);
0475 }
0476 
0477 static void __exit ubi_gluebi_exit(void)
0478 {
0479     struct gluebi_device *gluebi, *g;
0480 
0481     list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) {
0482         int err;
0483         struct mtd_info *mtd = &gluebi->mtd;
0484 
0485         err = mtd_device_unregister(mtd);
0486         if (err)
0487             err_msg("error %d while removing gluebi MTD device %d, UBI device %d, volume %d - ignoring",
0488                 err, mtd->index, gluebi->ubi_num,
0489                 gluebi->vol_id);
0490         kfree(mtd->name);
0491         kfree(gluebi);
0492     }
0493     ubi_unregister_volume_notifier(&gluebi_notifier);
0494 }
0495 
0496 module_init(ubi_gluebi_init);
0497 module_exit(ubi_gluebi_exit);
0498 MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
0499 MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
0500 MODULE_LICENSE("GPL");