aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/jffs2_fs_sb.h1
-rw-r--r--fs/jffs2/wbuf.c230
2 files changed, 119 insertions, 112 deletions
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 506690cc9a7..935fec1b120 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -100,6 +100,7 @@ struct jffs2_sb_info {
100#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 100#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
101 /* Write-behind buffer for NAND flash */ 101 /* Write-behind buffer for NAND flash */
102 unsigned char *wbuf; 102 unsigned char *wbuf;
103 unsigned char *oobbuf;
103 uint32_t wbuf_ofs; 104 uint32_t wbuf_ofs;
104 uint32_t wbuf_len; 105 uint32_t wbuf_len;
105 struct jffs2_inodirty *wbuf_inodes; 106 struct jffs2_inodirty *wbuf_inodes;
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index c6a62e16296..1195d06d437 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -955,158 +955,159 @@ exit:
955 return ret; 955 return ret;
956} 956}
957 957
958#define NR_OOB_SCAN_PAGES 4
959
958/* 960/*
959 * Check, if the out of band area is empty 961 * Check, if the out of band area is empty
960 */ 962 */
961int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode) 963int jffs2_check_oob_empty(struct jffs2_sb_info *c,
964 struct jffs2_eraseblock *jeb, int mode)
962{ 965{
963 unsigned char *buf; 966 int i, page, ret;
964 int ret = 0; 967 int oobsize = c->mtd->oobsize;
965 int i,len,page; 968 struct mtd_oob_ops ops;
966 size_t retlen; 969
967 int oob_size; 970 ops.len = NR_OOB_SCAN_PAGES * oobsize;
968 971 ops.ooblen = oobsize;
969 /* allocate a buffer for all oob data in this sector */ 972 ops.oobbuf = c->oobbuf;
970 oob_size = c->mtd->oobsize; 973 ops.ooboffs = 0;
971 len = 4 * oob_size; 974 ops.datbuf = NULL;
972 buf = kmalloc(len, GFP_KERNEL); 975 ops.mode = MTD_OOB_PLACE;
973 if (!buf) { 976
974 printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); 977 ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);
975 return -ENOMEM;
976 }
977 /*
978 * if mode = 0, we scan for a total empty oob area, else we have
979 * to take care of the cleanmarker in the first page of the block
980 */
981 ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf);
982 if (ret) { 978 if (ret) {
983 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); 979 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB "
984 goto out; 980 "failed %d for block at %08x\n", ret, jeb->offset));
981 return ret;
985 } 982 }
986 983
987 if (retlen < len) { 984 if (ops.retlen < ops.len) {
988 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " 985 D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB "
989 "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); 986 "returned short read (%zd bytes not %d) for block "
990 ret = -EIO; 987 "at %08x\n", ops.retlen, ops.len, jeb->offset));
991 goto out; 988 return -EIO;
992 } 989 }
993 990
994 /* Special check for first page */ 991 /* Special check for first page */
995 for(i = 0; i < oob_size ; i++) { 992 for(i = 0; i < oobsize ; i++) {
996 /* Yeah, we know about the cleanmarker. */ 993 /* Yeah, we know about the cleanmarker. */
997 if (mode && i >= c->fsdata_pos && 994 if (mode && i >= c->fsdata_pos &&
998 i < c->fsdata_pos + c->fsdata_len) 995 i < c->fsdata_pos + c->fsdata_len)
999 continue; 996 continue;
1000 997
1001 if (buf[i] != 0xFF) { 998 if (ops.oobbuf[i] != 0xFF) {
1002 D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", 999 D2(printk(KERN_DEBUG "Found %02x at %x in OOB for "
1003 buf[i], i, jeb->offset)); 1000 "%08x\n", ops.oobbuf[i], i, jeb->offset));
1004 ret = 1; 1001 return 1;
1005 goto out;
1006 } 1002 }
1007 } 1003 }
1008 1004
1009 /* we know, we are aligned :) */ 1005 /* we know, we are aligned :) */
1010 for (page = oob_size; page < len; page += sizeof(long)) { 1006 for (page = oobsize; page < ops.len; page += sizeof(long)) {
1011 unsigned long dat = *(unsigned long *)(&buf[page]); 1007 long dat = *(long *)(&ops.oobbuf[page]);
1012 if(dat != -1) { 1008 if(dat != -1)
1013 ret = 1; 1009 return 1;
1014 goto out;
1015 }
1016 } 1010 }
1017 1011 return 0;
1018out:
1019 kfree(buf);
1020
1021 return ret;
1022} 1012}
1023 1013
1024/* 1014/*
1025* Scan for a valid cleanmarker and for bad blocks 1015 * Scan for a valid cleanmarker and for bad blocks
1026* For virtual blocks (concatenated physical blocks) check the cleanmarker 1016 */
1027* only in the first page of the first physical block, but scan for bad blocks in all 1017int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c,
1028* physical blocks 1018 struct jffs2_eraseblock *jeb)
1029*/
1030int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
1031{ 1019{
1032 struct jffs2_unknown_node n; 1020 struct jffs2_unknown_node n;
1033 unsigned char buf[2 * NAND_MAX_OOBSIZE]; 1021 struct mtd_oob_ops ops;
1034 unsigned char *p; 1022 int oobsize = c->mtd->oobsize;
1035 int ret, i, cnt, retval = 0; 1023 unsigned char *p,*b;
1036 size_t retlen, offset; 1024 int i, ret;
1037 int oob_size; 1025 size_t offset = jeb->offset;
1038 1026
1039 offset = jeb->offset; 1027 /* Check first if the block is bad. */
1040 oob_size = c->mtd->oobsize; 1028 if (c->mtd->block_isbad(c->mtd, offset)) {
1041 1029 D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker()"
1042 /* Loop through the physical blocks */ 1030 ": Bad block at %08x\n", jeb->offset));
1043 for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { 1031 return 2;
1044 /* Check first if the block is bad. */ 1032 }
1045 if (c->mtd->block_isbad (c->mtd, offset)) {
1046 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
1047 return 2;
1048 }
1049 /*
1050 * We read oob data from page 0 and 1 of the block.
1051 * page 0 contains cleanmarker and badblock info
1052 * page 1 contains failure count of this block
1053 */
1054 ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf);
1055 1033
1056 if (ret) { 1034 ops.len = oobsize;
1057 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); 1035 ops.ooblen = oobsize;
1058 return ret; 1036 ops.oobbuf = c->oobbuf;
1059 } 1037 ops.ooboffs = 0;
1060 if (retlen < (oob_size << 1)) { 1038 ops.datbuf = NULL;
1061 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); 1039 ops.mode = MTD_OOB_PLACE;
1062 return -EIO;
1063 }
1064 1040
1065 /* Check cleanmarker only on the first physical block */ 1041 ret = c->mtd->read_oob(c->mtd, offset, &ops);
1066 if (!cnt) { 1042 if (ret) {
1067 n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); 1043 D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): "
1068 n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); 1044 "Read OOB failed %d for block at %08x\n",
1069 n.totlen = cpu_to_je32 (8); 1045 ret, jeb->offset));
1070 p = (unsigned char *) &n; 1046 return ret;
1047 }
1071 1048
1072 for (i = 0; i < c->fsdata_len; i++) { 1049 if (ops.retlen < ops.len) {
1073 if (buf[c->fsdata_pos + i] != p[i]) { 1050 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): "
1074 retval = 1; 1051 "Read OOB return short read (%zd bytes not %d) "
1075 } 1052 "for block at %08x\n", ops.retlen, ops.len,
1076 } 1053 jeb->offset));
1077 D1(if (retval == 1) { 1054 return -EIO;
1078 printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
1079 printk(KERN_WARNING "OOB at %08zx was ", offset);
1080 for (i=0; i < oob_size; i++) {
1081 printk("%02x ", buf[i]);
1082 }
1083 printk("\n");
1084 })
1085 }
1086 offset += c->mtd->erasesize;
1087 } 1055 }
1088 return retval; 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;
1089} 1078}
1090 1079
1091int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 1080int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
1081 struct jffs2_eraseblock *jeb)
1092{ 1082{
1093 struct jffs2_unknown_node n; 1083 struct jffs2_unknown_node n;
1094 int ret; 1084 int ret;
1095 size_t retlen; 1085 struct mtd_oob_ops ops;
1096 1086
1097 n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 1087 n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1098 n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); 1088 n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
1099 n.totlen = cpu_to_je32(8); 1089 n.totlen = cpu_to_je32(8);
1100 1090
1101 ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); 1091 ops.len = c->fsdata_len;
1092 ops.ooblen = c->fsdata_len;;
1093 ops.oobbuf = (uint8_t *)&n;
1094 ops.ooboffs = c->fsdata_pos;
1095 ops.datbuf = NULL;
1096 ops.mode = MTD_OOB_PLACE;
1097
1098 ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops);
1102 1099
1103 if (ret) { 1100 if (ret) {
1104 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); 1101 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
1102 "Write failed for block at %08x: error %d\n",
1103 jeb->offset, ret));
1105 return ret; 1104 return ret;
1106 } 1105 }
1107 if (retlen != c->fsdata_len) { 1106 if (ops.retlen != ops.len) {
1108 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len)); 1107 D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): "
1109 return ret; 1108 "Short write for block at %08x: %zd not %d\n",
1109 jeb->offset, ops.retlen, ops.len));
1110 return -EIO;
1110 } 1111 }
1111 return 0; 1112 return 0;
1112} 1113}
@@ -1185,6 +1186,10 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1185 if (!c->wbuf) 1186 if (!c->wbuf)
1186 return -ENOMEM; 1187 return -ENOMEM;
1187 1188
1189 c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->mtd->oobsize, GFP_KERNEL);
1190 if (!c->oobbuf)
1191 return -ENOMEM;
1192
1188 res = jffs2_nand_set_oobinfo(c); 1193 res = jffs2_nand_set_oobinfo(c);
1189 1194
1190#ifdef BREAKME 1195#ifdef BREAKME
@@ -1202,6 +1207,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
1202void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) 1207void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
1203{ 1208{
1204 kfree(c->wbuf); 1209 kfree(c->wbuf);
1210 kfree(c->oobbuf);
1205} 1211}
1206 1212
1207int jffs2_dataflash_setup(struct jffs2_sb_info *c) { 1213int jffs2_dataflash_setup(struct jffs2_sb_info *c) {