xref: /openbmc/linux/drivers/mtd/ubi/gluebi.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
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   */
43  struct 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 */
53  static LIST_HEAD(gluebi_devices);
54  static 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   */
find_gluebi_nolock(int ubi_num,int vol_id)66  static 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   */
gluebi_get_device(struct mtd_info * mtd)84  static 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   */
gluebi_put_device(struct mtd_info * mtd)130  static 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   */
gluebi_read(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,unsigned char * buf)153  static 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   */
gluebi_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf)193  static 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   */
gluebi_erase(struct mtd_info * mtd,struct erase_info * instr)234  static 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  
264  out_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   */
gluebi_create(struct ubi_device_info * di,struct ubi_volume_info * vi)278  static 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   */
gluebi_remove(struct ubi_volume_info * vi)348  static 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   */
gluebi_updated(struct ubi_volume_info * vi)394  static 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   */
gluebi_resized(struct ubi_volume_info * vi)421  static 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   */
gluebi_notify(struct notifier_block * nb,unsigned long l,void * ns_ptr)444  static 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  
468  static struct notifier_block gluebi_notifier = {
469  	.notifier_call	= gluebi_notify,
470  };
471  
ubi_gluebi_init(void)472  static int __init ubi_gluebi_init(void)
473  {
474  	return ubi_register_volume_notifier(&gluebi_notifier, 0);
475  }
476  
ubi_gluebi_exit(void)477  static 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  
496  module_init(ubi_gluebi_init);
497  module_exit(ubi_gluebi_exit);
498  MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
499  MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
500  MODULE_LICENSE("GPL");
501