aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.13/504-yaffs-fix-compat-tags-handling.patch
blob: a18cf6fd7bbb78d273a9c64ee6b057d0c152d0cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
pre { line-height: 125%; margin: 0; }
td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight { background: #ffffff; }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1577,6 +1577,10 @@ const struct inode_operations ubifs_syml
 	.follow_link = ubifs_follow_link,
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
+	.setxattr    = ubifs_setxattr,
+	.getxattr    = ubifs_getxattr,
+	.listxattr   = ubifs_listxattr,
+	.removexattr = ubifs_removexattr,
 };
 
 const struct file_operations ubifs_file_operations = {
--- a/fs
Subject: yaffs: fix compat tags handling

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -17,7 +17,9 @@
 #include "yaffs_getblockinfo.h"
 #include "yaffs_trace.h"
 
+#if 0
 static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+#endif
 
 
 /********** Tags ECC calculations  *********/
@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
 	return 0;
 }
 
+#if 0
 /********** Tags **********/
 
 static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
 	if(!dev->tagger.mark_bad_fn)
 		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
 }
+#else
+
+#include "yaffs_packedtags1.h"
+
+static int yaffs_tags_compat_write(struct yaffs_dev *dev,
+				   int nand_chunk,
+				   const u8 *data,
+				   const struct yaffs_ext_tags *tags)
+{
+	struct yaffs_packed_tags1 pt1;
+	u8 tag_buf[9];
+	int retval;
+
+	/* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
+	compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
+	compile_time_assertion(sizeof(struct yaffs_tags) == 8);
+
+	yaffs_pack_tags1(&pt1, tags);
+	yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
+
+	/* When deleting a chunk, the upper layer provides only skeletal
+	 * tags, one with is_deleted set.  However, we need to update the
+	 * tags, not erase them completely.  So we use the NAND write property
+	 * that only zeroed-bits stick and set tag bytes to all-ones and
+	 * zero just the (not) deleted bit.
+	 */
+	if (!dev->param.tags_9bytes) {
+		if (tags->is_deleted) {
+			memset(&pt1, 0xff, 8);
+			/* clear delete status bit to indicate deleted */
+			pt1.deleted = 0;
+		}
+		memcpy(tag_buf, &pt1, 8);
+	} else {
+		if (tags->is_deleted) {
+			memset(tag_buf, 0xff, 8);
+			tag_buf[8] = 0;
+		} else {
+			memcpy(tag_buf, &pt1, 8);
+			tag_buf[8] = 0xff;
+		}
+	}
+
+	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+			data,
+			(data) ? dev->data_bytes_per_chunk : 0,
+			tag_buf,
+			(dev->param.tags_9bytes) ? 9 : 8);
+
+	return retval;
+}
+
+/* Return with empty extended tags but add ecc_result.
+ */
+static int return_empty_tags(struct yaffs_ext_tags *tags,
+			     enum yaffs_ecc_result ecc_result,
+			     int retval)
+{
+	if (tags) {
+		memset(tags, 0, sizeof(*tags));
+		tags->ecc_result = ecc_result;
+	}
+
+	return retval;
+}
+
+static int yaffs_tags_compat_read(struct yaffs_dev *dev,
+				  int nand_chunk,
+				  u8 *data,
+				  struct yaffs_ext_tags *tags)
+{
+	struct yaffs_packed_tags1 pt1;
+	enum yaffs_ecc_result ecc_result;
+	int retval;
+	int deleted;
+	u8 tag_buf[9];
+
+	retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+			data, dev->param.total_bytes_per_chunk,
+			tag_buf,
+			(dev->param.tags_9bytes) ? 9 : 8,
+			&ecc_result);
+
+	switch (ecc_result) {
+	case YAFFS_ECC_RESULT_NO_ERROR:
+	case YAFFS_ECC_RESULT_FIXED:
+		break;
+
+	case YAFFS_ECC_RESULT_UNFIXED:
+	default:
+		return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
+		tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
+		return YAFFS_FAIL;
+	}
+
+	/* Check for a blank/erased chunk. */
+	if (yaffs_check_ff(tag_buf, 8)) {
+		/* when blank, upper layers want ecc_result to be <= NO_ERROR */
+		return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
+					 YAFFS_OK);
+	}
+
+	memcpy(&pt1, tag_buf, 8);
+
+	if (!dev->param.tags_9bytes) {
+		/* Read deleted status (bit) then return it to it's non-deleted
+		 * state before performing tags mini-ECC check. pt1.deleted is
+		 * inverted.
+		 */
+		deleted = !pt1.deleted;
+		pt1.deleted = 1;
+	} else {
+		deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
+	}
+
+	/* Check the packed tags mini-ECC and correct if necessary/possible. */
+	retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
+	switch (retval) {
+	case 0:
+		/* no tags error, use MTD result */
+		break;
+	case 1:
+		/* recovered tags-ECC error */
+		dev->n_tags_ecc_fixed++;
+		if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
+			ecc_result = YAFFS_ECC_RESULT_FIXED;
+		break;
+	default:
+		/* unrecovered tags-ECC error */
+		dev->n_tags_ecc_unfixed++;
+		return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
+					 YAFFS_FAIL);
+	}
+
+	/* Unpack the tags to extended form and set ECC result.
+	 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
+	 */
+	pt1.should_be_ff = 0xffffffff;
+	yaffs_unpack_tags1(tags, &pt1);
+	tags->ecc_result = ecc_result;
+
+	/* Set deleted state */
+	tags->is_deleted = deleted;
+	return YAFFS_OK;
+}
+
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+	return dev->drv.drv_mark_bad_fn(dev, block_no);
+}
+
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+					 int block_no,
+					 enum yaffs_block_state *state,
+					 u32 *seq_number)
+{
+	struct yaffs_ext_tags tags;
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
+
+	*seq_number = 0;
+
+	retval = dev->drv.drv_check_bad_fn(dev, block_no);
+	if (retval == YAFFS_FAIL) {
+		*state = YAFFS_BLOCK_STATE_DEAD;
+		goto out;
+	}
+
+	yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
+			       NULL, &tags);
+
+	if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
+		yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
+			    block_no);
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+	} else if (tags.chunk_used) {
+		*seq_number = tags.seq_number;
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+	} else {
+		*state = YAFFS_BLOCK_STATE_EMPTY;
+	}
+
+	retval = YAFFS_OK;
+
+out:
+	yaffs_trace(YAFFS_TRACE_MTD,
+		    "block query returns seq %u state %d",
+		    *seq_number, *state);
+
+	return retval;
+}
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev)
+{
+	if (dev->param.is_yaffs2)
+		return;
+
+	if (!dev->tagger.write_chunk_tags_fn)
+		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
+
+	if (!dev->tagger.read_chunk_tags_fn)
+		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
+
+	if (!dev->tagger.query_block_fn)
+		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
+
+	if (!dev->tagger.mark_bad_fn)
+		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+}
+#endif