diff options
Diffstat (limited to 'drivers/mtd/ubi/cdev.c')
-rw-r--r-- | drivers/mtd/ubi/cdev.c | 82 |
1 files changed, 64 insertions, 18 deletions
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 5ec13dc4705b..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); |
@@ -184,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, | |||
184 | struct ubi_volume_desc *desc = file->private_data; | 191 | struct ubi_volume_desc *desc = file->private_data; |
185 | struct ubi_volume *vol = desc->vol; | 192 | struct ubi_volume *vol = desc->vol; |
186 | struct ubi_device *ubi = vol->ubi; | 193 | struct ubi_device *ubi = vol->ubi; |
187 | int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; | 194 | int err, lnum, off, len, tbuf_size; |
188 | size_t count_save = count; | 195 | size_t count_save = count; |
189 | void *tbuf; | 196 | void *tbuf; |
190 | uint64_t tmp; | 197 | uint64_t tmp; |
191 | 198 | ||
192 | dbg_msg("read %zd bytes from offset %lld of volume %d", | 199 | dbg_msg("read %zd bytes from offset %lld of volume %d", |
193 | count, *offp, vol_id); | 200 | count, *offp, vol->vol_id); |
194 | 201 | ||
195 | if (vol->updating) { | 202 | if (vol->updating) { |
196 | dbg_err("updating"); | 203 | dbg_err("updating"); |
@@ -204,7 +211,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, | |||
204 | return 0; | 211 | return 0; |
205 | 212 | ||
206 | if (vol->corrupted) | 213 | if (vol->corrupted) |
207 | dbg_msg("read from corrupted volume %d", vol_id); | 214 | dbg_msg("read from corrupted volume %d", vol->vol_id); |
208 | 215 | ||
209 | if (*offp + count > vol->used_bytes) | 216 | if (*offp + count > vol->used_bytes) |
210 | count_save = count = vol->used_bytes - *offp; | 217 | count_save = count = vol->used_bytes - *offp; |
@@ -274,7 +281,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, | |||
274 | uint64_t tmp; | 281 | uint64_t tmp; |
275 | 282 | ||
276 | dbg_msg("requested: write %zd bytes to offset %lld of volume %u", | 283 | dbg_msg("requested: write %zd bytes to offset %lld of volume %u", |
277 | count, *offp, desc->vol->vol_id); | 284 | count, *offp, vol->vol_id); |
278 | 285 | ||
279 | if (vol->vol_type == UBI_STATIC_VOLUME) | 286 | if (vol->vol_type == UBI_STATIC_VOLUME) |
280 | return -EROFS; | 287 | return -EROFS; |
@@ -351,23 +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->vol_id, 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 | ||
382 | if (vol->changing_leb) { | ||
383 | revoke_exclusive(desc, UBI_READWRITE); | ||
384 | return count; | ||
385 | } | ||
386 | |||
371 | err = ubi_check_volume(ubi, vol->vol_id); | 387 | err = ubi_check_volume(ubi, vol->vol_id); |
372 | if (err < 0) | 388 | if (err < 0) |
373 | return err; | 389 | return err; |
@@ -382,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, | |||
382 | revoke_exclusive(desc, UBI_READWRITE); | 398 | revoke_exclusive(desc, UBI_READWRITE); |
383 | } | 399 | } |
384 | 400 | ||
385 | *offp += count; | ||
386 | return count; | 401 | return count; |
387 | } | 402 | } |
388 | 403 | ||
@@ -427,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
427 | if (err < 0) | 442 | if (err < 0) |
428 | break; | 443 | break; |
429 | 444 | ||
430 | err = ubi_start_update(ubi, vol->vol_id, bytes); | 445 | err = ubi_start_update(ubi, vol, bytes); |
431 | if (bytes == 0) | 446 | if (bytes == 0) |
432 | revoke_exclusive(desc, UBI_READWRITE); | 447 | revoke_exclusive(desc, UBI_READWRITE); |
448 | break; | ||
449 | } | ||
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; | ||
433 | 481 | ||
434 | file->f_pos = 0; | 482 | err = ubi_start_leb_change(ubi, vol, &req); |
483 | if (req.bytes == 0) | ||
484 | revoke_exclusive(desc, UBI_READWRITE); | ||
435 | break; | 485 | break; |
436 | } | 486 | } |
437 | 487 | ||
@@ -447,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
447 | break; | 497 | break; |
448 | } | 498 | } |
449 | 499 | ||
450 | if (desc->mode == UBI_READONLY) { | 500 | if (desc->mode == UBI_READONLY || |
501 | vol->vol_type == UBI_STATIC_VOLUME) { | ||
451 | err = -EROFS; | 502 | err = -EROFS; |
452 | break; | 503 | break; |
453 | } | 504 | } |
@@ -457,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
457 | break; | 508 | break; |
458 | } | 509 | } |
459 | 510 | ||
460 | if (vol->vol_type != UBI_DYNAMIC_VOLUME) { | ||
461 | err = -EROFS; | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); | 511 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); |
466 | err = ubi_eba_unmap_leb(ubi, vol, lnum); | 512 | err = ubi_eba_unmap_leb(ubi, vol, lnum); |
467 | if (err) | 513 | if (err) |