diff options
| -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"); | ||
