aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/cdev.c
diff options
context:
space:
mode:
authorArtem B. Bityutskiy <dedekind@linutronix.de>2006-06-27 04:22:22 -0400
committerFrank Haverkamp <haver@vnet.ibm.com>2007-04-27 07:23:33 -0400
commit801c135ce73d5df1caf3eca35b66a10824ae0707 (patch)
treeeaf6e7859650557192533b70746479de686c56e1 /drivers/mtd/ubi/cdev.c
parentde46c33745f5e2ad594c72f2cf5f490861b16ce1 (diff)
UBI: Unsorted Block Images
UBI (Latin: "where?") manages multiple logical volumes on a single flash device, specifically supporting NAND flash devices. UBI provides a flexible partitioning concept which still allows for wear-levelling across the whole flash device. In a sense, UBI may be compared to the Logical Volume Manager (LVM). Whereas LVM maps logical sector numbers to physical HDD sector numbers, UBI maps logical eraseblocks to physical eraseblocks. More information may be found at http://www.linux-mtd.infradead.org/doc/ubi.html Partitioning/Re-partitioning An UBI volume occupies a certain number of erase blocks. This is limited by a configured maximum volume size, which could also be viewed as the partition size. Each individual UBI volume's size can be changed independently of the other UBI volumes, provided that the sum of all volume sizes doesn't exceed a certain limit. UBI supports dynamic volumes and static volumes. Static volumes are read-only and their contents are protected by CRC check sums. Bad eraseblocks handling UBI transparently handles bad eraseblocks. When a physical eraseblock becomes bad, it is substituted by a good physical eraseblock, and the user does not even notice this. Scrubbing On a NAND flash bit flips can occur on any write operation, sometimes also on read. If bit flips persist on the device, at first they can still be corrected by ECC, but once they accumulate, correction will become impossible. Thus it is best to actively scrub the affected eraseblock, by first copying it to a free eraseblock and then erasing the original. The UBI layer performs this type of scrubbing under the covers, transparently to the UBI volume users. Erase Counts UBI maintains an erase count header per eraseblock. This frees higher-level layers (like file systems) from doing this and allows for centralized erase count management instead. The erase counts are used by the wear-levelling algorithm in the UBI layer. The algorithm itself is exchangeable. Booting from NAND For booting directly from NAND flash the hardware must at least be capable of fetching and executing a small portion of the NAND flash. Some NAND flash controllers have this kind of support. They usually limit the window to a few kilobytes in erase block 0. This "initial program loader" (IPL) must then contain sufficient logic to load and execute the next boot phase. Due to bad eraseblocks, which may be randomly scattered over the flash device, it is problematic to store the "secondary program loader" (SPL) statically. Also, due to bit-flips it may become corrupted over time. UBI allows to solve this problem gracefully by storing the SPL in a small static UBI volume. UBI volumes vs. static partitions UBI volumes are still very similar to static MTD partitions: * both consist of eraseblocks (logical eraseblocks in case of UBI volumes, and physical eraseblocks in case of static partitions; * both support three basic operations - read, write, erase. But UBI volumes have the following advantages over traditional static MTD partitions: * there are no eraseblock wear-leveling constraints in case of UBI volumes, so the user should not care about this; * there are no bit-flips and bad eraseblocks in case of UBI volumes. So, UBI volumes may be considered as flash devices with relaxed restrictions. Where can it be found? Documentation, kernel code and applications can be found in the MTD gits. What are the applications for? The applications help to create binary flash images for two purposes: pfi files (partial flash images) for in-system update of UBI volumes, and plain binary images, with or without OOB data in case of NAND, for a manufacturing step. Furthermore some tools are/and will be created that allow flash content analysis after a system has crashed.. Who did UBI? The original ideas, where UBI is based on, were developed by Andreas Arnez, Frank Haverkamp and Thomas Gleixner. Josh W. Boyer and some others were involved too. The implementation of the kernel layer was done by Artem B. Bityutskiy. The user-space applications and tools were written by Oliver Lohmann with contributions from Frank Haverkamp, Andreas Arnez, and Artem. Joern Engel contributed a patch which modifies JFFS2 so that it can be run on a UBI volume. Thomas Gleixner did modifications to the NAND layer. Alexander Schmidt made some testing work as well as core functionality improvements. Signed-off-by: Artem B. Bityutskiy <dedekind@linutronix.de> Signed-off-by: Frank Haverkamp <haver@vnet.ibm.com>
Diffstat (limited to 'drivers/mtd/ubi/cdev.c')
-rw-r--r--drivers/mtd/ubi/cdev.c722
1 files changed, 722 insertions, 0 deletions
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
new file mode 100644
index 000000000000..6612eb79bf17
--- /dev/null
+++ b/drivers/mtd/ubi/cdev.c
@@ -0,0 +1,722 @@
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 (Битюцкий Артём)
19 */
20
21/*
22 * This file includes implementation of UBI character device operations.
23 *
24 * There are two kinds of character devices in UBI: UBI character devices and
25 * UBI volume character devices. UBI character devices allow users to
26 * manipulate whole volumes: create, remove, and re-size them. Volume character
27 * devices provide volume I/O capabilities.
28 *
29 * Major and minor numbers are assigned dynamically to both UBI and volume
30 * character devices.
31 */
32
33#include <linux/module.h>
34#include <linux/stat.h>
35#include <linux/ioctl.h>
36#include <linux/capability.h>
37#include <mtd/ubi-user.h>
38#include <asm/uaccess.h>
39#include <asm/div64.h>
40#include "ubi.h"
41
42/*
43 * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
44 * logical eraseblock erase is a debug-only feature).
45 */
46#define UBI_CDEV_IOC_MAX_SEQ 2
47#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
48#define VOL_CDEV_IOC_MAX_SEQ 1
49#else
50#define VOL_CDEV_IOC_MAX_SEQ 2
51#endif
52
53/**
54 * major_to_device - get UBI device object by character device major number.
55 * @major: major number
56 *
57 * This function returns a pointer to the UBI device object.
58 */
59static struct ubi_device *major_to_device(int major)
60{
61 int i;
62
63 for (i = 0; i < ubi_devices_cnt; i++)
64 if (ubi_devices[i] && ubi_devices[i]->major == major)
65 return ubi_devices[i];
66 BUG();
67}
68
69/**
70 * get_exclusive - get exclusive access to an UBI volume.
71 * @desc: volume descriptor
72 *
73 * This function changes UBI volume open mode to "exclusive". Returns previous
74 * mode value (positive integer) in case of success and a negative error code
75 * in case of failure.
76 */
77static int get_exclusive(struct ubi_volume_desc *desc)
78{
79 int users, err;
80 struct ubi_volume *vol = desc->vol;
81
82 spin_lock(&vol->ubi->volumes_lock);
83 users = vol->readers + vol->writers + vol->exclusive;
84 ubi_assert(users > 0);
85 if (users > 1) {
86 dbg_err("%d users for volume %d", users, vol->vol_id);
87 err = -EBUSY;
88 } else {
89 vol->readers = vol->writers = 0;
90 vol->exclusive = 1;
91 err = desc->mode;
92 desc->mode = UBI_EXCLUSIVE;
93 }
94 spin_unlock(&vol->ubi->volumes_lock);
95
96 return err;
97}
98
99/**
100 * revoke_exclusive - revoke exclusive mode.
101 * @desc: volume descriptor
102 * @mode: new mode to switch to
103 */
104static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
105{
106 struct ubi_volume *vol = desc->vol;
107
108 spin_lock(&vol->ubi->volumes_lock);
109 ubi_assert(vol->readers == 0 && vol->writers == 0);
110 ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
111 vol->exclusive = 0;
112 if (mode == UBI_READONLY)
113 vol->readers = 1;
114 else if (mode == UBI_READWRITE)
115 vol->writers = 1;
116 else
117 vol->exclusive = 1;
118 spin_unlock(&vol->ubi->volumes_lock);
119
120 desc->mode = mode;
121}
122
123static int vol_cdev_open(struct inode *inode, struct file *file)
124{
125 struct ubi_volume_desc *desc;
126 const struct ubi_device *ubi = major_to_device(imajor(inode));
127 int vol_id = iminor(inode) - 1;
128 int mode;
129
130 if (file->f_mode & FMODE_WRITE)
131 mode = UBI_READWRITE;
132 else
133 mode = UBI_READONLY;
134
135 dbg_msg("open volume %d, mode %d", vol_id, mode);
136
137 desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
138 if (IS_ERR(desc))
139 return PTR_ERR(desc);
140
141 file->private_data = desc;
142 return 0;
143}
144
145static int vol_cdev_release(struct inode *inode, struct file *file)
146{
147 struct ubi_volume_desc *desc = file->private_data;
148 struct ubi_volume *vol = desc->vol;
149
150 dbg_msg("release volume %d, mode %d", vol->vol_id, desc->mode);
151
152 if (vol->updating) {
153 ubi_warn("update of volume %d not finished, volume is damaged",
154 vol->vol_id);
155 vol->updating = 0;
156 kfree(vol->upd_buf);
157 }
158
159 ubi_close_volume(desc);
160 return 0;
161}
162
163static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
164{
165 struct ubi_volume_desc *desc = file->private_data;
166 struct ubi_volume *vol = desc->vol;
167 loff_t new_offset;
168
169 if (vol->updating) {
170 /* Update is in progress, seeking is prohibited */
171 dbg_err("updating");
172 return -EBUSY;
173 }
174
175 switch (origin) {
176 case 0: /* SEEK_SET */
177 new_offset = offset;
178 break;
179 case 1: /* SEEK_CUR */
180 new_offset = file->f_pos + offset;
181 break;
182 case 2: /* SEEK_END */
183 new_offset = vol->used_bytes + offset;
184 break;
185 default:
186 return -EINVAL;
187 }
188
189 if (new_offset < 0 || new_offset > vol->used_bytes) {
190 dbg_err("bad seek %lld", new_offset);
191 return -EINVAL;
192 }
193
194 dbg_msg("seek volume %d, offset %lld, origin %d, new offset %lld",
195 vol->vol_id, offset, origin, new_offset);
196
197 file->f_pos = new_offset;
198 return new_offset;
199}
200
201static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
202 loff_t *offp)
203{
204 struct ubi_volume_desc *desc = file->private_data;
205 struct ubi_volume *vol = desc->vol;
206 struct ubi_device *ubi = vol->ubi;
207 int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size;
208 size_t count_save = count;
209 void *tbuf;
210 uint64_t tmp;
211
212 dbg_msg("read %zd bytes from offset %lld of volume %d",
213 count, *offp, vol_id);
214
215 if (vol->updating) {
216 dbg_err("updating");
217 return -EBUSY;
218 }
219 if (vol->upd_marker) {
220 dbg_err("damaged volume, update marker is set");
221 return -EBADF;
222 }
223 if (*offp == vol->used_bytes || count == 0)
224 return 0;
225
226 if (vol->corrupted)
227 dbg_msg("read from corrupted volume %d", vol_id);
228
229 if (*offp + count > vol->used_bytes)
230 count_save = count = vol->used_bytes - *offp;
231
232 tbuf_size = vol->usable_leb_size;
233 if (count < tbuf_size)
234 tbuf_size = ALIGN(count, ubi->min_io_size);
235 tbuf = kmalloc(tbuf_size, GFP_KERNEL);
236 if (!tbuf)
237 return -ENOMEM;
238
239 len = count > tbuf_size ? tbuf_size : count;
240
241 tmp = *offp;
242 off = do_div(tmp, vol->usable_leb_size);
243 lnum = tmp;
244
245 do {
246 cond_resched();
247
248 if (off + len >= vol->usable_leb_size)
249 len = vol->usable_leb_size - off;
250
251 err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0);
252 if (err)
253 break;
254
255 off += len;
256 if (off == vol->usable_leb_size) {
257 lnum += 1;
258 off -= vol->usable_leb_size;
259 }
260
261 count -= len;
262 *offp += len;
263
264 err = copy_to_user(buf, tbuf, len);
265 if (err) {
266 err = -EFAULT;
267 break;
268 }
269
270 buf += len;
271 len = count > tbuf_size ? tbuf_size : count;
272 } while (count);
273
274 kfree(tbuf);
275 return err ? err : count_save - count;
276}
277
278#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
279
280/*
281 * This function allows to directly write to dynamic UBI volumes, without
282 * issuing the volume update operation. Available only as a debugging feature.
283 * Very useful for testing UBI.
284 */
285static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
286 size_t count, loff_t *offp)
287{
288 struct ubi_volume_desc *desc = file->private_data;
289 struct ubi_volume *vol = desc->vol;
290 struct ubi_device *ubi = vol->ubi;
291 int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0;
292 size_t count_save = count;
293 char *tbuf;
294 uint64_t tmp;
295
296 dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
297 count, *offp, desc->vol->vol_id);
298
299 if (vol->vol_type == UBI_STATIC_VOLUME)
300 return -EROFS;
301
302 tmp = *offp;
303 off = do_div(tmp, vol->usable_leb_size);
304 lnum = tmp;
305
306 if (off % ubi->min_io_size) {
307 dbg_err("unaligned position");
308 return -EINVAL;
309 }
310
311 if (*offp + count > vol->used_bytes)
312 count_save = count = vol->used_bytes - *offp;
313
314 /* We can write only in fractions of the minimum I/O unit */
315 if (count % ubi->min_io_size) {
316 dbg_err("unaligned write length");
317 return -EINVAL;
318 }
319
320 tbuf_size = vol->usable_leb_size;
321 if (count < tbuf_size)
322 tbuf_size = ALIGN(count, ubi->min_io_size);
323 tbuf = kmalloc(tbuf_size, GFP_KERNEL);
324 if (!tbuf)
325 return -ENOMEM;
326
327 len = count > tbuf_size ? tbuf_size : count;
328
329 while (count) {
330 cond_resched();
331
332 if (off + len >= vol->usable_leb_size)
333 len = vol->usable_leb_size - off;
334
335 err = copy_from_user(tbuf, buf, len);
336 if (err) {
337 err = -EFAULT;
338 break;
339 }
340
341 err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
342 UBI_UNKNOWN);
343 if (err)
344 break;
345
346 off += len;
347 if (off == vol->usable_leb_size) {
348 lnum += 1;
349 off -= vol->usable_leb_size;
350 }
351
352 count -= len;
353 *offp += len;
354 buf += len;
355 len = count > tbuf_size ? tbuf_size : count;
356 }
357
358 kfree(tbuf);
359 return err ? err : count_save - count;
360}
361
362#else
363#define vol_cdev_direct_write(file, buf, count, offp) -EPERM
364#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */
365
366static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
367 size_t count, loff_t *offp)
368{
369 int err = 0;
370 struct ubi_volume_desc *desc = file->private_data;
371 struct ubi_volume *vol = desc->vol;
372 struct ubi_device *ubi = vol->ubi;
373
374 if (!vol->updating)
375 return vol_cdev_direct_write(file, buf, count, offp);
376
377 err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
378 if (err < 0) {
379 ubi_err("cannot write %zd bytes of update data", count);
380 return err;
381 }
382
383 if (err) {
384 /*
385 * Update is finished, @err contains number of actually written
386 * bytes now.
387 */
388 count = err;
389
390 err = ubi_check_volume(ubi, vol->vol_id);
391 if (err < 0)
392 return err;
393
394 if (err) {
395 ubi_warn("volume %d on UBI device %d is corrupted",
396 vol->vol_id, ubi->ubi_num);
397 vol->corrupted = 1;
398 }
399 vol->checked = 1;
400 revoke_exclusive(desc, UBI_READWRITE);
401 }
402
403 *offp += count;
404 return count;
405}
406
407static int vol_cdev_ioctl(struct inode *inode, struct file *file,
408 unsigned int cmd, unsigned long arg)
409{
410 int err = 0;
411 struct ubi_volume_desc *desc = file->private_data;
412 struct ubi_volume *vol = desc->vol;
413 struct ubi_device *ubi = vol->ubi;
414 void __user *argp = (void __user *)arg;
415
416 if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
417 _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
418 return -ENOTTY;
419
420 if (_IOC_DIR(cmd) && _IOC_READ)
421 err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
422 else if (_IOC_DIR(cmd) && _IOC_WRITE)
423 err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
424 if (err)
425 return -EFAULT;
426
427 switch (cmd) {
428
429 /* Volume update command */
430 case UBI_IOCVOLUP:
431 {
432 int64_t bytes, rsvd_bytes;
433
434 if (!capable(CAP_SYS_RESOURCE)) {
435 err = -EPERM;
436 break;
437 }
438
439 err = copy_from_user(&bytes, argp, sizeof(int64_t));
440 if (err) {
441 err = -EFAULT;
442 break;
443 }
444
445 if (desc->mode == UBI_READONLY) {
446 err = -EROFS;
447 break;
448 }
449
450 rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad);
451 if (bytes < 0 || bytes > rsvd_bytes) {
452 err = -EINVAL;
453 break;
454 }
455
456 err = get_exclusive(desc);
457 if (err < 0)
458 break;
459
460 err = ubi_start_update(ubi, vol->vol_id, bytes);
461 if (bytes == 0)
462 revoke_exclusive(desc, UBI_READWRITE);
463
464 file->f_pos = 0;
465 break;
466 }
467
468#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
469 /* Logical eraseblock erasure command */
470 case UBI_IOCEBER:
471 {
472 int32_t lnum;
473
474 err = __get_user(lnum, (__user int32_t *)argp);
475 if (err) {
476 err = -EFAULT;
477 break;
478 }
479
480 if (desc->mode == UBI_READONLY) {
481 err = -EROFS;
482 break;
483 }
484
485 if (lnum < 0 || lnum >= vol->reserved_pebs) {
486 err = -EINVAL;
487 break;
488 }
489
490 if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
491 err = -EROFS;
492 break;
493 }
494
495 dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
496 err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum);
497 if (err)
498 break;
499
500 err = ubi_wl_flush(ubi);
501 break;
502 }
503#endif
504
505 default:
506 err = -ENOTTY;
507 break;
508 }
509
510 return err;
511}
512
513/**
514 * verify_mkvol_req - verify volume creation request.
515 * @ubi: UBI device description object
516 * @req: the request to check
517 *
518 * This function zero if the request is correct, and %-EINVAL if not.
519 */
520static int verify_mkvol_req(const struct ubi_device *ubi,
521 const struct ubi_mkvol_req *req)
522{
523 int n, err = -EINVAL;
524
525 if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
526 req->name_len < 0)
527 goto bad;
528
529 if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
530 req->vol_id != UBI_VOL_NUM_AUTO)
531 goto bad;
532
533 if (req->alignment == 0)
534 goto bad;
535
536 if (req->bytes == 0)
537 goto bad;
538
539 if (req->vol_type != UBI_DYNAMIC_VOLUME &&
540 req->vol_type != UBI_STATIC_VOLUME)
541 goto bad;
542
543 if (req->alignment > ubi->leb_size)
544 goto bad;
545
546 n = req->alignment % ubi->min_io_size;
547 if (req->alignment != 1 && n)
548 goto bad;
549
550 if (req->name_len > UBI_VOL_NAME_MAX) {
551 err = -ENAMETOOLONG;
552 goto bad;
553 }
554
555 return 0;
556
557bad:
558 dbg_err("bad volume creation request");
559 ubi_dbg_dump_mkvol_req(req);
560 return err;
561}
562
563/**
564 * verify_rsvol_req - verify volume re-size request.
565 * @ubi: UBI device description object
566 * @req: the request to check
567 *
568 * This function returns zero if the request is correct, and %-EINVAL if not.
569 */
570static int verify_rsvol_req(const struct ubi_device *ubi,
571 const struct ubi_rsvol_req *req)
572{
573 if (req->bytes <= 0)
574 return -EINVAL;
575
576 if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)
577 return -EINVAL;
578
579 return 0;
580}
581
582static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
583 unsigned int cmd, unsigned long arg)
584{
585 int err = 0;
586 struct ubi_device *ubi;
587 struct ubi_volume_desc *desc;
588 void __user *argp = (void __user *)arg;
589
590 if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
591 _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
592 return -ENOTTY;
593
594 if (_IOC_DIR(cmd) && _IOC_READ)
595 err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
596 else if (_IOC_DIR(cmd) && _IOC_WRITE)
597 err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
598 if (err)
599 return -EFAULT;
600
601 if (!capable(CAP_SYS_RESOURCE))
602 return -EPERM;
603
604 ubi = major_to_device(imajor(inode));
605 if (IS_ERR(ubi))
606 return PTR_ERR(ubi);
607
608 switch (cmd) {
609 /* Create volume command */
610 case UBI_IOCMKVOL:
611 {
612 struct ubi_mkvol_req req;
613
614 dbg_msg("create volume");
615 err = __copy_from_user(&req, argp,
616 sizeof(struct ubi_mkvol_req));
617 if (err) {
618 err = -EFAULT;
619 break;
620 }
621
622 err = verify_mkvol_req(ubi, &req);
623 if (err)
624 break;
625
626 req.name[req.name_len] = '\0';
627
628 err = ubi_create_volume(ubi, &req);
629 if (err)
630 break;
631
632 err = __put_user(req.vol_id, (__user int32_t *)argp);
633 if (err)
634 err = -EFAULT;
635
636 break;
637 }
638
639 /* Remove volume command */
640 case UBI_IOCRMVOL:
641 {
642 int vol_id;
643
644 dbg_msg("remove volume");
645 err = __get_user(vol_id, (__user int32_t *)argp);
646 if (err) {
647 err = -EFAULT;
648 break;
649 }
650
651 desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
652 if (IS_ERR(desc)) {
653 err = PTR_ERR(desc);
654 break;
655 }
656
657 err = ubi_remove_volume(desc);
658 if (err)
659 ubi_close_volume(desc);
660
661 break;
662 }
663
664 /* Re-size volume command */
665 case UBI_IOCRSVOL:
666 {
667 int pebs;
668 uint64_t tmp;
669 struct ubi_rsvol_req req;
670
671 dbg_msg("re-size volume");
672 err = __copy_from_user(&req, argp,
673 sizeof(struct ubi_rsvol_req));
674 if (err) {
675 err = -EFAULT;
676 break;
677 }
678
679 err = verify_rsvol_req(ubi, &req);
680 if (err)
681 break;
682
683 desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);
684 if (IS_ERR(desc)) {
685 err = PTR_ERR(desc);
686 break;
687 }
688
689 tmp = req.bytes;
690 pebs = !!do_div(tmp, desc->vol->usable_leb_size);
691 pebs += tmp;
692
693 err = ubi_resize_volume(desc, pebs);
694 ubi_close_volume(desc);
695 break;
696 }
697
698 default:
699 err = -ENOTTY;
700 break;
701 }
702
703 return err;
704}
705
706/* UBI character device operations */
707struct file_operations ubi_cdev_operations = {
708 .owner = THIS_MODULE,
709 .ioctl = ubi_cdev_ioctl,
710 .llseek = no_llseek
711};
712
713/* UBI volume character device operations */
714struct file_operations ubi_vol_cdev_operations = {
715 .owner = THIS_MODULE,
716 .open = vol_cdev_open,
717 .release = vol_cdev_release,
718 .llseek = vol_cdev_llseek,
719 .read = vol_cdev_read,
720 .write = vol_cdev_write,
721 .ioctl = vol_cdev_ioctl
722};