diff options
Diffstat (limited to 'drivers/mtd/ubi/cdev.c')
-rw-r--r-- | drivers/mtd/ubi/cdev.c | 72 |
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) |