aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 16:34:11 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 16:34:11 -0500
commit4935361766cc73949fe032cd157d314f288922ba (patch)
tree1584f81525ae05a04d515b13a4787cd8eed46029 /fs
parent2874b391bd78a5b8cb84be67297a345fbdec4ac8 (diff)
parent4f65992381112acd7d2732665a9eae492c2c9de6 (diff)
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (49 commits) [MTD] [NAND] S3C2412 fix hw ecc [MTD] [NAND] Work around false compiler warning in CAFÉ driver [JFFS2] printk warning fixes [MTD] [MAPS] ichxrom warning fix [MTD] [MAPS] amd76xrom warning fix [MTD] [MAPS] esb2rom warning fixes [MTD] [MAPS] ck804xrom warning fix [MTD] [MAPS] netsc520 warning fix [MTD] [MAPS] sc520cdp warning fix [MTD] [ONENAND] onenand_base warning fix [MTD] [NAND] eXcite nand flash driver [MTD] Improve heuristic for detecting wrong-endian RedBoot partition table [MTD] Fix RedBoot partition parsing regression harder. [MTD] [NAND] S3C2410: Hardware ECC correction code [JFFS2] Use MTD_OOB_AUTO to automatically place cleanmarker on NAND [MTD] Clarify OOB-operation interface comments [MTD] remove unused ecctype,eccsize fields from struct mtd_info [MTD] [NOR] Intel: remove ugly PROGREGION macros [MTD] [NOR] STAA: use writesize instead off eccsize to represent ECC block [MTD] OneNAND: Invalidate bufferRAM after erase ...
Diffstat (limited to 'fs')
-rw-r--r--fs/jffs2/build.c22
-rw-r--r--fs/jffs2/jffs2_fs_sb.h12
-rw-r--r--fs/jffs2/scan.c10
-rw-r--r--fs/jffs2/wbuf.c203
4 files changed, 90 insertions, 157 deletions
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 02826967ab58..07119c42a861 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -348,23 +348,27 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
348 348
349 ret = jffs2_sum_init(c); 349 ret = jffs2_sum_init(c);
350 if (ret) 350 if (ret)
351 return ret; 351 goto out_free;
352 352
353 if (jffs2_build_filesystem(c)) { 353 if (jffs2_build_filesystem(c)) {
354 dbg_fsbuild("build_fs failed\n"); 354 dbg_fsbuild("build_fs failed\n");
355 jffs2_free_ino_caches(c); 355 jffs2_free_ino_caches(c);
356 jffs2_free_raw_node_refs(c); 356 jffs2_free_raw_node_refs(c);
357#ifndef __ECOS 357 ret = -EIO;
358 if (jffs2_blocks_use_vmalloc(c)) 358 goto out_free;
359 vfree(c->blocks);
360 else
361#endif
362 kfree(c->blocks);
363
364 return -EIO;
365 } 359 }
366 360
367 jffs2_calc_trigger_levels(c); 361 jffs2_calc_trigger_levels(c);
368 362
369 return 0; 363 return 0;
364
365 out_free:
366#ifndef __ECOS
367 if (jffs2_blocks_use_vmalloc(c))
368 vfree(c->blocks);
369 else
370#endif
371 kfree(c->blocks);
372
373 return ret;
370} 374}
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index b98594992eed..ea88f69af130 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -98,20 +98,14 @@ struct jffs2_sb_info {
98 uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ 98 uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
99 99
100#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 100#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
101 /* Write-behind buffer for NAND flash */ 101 unsigned char *wbuf; /* Write-behind buffer for NAND flash */
102 unsigned char *wbuf;
103 unsigned char *oobbuf;
104 uint32_t wbuf_ofs; 102 uint32_t wbuf_ofs;
105 uint32_t wbuf_len; 103 uint32_t wbuf_len;
106 struct jffs2_inodirty *wbuf_inodes; 104 struct jffs2_inodirty *wbuf_inodes;
107
108 struct rw_semaphore wbuf_sem; /* Protects the write buffer */ 105 struct rw_semaphore wbuf_sem; /* Protects the write buffer */
109 106
110 /* Information about out-of-band area usage... */ 107 unsigned char *oobbuf;
111 struct nand_ecclayout *ecclayout; 108 int oobavail; /* How many bytes are available for JFFS2 in OOB */
112 uint32_t badblock_pos;
113 uint32_t fsdata_pos;
114 uint32_t fsdata_len;
115#endif 109#endif
116 110
117 struct jffs2_summary *summary; /* Summary information */ 111 struct jffs2_summary *summary; /* Summary information */
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 3af746eaff0e..31c1475d922a 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -450,16 +450,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
450 450
451#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 451#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
452 if (jffs2_cleanmarker_oob(c)) { 452 if (jffs2_cleanmarker_oob(c)) {
453 int ret = jffs2_check_nand_cleanmarker(c, jeb); 453 int ret;
454
455 if (c->mtd->block_isbad(c->mtd, jeb->offset))
456 return BLK_STATE_BADBLOCK;
457
458 ret = jffs2_check_nand_cleanmarker(c, jeb);
454 D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); 459 D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
460
455 /* Even if it's not found, we still scan to see 461 /* Even if it's not found, we still scan to see
456 if the block is empty. We use this information 462 if the block is empty. We use this information
457 to decide whether to erase it or not. */ 463 to decide whether to erase it or not. */
458 switch (ret) { 464 switch (ret) {
459 case 0: cleanmarkerfound = 1; break; 465 case 0: cleanmarkerfound = 1; break;
460 case 1: break; 466 case 1: break;
461 case 2: return BLK_STATE_BADBLOCK;
462 case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
463 default: return ret; 467 default: return ret;
464 } 468 }
465 } 469 }
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 9c99859f5edd..de718e3a1692 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -957,43 +957,48 @@ exit:
957 return ret; 957 return ret;
958} 958}
959 959
960#define NR_OOB_SCAN_PAGES 4 960#define NR_OOB_SCAN_PAGES 4
961
962/* For historical reasons we use only 12 bytes for OOB clean marker */
963#define OOB_CM_SIZE 12
964
965static const struct jffs2_unknown_node oob_cleanmarker =
966{
967 .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
968 .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
969 .totlen = cpu_to_je32(8)
970};
961 971
962/* 972/*
963 * Check, if the out of band area is empty 973 * Check, if the out of band area is empty. This function knows about the clean
974 * marker and if it is present in OOB, treats the OOB as empty anyway.
964 */ 975 */
965int jffs2_check_oob_empty(struct jffs2_sb_info *c, 976int jffs2_check_oob_empty(struct jffs2_sb_info *c,
966 struct jffs2_eraseblock *jeb, int mode) 977 struct jffs2_eraseblock *jeb, int mode)
967{ 978{
968 int i, page, ret; 979 int i, ret;
969 int oobsize = c->mtd->oobsize; 980 int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
970 struct mtd_oob_ops ops; 981 struct mtd_oob_ops ops;
971 982
972 ops.ooblen = NR_OOB_SCAN_PAGES * oobsize; 983 ops.mode = MTD_OOB_AUTO;
984 ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;
973 ops.oobbuf = c->oobbuf; 985 ops.oobbuf = c->oobbuf;
974 ops.ooboffs = 0; 986 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
975 ops.datbuf = NULL; 987 ops.datbuf = NULL;
976 ops.mode = MTD_OOB_PLACE;
977 988
978 ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops); 989 ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
979 if (ret) { 990 if (ret || ops.oobretlen != ops.ooblen) {
980 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " 991 printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
981 "failed %d for block at %08x\n", ret, jeb->offset)); 992 " bytes, read %zd bytes, error %d\n",
993 jeb->offset, ops.ooblen, ops.oobretlen, ret);
994 if (!ret)
995 ret = -EIO;
982 return ret; 996 return ret;
983 } 997 }
984 998
985 if (ops.oobretlen < ops.ooblen) { 999 for(i = 0; i < ops.ooblen; i++) {
986 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " 1000 if (mode && i < cmlen)
987 "returned short read (%zd bytes not %d) for block " 1001 /* Yeah, we know about the cleanmarker */
988 "at %08x\n", ops.oobretlen, ops.ooblen, jeb->offset));
989 return -EIO;
990 }
991
992 /* Special check for first page */
993 for(i = 0; i < oobsize ; i++) {
994 /* Yeah, we know about the cleanmarker. */
995 if (mode && i >= c->fsdata_pos &&
996 i < c->fsdata_pos + c->fsdata_len)
997 continue; 1002 continue;
998 1003
999 if (ops.oobbuf[i] != 0xFF) { 1004 if (ops.oobbuf[i] != 0xFF) {
@@ -1003,111 +1008,63 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
1003 } 1008 }
1004 } 1009 }
1005 1010
1006 /* we know, we are aligned :) */
1007 for (page = oobsize; page < ops.ooblen; page += sizeof(long)) {
1008 long dat = *(long *)(&ops.oobbuf[page]);
1009 if(dat != -1)
1010 return 1;
1011 }
1012 return 0; 1011 return 0;
1013} 1012}
1014 1013
1015/* 1014/*
1016 * Scan for a valid cleanmarker and for bad blocks 1015 * Check for a valid cleanmarker.
1016 * Returns: 0 if a valid cleanmarker was found
1017 * 1 if no cleanmarker was found
1018 * negative error code if an error occurred
1017 */ 1019 */
1018int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, 1020int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
1019 struct jffs2_eraseblock *jeb) 1021 struct jffs2_eraseblock *jeb)
1020{ 1022{
1021 struct jffs2_unknown_node n;
1022 struct mtd_oob_ops ops; 1023 struct mtd_oob_ops ops;
1023 int oobsize = c->mtd->oobsize; 1024 int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
1024 unsigned char *p,*b;
1025 int i, ret;
1026 size_t offset = jeb->offset;
1027
1028 /* Check first if the block is bad. */
1029 if (c->mtd->block_isbad(c->mtd, offset)) {
1030 D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker()"
1031 ": Bad block at %08x\n", jeb->offset));
1032 return 2;
1033 }
1034 1025
1035 ops.ooblen = oobsize; 1026 ops.mode = MTD_OOB_AUTO;
1027 ops.ooblen = cmlen;
1036 ops.oobbuf = c->oobbuf; 1028 ops.oobbuf = c->oobbuf;
1037 ops.ooboffs = 0; 1029 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
1038 ops.datbuf = NULL; 1030 ops.datbuf = NULL;
1039 ops.mode = MTD_OOB_PLACE;
1040 1031
1041 ret = c->mtd->read_oob(c->mtd, offset, &ops); 1032 ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
1042 if (ret) { 1033 if (ret || ops.oobretlen != ops.ooblen) {
1043 D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): " 1034 printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
1044 "Read OOB failed %d for block at %08x\n", 1035 " bytes, read %zd bytes, error %d\n",
1045 ret, jeb->offset)); 1036 jeb->offset, ops.ooblen, ops.oobretlen, ret);
1037 if (!ret)
1038 ret = -EIO;
1046 return ret; 1039 return ret;
1047 } 1040 }
1048 1041
1049 if (ops.oobretlen < ops.ooblen) { 1042 return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen);
1050 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): "
1051 "Read OOB return short read (%zd bytes not %d) "
1052 "for block at %08x\n", ops.oobretlen, ops.ooblen,
1053 jeb->offset));
1054 return -EIO;
1055 }
1056
1057 n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
1058 n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
1059 n.totlen = cpu_to_je32 (8);
1060 p = (unsigned char *) &n;
1061 b = c->oobbuf + c->fsdata_pos;
1062
1063 for (i = c->fsdata_len; i; i--) {
1064 if (*b++ != *p++)
1065 ret = 1;
1066 }
1067
1068 D1(if (ret == 1) {
1069 printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
1070 "Cleanmarker node not detected in block at %08x\n",
1071 offset);
1072 printk(KERN_WARNING "OOB at %08zx was ", offset);
1073 for (i=0; i < oobsize; i++)
1074 printk("%02x ", c->oobbuf[i]);
1075 printk("\n");
1076 });
1077 return ret;
1078} 1043}
1079 1044
1080int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, 1045int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
1081 struct jffs2_eraseblock *jeb) 1046 struct jffs2_eraseblock *jeb)
1082{ 1047{
1083 struct jffs2_unknown_node n; 1048 int ret;
1084 int ret;
1085 struct mtd_oob_ops ops; 1049 struct mtd_oob_ops ops;
1050 int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
1086 1051
1087 n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 1052 ops.mode = MTD_OOB_AUTO;
1088 n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); 1053 ops.ooblen = cmlen;
1089 n.totlen = cpu_to_je32(8); 1054 ops.oobbuf = (uint8_t *)&oob_cleanmarker;
1090 1055 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
1091 ops.ooblen = c->fsdata_len;
1092 ops.oobbuf = (uint8_t *)&n;
1093 ops.ooboffs = c->fsdata_pos;
1094 ops.datbuf = NULL; 1056 ops.datbuf = NULL;
1095 ops.mode = MTD_OOB_PLACE;
1096 1057
1097 ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops); 1058 ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops);
1098 1059 if (ret || ops.oobretlen != ops.ooblen) {
1099 if (ret) { 1060 printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"
1100 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): " 1061 " bytes, read %zd bytes, error %d\n",
1101 "Write failed for block at %08x: error %d\n", 1062 jeb->offset, ops.ooblen, ops.oobretlen, ret);
1102 jeb->offset, ret)); 1063 if (!ret)
1064 ret = -EIO;
1103 return ret; 1065 return ret;
1104 } 1066 }
1105 if (ops.oobretlen != ops.ooblen) { 1067
1106 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
1107 "Short write for block at %08x: %zd not %d\n",
1108 jeb->offset, ops.oobretlen, ops.ooblen));
1109 return -EIO;
1110 }
1111 return 0; 1068 return 0;
1112} 1069}
1113 1070
@@ -1140,41 +1097,24 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
1140 return 1; 1097 return 1;
1141} 1098}
1142 1099
1143static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) 1100int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1144{ 1101{
1145 struct nand_ecclayout *oinfo = c->mtd->ecclayout; 1102 struct nand_ecclayout *oinfo = c->mtd->ecclayout;
1146 1103
1147 /* Do this only, if we have an oob buffer */
1148 if (!c->mtd->oobsize) 1104 if (!c->mtd->oobsize)
1149 return 0; 1105 return 0;
1150 1106
1151 /* Cleanmarker is out-of-band, so inline size zero */ 1107 /* Cleanmarker is out-of-band, so inline size zero */
1152 c->cleanmarker_size = 0; 1108 c->cleanmarker_size = 0;
1153 1109
1154 /* Should we use autoplacement ? */ 1110 if (!oinfo || oinfo->oobavail == 0) {
1155 if (!oinfo) { 1111 printk(KERN_ERR "inconsistent device description\n");
1156 D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
1157 return -EINVAL; 1112 return -EINVAL;
1158 } 1113 }
1159 1114
1160 D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n")); 1115 D1(printk(KERN_DEBUG "JFFS2 using OOB on NAND\n"));
1161 /* Get the position of the free bytes */
1162 if (!oinfo->oobfree[0].length) {
1163 printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep."
1164 " Autoplacement selected and no empty space in oob\n");
1165 return -ENOSPC;
1166 }
1167 c->fsdata_pos = oinfo->oobfree[0].offset;
1168 c->fsdata_len = oinfo->oobfree[0].length;
1169 if (c->fsdata_len > 8)
1170 c->fsdata_len = 8;
1171 1116
1172 return 0; 1117 c->oobavail = oinfo->oobavail;
1173}
1174
1175int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1176{
1177 int res;
1178 1118
1179 /* Initialise write buffer */ 1119 /* Initialise write buffer */
1180 init_rwsem(&c->wbuf_sem); 1120 init_rwsem(&c->wbuf_sem);
@@ -1185,22 +1125,13 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1185 if (!c->wbuf) 1125 if (!c->wbuf)
1186 return -ENOMEM; 1126 return -ENOMEM;
1187 1127
1188 c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->mtd->oobsize, GFP_KERNEL); 1128 c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->oobavail, GFP_KERNEL);
1189 if (!c->oobbuf) 1129 if (!c->oobbuf) {
1190 return -ENOMEM;
1191
1192 res = jffs2_nand_set_oobinfo(c);
1193
1194#ifdef BREAKME
1195 if (!brokenbuf)
1196 brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1197 if (!brokenbuf) {
1198 kfree(c->wbuf); 1130 kfree(c->wbuf);
1199 return -ENOMEM; 1131 return -ENOMEM;
1200 } 1132 }
1201 memset(brokenbuf, 0xdb, c->wbuf_pagesize); 1133
1202#endif 1134 return 0;
1203 return res;
1204} 1135}
1205 1136
1206void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) 1137void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)