aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/ubi/cdev.c')
-rw-r--r--drivers/mtd/ubi/cdev.c72
1 files changed, 60 insertions, 12 deletions
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 0c4044d6cae0..9d6aae5449b6 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
132 if (vol->updating) { 132 if (vol->updating) {
133 ubi_warn("update of volume %d not finished, volume is damaged", 133 ubi_warn("update of volume %d not finished, volume is damaged",
134 vol->vol_id); 134 vol->vol_id);
135 ubi_assert(!vol->changing_leb);
135 vol->updating = 0; 136 vol->updating = 0;
136 vfree(vol->upd_buf); 137 vfree(vol->upd_buf);
138 } else if (vol->changing_leb) {
139 dbg_msg("only %lld of %lld bytes received for atomic LEB change"
140 " for volume %d:%d, cancel", vol->upd_received,
141 vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
142 vol->changing_leb = 0;
143 vfree(vol->upd_buf);
137 } 144 }
138 145
139 ubi_close_volume(desc); 146 ubi_close_volume(desc);
@@ -351,24 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
351 struct ubi_volume *vol = desc->vol; 358 struct ubi_volume *vol = desc->vol;
352 struct ubi_device *ubi = vol->ubi; 359 struct ubi_device *ubi = vol->ubi;
353 360
354 if (!vol->updating) 361 if (!vol->updating && !vol->changing_leb)
355 return vol_cdev_direct_write(file, buf, count, offp); 362 return vol_cdev_direct_write(file, buf, count, offp);
356 363
357 err = ubi_more_update_data(ubi, vol, buf, count); 364 if (vol->updating)
365 err = ubi_more_update_data(ubi, vol, buf, count);
366 else
367 err = ubi_more_leb_change_data(ubi, vol, buf, count);
368
358 if (err < 0) { 369 if (err < 0) {
359 ubi_err("cannot write %zd bytes of update data, error %d", 370 ubi_err("cannot accept more %zd bytes of data, error %d",
360 count, err); 371 count, err);
361 return err; 372 return err;
362 } 373 }
363 374
364 if (err) { 375 if (err) {
365 /* 376 /*
366 * Update is finished, @err contains number of actually written 377 * The operation is finished, @err contains number of actually
367 * bytes now. 378 * written bytes.
368 */ 379 */
369 count = err; 380 count = err;
370 381
371 vol->updating = 0; 382 if (vol->changing_leb) {
383 revoke_exclusive(desc, UBI_READWRITE);
384 return count;
385 }
386
372 err = ubi_check_volume(ubi, vol->vol_id); 387 err = ubi_check_volume(ubi, vol->vol_id);
373 if (err < 0) 388 if (err < 0)
374 return err; 389 return err;
@@ -433,6 +448,43 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
433 break; 448 break;
434 } 449 }
435 450
451 /* Atomic logical eraseblock change command */
452 case UBI_IOCEBCH:
453 {
454 struct ubi_leb_change_req req;
455
456 err = copy_from_user(&req, argp,
457 sizeof(struct ubi_leb_change_req));
458 if (err) {
459 err = -EFAULT;
460 break;
461 }
462
463 if (desc->mode == UBI_READONLY ||
464 vol->vol_type == UBI_STATIC_VOLUME) {
465 err = -EROFS;
466 break;
467 }
468
469 /* Validate the request */
470 err = -EINVAL;
471 if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
472 req.bytes < 0 || req.lnum >= vol->usable_leb_size)
473 break;
474 if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
475 req.dtype != UBI_UNKNOWN)
476 break;
477
478 err = get_exclusive(desc);
479 if (err < 0)
480 break;
481
482 err = ubi_start_leb_change(ubi, vol, &req);
483 if (req.bytes == 0)
484 revoke_exclusive(desc, UBI_READWRITE);
485 break;
486 }
487
436#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO 488#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
437 /* Logical eraseblock erasure command */ 489 /* Logical eraseblock erasure command */
438 case UBI_IOCEBER: 490 case UBI_IOCEBER:
@@ -445,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
445 break; 497 break;
446 } 498 }
447 499
448 if (desc->mode == UBI_READONLY) { 500 if (desc->mode == UBI_READONLY ||
501 vol->vol_type == UBI_STATIC_VOLUME) {
449 err = -EROFS; 502 err = -EROFS;
450 break; 503 break;
451 } 504 }
@@ -455,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
455 break; 508 break;
456 } 509 }
457 510
458 if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
459 err = -EROFS;
460 break;
461 }
462
463 dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); 511 dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
464 err = ubi_eba_unmap_leb(ubi, vol, lnum); 512 err = ubi_eba_unmap_leb(ubi, vol, lnum);
465 if (err) 513 if (err)