Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gluebi.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) International Business Machines Corp., 2006
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12  * the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Artem Bityutskiy (Битюцкий Артём), Joern Engel
19  */
20 
21 /*
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.
26  *
27  * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
28  * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The
29  * eraseblock size is equivalent to the logical eraseblock size of the volume.
30  */
31 
32 #include <linux/err.h>
33 #include <linux/list.h>
34 #include <linux/slab.h>
35 #include <linux/sched.h>
36 #include <linux/math64.h>
37 #include <linux/module.h>
38 #include <linux/mutex.h>
39 #include <linux/mtd/ubi.h>
40 #include <linux/mtd/mtd.h>
41 #include "ubi-media.h"
42 
43 #define err_msg(fmt, ...) \
44  pr_err("gluebi (pid %d): %s: " fmt "\n", \
45  current->pid, __func__, ##__VA_ARGS__)
46 
56 struct gluebi_device {
57  struct mtd_info mtd;
58  int refcnt;
60  int ubi_num;
61  int vol_id;
62  struct list_head list;
63 };
64 
65 /* List of all gluebi devices */
66 static LIST_HEAD(gluebi_devices);
67 static DEFINE_MUTEX(devices_mutex);
68 
79 static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id)
80 {
81  struct gluebi_device *gluebi;
82 
83  list_for_each_entry(gluebi, &gluebi_devices, list)
84  if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id)
85  return gluebi;
86  return NULL;
87 }
88 
97 static int gluebi_get_device(struct mtd_info *mtd)
98 {
99  struct gluebi_device *gluebi;
100  int ubi_mode = UBI_READONLY;
101 
102  if (!try_module_get(THIS_MODULE))
103  return -ENODEV;
104 
105  if (mtd->flags & MTD_WRITEABLE)
106  ubi_mode = UBI_READWRITE;
107 
108  gluebi = container_of(mtd, struct gluebi_device, mtd);
109  mutex_lock(&devices_mutex);
110  if (gluebi->refcnt > 0) {
111  /*
112  * The MTD device is already referenced and this is just one
113  * more reference. MTD allows many users to open the same
114  * volume simultaneously and do not distinguish between
115  * readers/writers/exclusive openers as UBI does. So we do not
116  * open the UBI volume again - just increase the reference
117  * counter and return.
118  */
119  gluebi->refcnt += 1;
120  mutex_unlock(&devices_mutex);
121  return 0;
122  }
123 
124  /*
125  * This is the first reference to this UBI volume via the MTD device
126  * interface. Open the corresponding volume in read-write mode.
127  */
128  gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id,
129  ubi_mode);
130  if (IS_ERR(gluebi->desc)) {
131  mutex_unlock(&devices_mutex);
132  module_put(THIS_MODULE);
133  return PTR_ERR(gluebi->desc);
134  }
135  gluebi->refcnt += 1;
136  mutex_unlock(&devices_mutex);
137  return 0;
138 }
139 
147 static void gluebi_put_device(struct mtd_info *mtd)
148 {
149  struct gluebi_device *gluebi;
150 
151  gluebi = container_of(mtd, struct gluebi_device, mtd);
152  mutex_lock(&devices_mutex);
153  gluebi->refcnt -= 1;
154  if (gluebi->refcnt == 0)
155  ubi_close_volume(gluebi->desc);
156  module_put(THIS_MODULE);
157  mutex_unlock(&devices_mutex);
158 }
159 
171 static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
172  size_t *retlen, unsigned char *buf)
173 {
174  int err = 0, lnum, offs, total_read;
175  struct gluebi_device *gluebi;
176 
177  gluebi = container_of(mtd, struct gluebi_device, mtd);
178  lnum = div_u64_rem(from, mtd->erasesize, &offs);
179  total_read = len;
180  while (total_read) {
181  size_t to_read = mtd->erasesize - offs;
182 
183  if (to_read > total_read)
184  to_read = total_read;
185 
186  err = ubi_read(gluebi->desc, lnum, buf, offs, to_read);
187  if (err)
188  break;
189 
190  lnum += 1;
191  offs = 0;
192  total_read -= to_read;
193  buf += to_read;
194  }
195 
196  *retlen = len - total_read;
197  return err;
198 }
199 
211 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
212  size_t *retlen, const u_char *buf)
213 {
214  int err = 0, lnum, offs, total_written;
215  struct gluebi_device *gluebi;
216 
217  gluebi = container_of(mtd, struct gluebi_device, mtd);
218  lnum = div_u64_rem(to, mtd->erasesize, &offs);
219 
220  if (len % mtd->writesize || offs % mtd->writesize)
221  return -EINVAL;
222 
223  total_written = len;
224  while (total_written) {
225  size_t to_write = mtd->erasesize - offs;
226 
227  if (to_write > total_written)
228  to_write = total_written;
229 
230  err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
231  if (err)
232  break;
233 
234  lnum += 1;
235  offs = 0;
236  total_written -= to_write;
237  buf += to_write;
238  }
239 
240  *retlen = len - total_written;
241  return err;
242 }
243 
252 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
253 {
254  int err, i, lnum, count;
255  struct gluebi_device *gluebi;
256 
257  if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
258  return -EINVAL;
259 
260  lnum = mtd_div_by_eb(instr->addr, mtd);
261  count = mtd_div_by_eb(instr->len, mtd);
262  gluebi = container_of(mtd, struct gluebi_device, mtd);
263 
264  for (i = 0; i < count - 1; i++) {
265  err = ubi_leb_unmap(gluebi->desc, lnum + i);
266  if (err)
267  goto out_err;
268  }
269  /*
270  * MTD erase operations are synchronous, so we have to make sure the
271  * physical eraseblock is wiped out.
272  *
273  * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
274  * will wait for the end of operations
275  */
276  err = ubi_leb_erase(gluebi->desc, lnum + i);
277  if (err)
278  goto out_err;
279 
280  instr->state = MTD_ERASE_DONE;
281  mtd_erase_callback(instr);
282  return 0;
283 
284 out_err:
285  instr->state = MTD_ERASE_FAILED;
286  instr->fail_addr = (long long)lnum * mtd->erasesize;
287  return err;
288 }
289 
299 static int gluebi_create(struct ubi_device_info *di,
300  struct ubi_volume_info *vi)
301 {
302  struct gluebi_device *gluebi, *g;
303  struct mtd_info *mtd;
304 
305  gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL);
306  if (!gluebi)
307  return -ENOMEM;
308 
309  mtd = &gluebi->mtd;
310  mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL);
311  if (!mtd->name) {
312  kfree(gluebi);
313  return -ENOMEM;
314  }
315 
316  gluebi->vol_id = vi->vol_id;
317  gluebi->ubi_num = vi->ubi_num;
318  mtd->type = MTD_UBIVOLUME;
319  if (!di->ro_mode)
320  mtd->flags = MTD_WRITEABLE;
321  mtd->owner = THIS_MODULE;
322  mtd->writesize = di->min_io_size;
323  mtd->erasesize = vi->usable_leb_size;
324  mtd->_read = gluebi_read;
325  mtd->_write = gluebi_write;
326  mtd->_erase = gluebi_erase;
327  mtd->_get_device = gluebi_get_device;
328  mtd->_put_device = gluebi_put_device;
329 
330  /*
331  * In case of dynamic a volume, MTD device size is just volume size. In
332  * case of a static volume the size is equivalent to the amount of data
333  * bytes.
334  */
335  if (vi->vol_type == UBI_DYNAMIC_VOLUME)
336  mtd->size = (unsigned long long)vi->usable_leb_size * vi->size;
337  else
338  mtd->size = vi->used_bytes;
339 
340  /* Just a sanity check - make sure this gluebi device does not exist */
341  mutex_lock(&devices_mutex);
342  g = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
343  if (g)
344  err_msg("gluebi MTD device %d form UBI device %d volume %d already exists",
345  g->mtd.index, vi->ubi_num, vi->vol_id);
346  mutex_unlock(&devices_mutex);
347 
348  if (mtd_device_register(mtd, NULL, 0)) {
349  err_msg("cannot add MTD device");
350  kfree(mtd->name);
351  kfree(gluebi);
352  return -ENFILE;
353  }
354 
355  mutex_lock(&devices_mutex);
356  list_add_tail(&gluebi->list, &gluebi_devices);
357  mutex_unlock(&devices_mutex);
358  return 0;
359 }
360 
369 static int gluebi_remove(struct ubi_volume_info *vi)
370 {
371  int err = 0;
372  struct mtd_info *mtd;
373  struct gluebi_device *gluebi;
374 
375  mutex_lock(&devices_mutex);
376  gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
377  if (!gluebi) {
378  err_msg("got remove notification for unknown UBI device %d volume %d",
379  vi->ubi_num, vi->vol_id);
380  err = -ENOENT;
381  } else if (gluebi->refcnt)
382  err = -EBUSY;
383  else
384  list_del(&gluebi->list);
385  mutex_unlock(&devices_mutex);
386  if (err)
387  return err;
388 
389  mtd = &gluebi->mtd;
390  err = mtd_device_unregister(mtd);
391  if (err) {
392  err_msg("cannot remove fake MTD device %d, UBI device %d, volume %d, error %d",
393  mtd->index, gluebi->ubi_num, gluebi->vol_id, err);
394  mutex_lock(&devices_mutex);
395  list_add_tail(&gluebi->list, &gluebi_devices);
396  mutex_unlock(&devices_mutex);
397  return err;
398  }
399 
400  kfree(mtd->name);
401  kfree(gluebi);
402  return 0;
403 }
404 
415 static int gluebi_updated(struct ubi_volume_info *vi)
416 {
417  struct gluebi_device *gluebi;
418 
419  mutex_lock(&devices_mutex);
420  gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
421  if (!gluebi) {
422  mutex_unlock(&devices_mutex);
423  err_msg("got update notification for unknown UBI device %d volume %d",
424  vi->ubi_num, vi->vol_id);
425  return -ENOENT;
426  }
427 
428  if (vi->vol_type == UBI_STATIC_VOLUME)
429  gluebi->mtd.size = vi->used_bytes;
430  mutex_unlock(&devices_mutex);
431  return 0;
432 }
433 
442 static int gluebi_resized(struct ubi_volume_info *vi)
443 {
444  struct gluebi_device *gluebi;
445 
446  mutex_lock(&devices_mutex);
447  gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
448  if (!gluebi) {
449  mutex_unlock(&devices_mutex);
450  err_msg("got update notification for unknown UBI device %d volume %d",
451  vi->ubi_num, vi->vol_id);
452  return -ENOENT;
453  }
454  gluebi->mtd.size = vi->used_bytes;
455  mutex_unlock(&devices_mutex);
456  return 0;
457 }
458 
465 static int gluebi_notify(struct notifier_block *nb, unsigned long l,
466  void *ns_ptr)
467 {
468  struct ubi_notification *nt = ns_ptr;
469 
470  switch (l) {
471  case UBI_VOLUME_ADDED:
472  gluebi_create(&nt->di, &nt->vi);
473  break;
474  case UBI_VOLUME_REMOVED:
475  gluebi_remove(&nt->vi);
476  break;
477  case UBI_VOLUME_RESIZED:
478  gluebi_resized(&nt->vi);
479  break;
480  case UBI_VOLUME_UPDATED:
481  gluebi_updated(&nt->vi);
482  break;
483  default:
484  break;
485  }
486  return NOTIFY_OK;
487 }
488 
489 static struct notifier_block gluebi_notifier = {
490  .notifier_call = gluebi_notify,
491 };
492 
493 static int __init ubi_gluebi_init(void)
494 {
495  return ubi_register_volume_notifier(&gluebi_notifier, 0);
496 }
497 
498 static void __exit ubi_gluebi_exit(void)
499 {
500  struct gluebi_device *gluebi, *g;
501 
502  list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) {
503  int err;
504  struct mtd_info *mtd = &gluebi->mtd;
505 
506  err = mtd_device_unregister(mtd);
507  if (err)
508  err_msg("error %d while removing gluebi MTD device %d, UBI device %d, volume %d - ignoring",
509  err, mtd->index, gluebi->ubi_num,
510  gluebi->vol_id);
511  kfree(mtd->name);
512  kfree(gluebi);
513  }
514  ubi_unregister_volume_notifier(&gluebi_notifier);
515 }
516 
517 module_init(ubi_gluebi_init);
518 module_exit(ubi_gluebi_exit);
519 MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
520 MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
521 MODULE_LICENSE("GPL");