aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/wbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2/wbuf.c')
-rw-r--r--fs/jffs2/wbuf.c203
1 files changed, 67 insertions, 136 deletions
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)