diff options
author | Tom Rini | 2013-02-22 15:55:19 -0600 |
---|---|---|
committer | Tom Rini | 2013-03-12 13:22:31 -0500 |
commit | d8699dca33973ba7813949b9e0eea292eeec7293 (patch) | |
tree | a767f6834c18b17feec4abb9a928b16cd326d646 | |
parent | c79739dd35caaf9fd66c007aff5d32f2bfb6ac15 (diff) | |
download | ti-u-boot-d8699dca33973ba7813949b9e0eea292eeec7293.tar.gz ti-u-boot-d8699dca33973ba7813949b9e0eea292eeec7293.tar.xz ti-u-boot-d8699dca33973ba7813949b9e0eea292eeec7293.zip |
nand: Extend nand_(read|write)_skip_bad with *actual and limit parameters
We make these two functions take a size_t pointer to how much space
was used on NAND to read or write the buffer (when reads/writes happen)
so that bad blocks can be accounted for. We also make them take an
loff_t limit on how much data can be read or written. This means that
we can now catch the case of when writing to a partition would exceed
the partition size due to bad blocks. To do this we also need to make
check_skip_len count not just complete blocks used but partial ones as
well. All callers of nand_(read|write)_skip_bad are adjusted to call
these with the most sensible limits available.
The changes were started by Pantelis and finished by Tom.
Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Tom Rini <trini@ti.com>
-rw-r--r-- | common/cmd_nand.c | 53 | ||||
-rw-r--r-- | common/env_nand.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 68 | ||||
-rw-r--r-- | include/nand.h | 4 |
4 files changed, 95 insertions, 33 deletions
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 1568594ca4..54107933bf 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c | |||
@@ -137,7 +137,8 @@ static inline int str2long(const char *p, ulong *num) | |||
137 | return *p != '\0' && *endptr == '\0'; | 137 | return *p != '\0' && *endptr == '\0'; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) | 140 | static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, |
141 | loff_t *maxsize) | ||
141 | { | 142 | { |
142 | #ifdef CONFIG_CMD_MTDPARTS | 143 | #ifdef CONFIG_CMD_MTDPARTS |
143 | struct mtd_device *dev; | 144 | struct mtd_device *dev; |
@@ -160,6 +161,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) | |||
160 | 161 | ||
161 | *off = part->offset; | 162 | *off = part->offset; |
162 | *size = part->size; | 163 | *size = part->size; |
164 | *maxsize = part->size; | ||
163 | *idx = dev->id->num; | 165 | *idx = dev->id->num; |
164 | 166 | ||
165 | ret = set_dev(*idx); | 167 | ret = set_dev(*idx); |
@@ -173,10 +175,11 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) | |||
173 | #endif | 175 | #endif |
174 | } | 176 | } |
175 | 177 | ||
176 | static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) | 178 | static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, |
179 | loff_t *maxsize) | ||
177 | { | 180 | { |
178 | if (!str2off(arg, off)) | 181 | if (!str2off(arg, off)) |
179 | return get_part(arg, idx, off, maxsize); | 182 | return get_part(arg, idx, off, size, maxsize); |
180 | 183 | ||
181 | if (*off >= nand_info[*idx].size) { | 184 | if (*off >= nand_info[*idx].size) { |
182 | puts("Offset exceeds device limit\n"); | 185 | puts("Offset exceeds device limit\n"); |
@@ -184,36 +187,35 @@ static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) | |||
184 | } | 187 | } |
185 | 188 | ||
186 | *maxsize = nand_info[*idx].size - *off; | 189 | *maxsize = nand_info[*idx].size - *off; |
190 | *size = *maxsize; | ||
187 | return 0; | 191 | return 0; |
188 | } | 192 | } |
189 | 193 | ||
190 | static int arg_off_size(int argc, char *const argv[], int *idx, | 194 | static int arg_off_size(int argc, char *const argv[], int *idx, |
191 | loff_t *off, loff_t *size) | 195 | loff_t *off, loff_t *size, loff_t *maxsize) |
192 | { | 196 | { |
193 | int ret; | 197 | int ret; |
194 | loff_t maxsize = 0; | ||
195 | 198 | ||
196 | if (argc == 0) { | 199 | if (argc == 0) { |
197 | *off = 0; | 200 | *off = 0; |
198 | *size = nand_info[*idx].size; | 201 | *size = nand_info[*idx].size; |
202 | *maxsize = *size; | ||
199 | goto print; | 203 | goto print; |
200 | } | 204 | } |
201 | 205 | ||
202 | ret = arg_off(argv[0], idx, off, &maxsize); | 206 | ret = arg_off(argv[0], idx, off, size, maxsize); |
203 | if (ret) | 207 | if (ret) |
204 | return ret; | 208 | return ret; |
205 | 209 | ||
206 | if (argc == 1) { | 210 | if (argc == 1) |
207 | *size = maxsize; | ||
208 | goto print; | 211 | goto print; |
209 | } | ||
210 | 212 | ||
211 | if (!str2off(argv[1], size)) { | 213 | if (!str2off(argv[1], size)) { |
212 | printf("'%s' is not a number\n", argv[1]); | 214 | printf("'%s' is not a number\n", argv[1]); |
213 | return -1; | 215 | return -1; |
214 | } | 216 | } |
215 | 217 | ||
216 | if (*size > maxsize) { | 218 | if (*size > *maxsize) { |
217 | puts("Size exceeds partition or device limit\n"); | 219 | puts("Size exceeds partition or device limit\n"); |
218 | return -1; | 220 | return -1; |
219 | } | 221 | } |
@@ -307,7 +309,8 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) | |||
307 | if (argc < 3) | 309 | if (argc < 3) |
308 | goto usage; | 310 | goto usage; |
309 | 311 | ||
310 | if (arg_off(argv[2], &idx, &addr, &maxsize)) { | 312 | /* We don't care about size, or maxsize. */ |
313 | if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) { | ||
311 | puts("Offset or partition name expected\n"); | 314 | puts("Offset or partition name expected\n"); |
312 | return 1; | 315 | return 1; |
313 | } | 316 | } |
@@ -432,7 +435,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
432 | { | 435 | { |
433 | int i, ret = 0; | 436 | int i, ret = 0; |
434 | ulong addr; | 437 | ulong addr; |
435 | loff_t off, size; | 438 | loff_t off, size, maxsize; |
436 | char *cmd, *s; | 439 | char *cmd, *s; |
437 | nand_info_t *nand; | 440 | nand_info_t *nand; |
438 | #ifdef CONFIG_SYS_NAND_QUIET | 441 | #ifdef CONFIG_SYS_NAND_QUIET |
@@ -557,7 +560,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
557 | 560 | ||
558 | printf("\nNAND %s: ", cmd); | 561 | printf("\nNAND %s: ", cmd); |
559 | /* skip first two or three arguments, look for offset and size */ | 562 | /* skip first two or three arguments, look for offset and size */ |
560 | if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0) | 563 | if (arg_off_size(argc - o, argv + o, &dev, &off, &size, |
564 | &maxsize) != 0) | ||
561 | return 1; | 565 | return 1; |
562 | 566 | ||
563 | nand = &nand_info[dev]; | 567 | nand = &nand_info[dev]; |
@@ -625,7 +629,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
625 | if (s && !strcmp(s, ".raw")) { | 629 | if (s && !strcmp(s, ".raw")) { |
626 | raw = 1; | 630 | raw = 1; |
627 | 631 | ||
628 | if (arg_off(argv[3], &dev, &off, &size)) | 632 | if (arg_off(argv[3], &dev, &off, &size, &maxsize)) |
629 | return 1; | 633 | return 1; |
630 | 634 | ||
631 | if (argc > 4 && !str2long(argv[4], &pagecount)) { | 635 | if (argc > 4 && !str2long(argv[4], &pagecount)) { |
@@ -641,7 +645,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
641 | rwsize = pagecount * (nand->writesize + nand->oobsize); | 645 | rwsize = pagecount * (nand->writesize + nand->oobsize); |
642 | } else { | 646 | } else { |
643 | if (arg_off_size(argc - 3, argv + 3, &dev, | 647 | if (arg_off_size(argc - 3, argv + 3, &dev, |
644 | &off, &size) != 0) | 648 | &off, &size, &maxsize) != 0) |
645 | return 1; | 649 | return 1; |
646 | 650 | ||
647 | rwsize = size; | 651 | rwsize = size; |
@@ -651,9 +655,11 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
651 | !strcmp(s, ".e") || !strcmp(s, ".i")) { | 655 | !strcmp(s, ".e") || !strcmp(s, ".i")) { |
652 | if (read) | 656 | if (read) |
653 | ret = nand_read_skip_bad(nand, off, &rwsize, | 657 | ret = nand_read_skip_bad(nand, off, &rwsize, |
658 | NULL, maxsize, | ||
654 | (u_char *)addr); | 659 | (u_char *)addr); |
655 | else | 660 | else |
656 | ret = nand_write_skip_bad(nand, off, &rwsize, | 661 | ret = nand_write_skip_bad(nand, off, &rwsize, |
662 | NULL, maxsize, | ||
657 | (u_char *)addr, 0); | 663 | (u_char *)addr, 0); |
658 | #ifdef CONFIG_CMD_NAND_TRIMFFS | 664 | #ifdef CONFIG_CMD_NAND_TRIMFFS |
659 | } else if (!strcmp(s, ".trimffs")) { | 665 | } else if (!strcmp(s, ".trimffs")) { |
@@ -661,8 +667,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
661 | printf("Unknown nand command suffix '%s'\n", s); | 667 | printf("Unknown nand command suffix '%s'\n", s); |
662 | return 1; | 668 | return 1; |
663 | } | 669 | } |
664 | ret = nand_write_skip_bad(nand, off, &rwsize, | 670 | ret = nand_write_skip_bad(nand, off, &rwsize, NULL, |
665 | (u_char *)addr, | 671 | maxsize, (u_char *)addr, |
666 | WITH_DROP_FFS); | 672 | WITH_DROP_FFS); |
667 | #endif | 673 | #endif |
668 | #ifdef CONFIG_CMD_NAND_YAFFS | 674 | #ifdef CONFIG_CMD_NAND_YAFFS |
@@ -671,8 +677,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
671 | printf("Unknown nand command suffix '%s'.\n", s); | 677 | printf("Unknown nand command suffix '%s'.\n", s); |
672 | return 1; | 678 | return 1; |
673 | } | 679 | } |
674 | ret = nand_write_skip_bad(nand, off, &rwsize, | 680 | ret = nand_write_skip_bad(nand, off, &rwsize, NULL, |
675 | (u_char *)addr, | 681 | maxsize, (u_char *)addr, |
676 | WITH_INLINE_OOB); | 682 | WITH_INLINE_OOB); |
677 | #endif | 683 | #endif |
678 | } else if (!strcmp(s, ".oob")) { | 684 | } else if (!strcmp(s, ".oob")) { |
@@ -781,7 +787,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |||
781 | if (s && !strcmp(s, ".allexcept")) | 787 | if (s && !strcmp(s, ".allexcept")) |
782 | allexcept = 1; | 788 | allexcept = 1; |
783 | 789 | ||
784 | if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) | 790 | if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size, |
791 | &maxsize) < 0) | ||
785 | return 1; | 792 | return 1; |
786 | 793 | ||
787 | if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { | 794 | if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { |
@@ -879,7 +886,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, | |||
879 | printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); | 886 | printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); |
880 | 887 | ||
881 | cnt = nand->writesize; | 888 | cnt = nand->writesize; |
882 | r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); | 889 | r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, |
890 | (u_char *) addr); | ||
883 | if (r) { | 891 | if (r) { |
884 | puts("** Read error\n"); | 892 | puts("** Read error\n"); |
885 | bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ); | 893 | bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ); |
@@ -911,7 +919,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, | |||
911 | } | 919 | } |
912 | bootstage_mark(BOOTSTAGE_ID_NAND_TYPE); | 920 | bootstage_mark(BOOTSTAGE_ID_NAND_TYPE); |
913 | 921 | ||
914 | r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); | 922 | r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, |
923 | (u_char *) addr); | ||
915 | if (r) { | 924 | if (r) { |
916 | puts("** Read error\n"); | 925 | puts("** Read error\n"); |
917 | bootstage_error(BOOTSTAGE_ID_NAND_READ); | 926 | bootstage_error(BOOTSTAGE_ID_NAND_READ); |
diff --git a/common/env_nand.c b/common/env_nand.c index 22e72a20b0..123bcc7273 100644 --- a/common/env_nand.c +++ b/common/env_nand.c | |||
@@ -281,7 +281,8 @@ int readenv(size_t offset, u_char *buf) | |||
281 | } else { | 281 | } else { |
282 | char_ptr = &buf[amount_loaded]; | 282 | char_ptr = &buf[amount_loaded]; |
283 | if (nand_read_skip_bad(&nand_info[0], offset, | 283 | if (nand_read_skip_bad(&nand_info[0], offset, |
284 | &len, char_ptr)) | 284 | &len, NULL, |
285 | nand_info[0].size, char_ptr)) | ||
285 | return 1; | 286 | return 1; |
286 | 287 | ||
287 | offset += blocksize; | 288 | offset += blocksize; |
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2ba0c5ef95..a5c91f833a 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c | |||
@@ -399,11 +399,13 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, | |||
399 | * @param nand NAND device | 399 | * @param nand NAND device |
400 | * @param offset offset in flash | 400 | * @param offset offset in flash |
401 | * @param length image length | 401 | * @param length image length |
402 | * @param used length of flash needed for the requested length | ||
402 | * @return 0 if the image fits and there are no bad blocks | 403 | * @return 0 if the image fits and there are no bad blocks |
403 | * 1 if the image fits, but there are bad blocks | 404 | * 1 if the image fits, but there are bad blocks |
404 | * -1 if the image does not fit | 405 | * -1 if the image does not fit |
405 | */ | 406 | */ |
406 | static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) | 407 | static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length, |
408 | size_t *used) | ||
407 | { | 409 | { |
408 | size_t len_excl_bad = 0; | 410 | size_t len_excl_bad = 0; |
409 | int ret = 0; | 411 | int ret = 0; |
@@ -425,8 +427,13 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) | |||
425 | ret = 1; | 427 | ret = 1; |
426 | 428 | ||
427 | offset += block_len; | 429 | offset += block_len; |
430 | *used += block_len; | ||
428 | } | 431 | } |
429 | 432 | ||
433 | /* If the length is not a multiple of block_len, adjust. */ | ||
434 | if (len_excl_bad > length) | ||
435 | *used -= (len_excl_bad - length); | ||
436 | |||
430 | return ret; | 437 | return ret; |
431 | } | 438 | } |
432 | 439 | ||
@@ -459,23 +466,36 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, | |||
459 | * Write image to NAND flash. | 466 | * Write image to NAND flash. |
460 | * Blocks that are marked bad are skipped and the is written to the next | 467 | * Blocks that are marked bad are skipped and the is written to the next |
461 | * block instead as long as the image is short enough to fit even after | 468 | * block instead as long as the image is short enough to fit even after |
462 | * skipping the bad blocks. | 469 | * skipping the bad blocks. Due to bad blocks we may not be able to |
470 | * perform the requested write. In the case where the write would | ||
471 | * extend beyond the end of the NAND device, both length and actual (if | ||
472 | * not NULL) are set to 0. In the case where the write would extend | ||
473 | * beyond the limit we are passed, length is set to 0 and actual is set | ||
474 | * to the required length. | ||
463 | * | 475 | * |
464 | * @param nand NAND device | 476 | * @param nand NAND device |
465 | * @param offset offset in flash | 477 | * @param offset offset in flash |
466 | * @param length buffer length | 478 | * @param length buffer length |
479 | * @param actual set to size required to write length worth of | ||
480 | * buffer or 0 on error, if not NULL | ||
481 | * @param lim maximum size that actual may be in order to not | ||
482 | * exceed the buffer | ||
467 | * @param buffer buffer to read from | 483 | * @param buffer buffer to read from |
468 | * @param flags flags modifying the behaviour of the write to NAND | 484 | * @param flags flags modifying the behaviour of the write to NAND |
469 | * @return 0 in case of success | 485 | * @return 0 in case of success |
470 | */ | 486 | */ |
471 | int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | 487 | int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, |
472 | u_char *buffer, int flags) | 488 | size_t *actual, loff_t lim, u_char *buffer, int flags) |
473 | { | 489 | { |
474 | int rval = 0, blocksize; | 490 | int rval = 0, blocksize; |
475 | size_t left_to_write = *length; | 491 | size_t left_to_write = *length; |
492 | size_t used_for_write = 0; | ||
476 | u_char *p_buffer = buffer; | 493 | u_char *p_buffer = buffer; |
477 | int need_skip; | 494 | int need_skip; |
478 | 495 | ||
496 | if (actual) | ||
497 | *actual = 0; | ||
498 | |||
479 | #ifdef CONFIG_CMD_NAND_YAFFS | 499 | #ifdef CONFIG_CMD_NAND_YAFFS |
480 | if (flags & WITH_YAFFS_OOB) { | 500 | if (flags & WITH_YAFFS_OOB) { |
481 | if (flags & ~WITH_YAFFS_OOB) | 501 | if (flags & ~WITH_YAFFS_OOB) |
@@ -512,13 +532,23 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | |||
512 | return -EINVAL; | 532 | return -EINVAL; |
513 | } | 533 | } |
514 | 534 | ||
515 | need_skip = check_skip_len(nand, offset, *length); | 535 | need_skip = check_skip_len(nand, offset, *length, &used_for_write); |
536 | |||
537 | if (actual) | ||
538 | *actual = used_for_write; | ||
539 | |||
516 | if (need_skip < 0) { | 540 | if (need_skip < 0) { |
517 | printf("Attempt to write outside the flash area\n"); | 541 | printf("Attempt to write outside the flash area\n"); |
518 | *length = 0; | 542 | *length = 0; |
519 | return -EINVAL; | 543 | return -EINVAL; |
520 | } | 544 | } |
521 | 545 | ||
546 | if (used_for_write > lim) { | ||
547 | puts("Size of write exceeds partition or device limit\n"); | ||
548 | *length = 0; | ||
549 | return -EFBIG; | ||
550 | } | ||
551 | |||
522 | if (!need_skip && !(flags & WITH_DROP_FFS)) { | 552 | if (!need_skip && !(flags & WITH_DROP_FFS)) { |
523 | rval = nand_write(nand, offset, length, buffer); | 553 | rval = nand_write(nand, offset, length, buffer); |
524 | if (rval == 0) | 554 | if (rval == 0) |
@@ -609,36 +639,58 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | |||
609 | * | 639 | * |
610 | * Read image from NAND flash. | 640 | * Read image from NAND flash. |
611 | * Blocks that are marked bad are skipped and the next block is read | 641 | * Blocks that are marked bad are skipped and the next block is read |
612 | * instead as long as the image is short enough to fit even after skipping the | 642 | * instead as long as the image is short enough to fit even after |
613 | * bad blocks. | 643 | * skipping the bad blocks. Due to bad blocks we may not be able to |
644 | * perform the requested read. In the case where the read would extend | ||
645 | * beyond the end of the NAND device, both length and actual (if not | ||
646 | * NULL) are set to 0. In the case where the read would extend beyond | ||
647 | * the limit we are passed, length is set to 0 and actual is set to the | ||
648 | * required length. | ||
614 | * | 649 | * |
615 | * @param nand NAND device | 650 | * @param nand NAND device |
616 | * @param offset offset in flash | 651 | * @param offset offset in flash |
617 | * @param length buffer length, on return holds number of read bytes | 652 | * @param length buffer length, on return holds number of read bytes |
653 | * @param actual set to size required to read length worth of buffer or 0 | ||
654 | * on error, if not NULL | ||
655 | * @param lim maximum size that actual may be in order to not exceed the | ||
656 | * buffer | ||
618 | * @param buffer buffer to write to | 657 | * @param buffer buffer to write to |
619 | * @return 0 in case of success | 658 | * @return 0 in case of success |
620 | */ | 659 | */ |
621 | int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | 660 | int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, |
622 | u_char *buffer) | 661 | size_t *actual, loff_t lim, u_char *buffer) |
623 | { | 662 | { |
624 | int rval; | 663 | int rval; |
625 | size_t left_to_read = *length; | 664 | size_t left_to_read = *length; |
665 | size_t used_for_read = 0; | ||
626 | u_char *p_buffer = buffer; | 666 | u_char *p_buffer = buffer; |
627 | int need_skip; | 667 | int need_skip; |
628 | 668 | ||
629 | if ((offset & (nand->writesize - 1)) != 0) { | 669 | if ((offset & (nand->writesize - 1)) != 0) { |
630 | printf("Attempt to read non page-aligned data\n"); | 670 | printf("Attempt to read non page-aligned data\n"); |
631 | *length = 0; | 671 | *length = 0; |
672 | if (actual) | ||
673 | *actual = 0; | ||
632 | return -EINVAL; | 674 | return -EINVAL; |
633 | } | 675 | } |
634 | 676 | ||
635 | need_skip = check_skip_len(nand, offset, *length); | 677 | need_skip = check_skip_len(nand, offset, *length, &used_for_read); |
678 | |||
679 | if (actual) | ||
680 | *actual = used_for_read; | ||
681 | |||
636 | if (need_skip < 0) { | 682 | if (need_skip < 0) { |
637 | printf("Attempt to read outside the flash area\n"); | 683 | printf("Attempt to read outside the flash area\n"); |
638 | *length = 0; | 684 | *length = 0; |
639 | return -EINVAL; | 685 | return -EINVAL; |
640 | } | 686 | } |
641 | 687 | ||
688 | if (used_for_read > lim) { | ||
689 | puts("Size of read exceeds partition or device limit\n"); | ||
690 | *length = 0; | ||
691 | return -EFBIG; | ||
692 | } | ||
693 | |||
642 | if (!need_skip) { | 694 | if (!need_skip) { |
643 | rval = nand_read(nand, offset, length, buffer); | 695 | rval = nand_read(nand, offset, length, buffer); |
644 | if (!rval || rval == -EUCLEAN) | 696 | if (!rval || rval == -EUCLEAN) |
diff --git a/include/nand.h b/include/nand.h index dded4e27f0..f0f3bf94b5 100644 --- a/include/nand.h +++ b/include/nand.h | |||
@@ -129,7 +129,7 @@ struct nand_erase_options { | |||
129 | typedef struct nand_erase_options nand_erase_options_t; | 129 | typedef struct nand_erase_options nand_erase_options_t; |
130 | 130 | ||
131 | int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | 131 | int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, |
132 | u_char *buffer); | 132 | size_t *actual, loff_t lim, u_char *buffer); |
133 | 133 | ||
134 | #define WITH_YAFFS_OOB (1 << 0) /* whether write with yaffs format. This flag | 134 | #define WITH_YAFFS_OOB (1 << 0) /* whether write with yaffs format. This flag |
135 | * is a 'mode' meaning it cannot be mixed with | 135 | * is a 'mode' meaning it cannot be mixed with |
@@ -137,7 +137,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | |||
137 | #define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */ | 137 | #define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */ |
138 | 138 | ||
139 | int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, | 139 | int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, |
140 | u_char *buffer, int flags); | 140 | size_t *actual, loff_t lim, u_char *buffer, int flags); |
141 | int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); | 141 | int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); |
142 | int nand_torture(nand_info_t *nand, loff_t offset); | 142 | int nand_torture(nand_info_t *nand, loff_t offset); |
143 | 143 | ||