aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.12/514-yaffs-3.6-use-delayed-work-instead-of-write_super.patch
blob: c6ecddf0b2d91f3f029d926b50314265b4426f87 (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
--- a/fs/yaffs2/yaffs_vfs_glue.c
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -393,6 +393,84 @@ static void yaffs_touch_super(yaffs_dev_
 static int yaffs_vfs_setattr(struct inode *, struct iattr *);
 
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+
+#define yaffs_super_to_dev(sb)    ((struct yaffs_dev_s *)sb->s_fs_info)
+
+static inline struct yaffs_LinuxContext *
+yaffs_sb_to_ylc(struct super_block *sb)
+{
+	struct yaffs_dev_s *ydev;
+	struct yaffs_LinuxContext *ylc;
+
+	ydev = yaffs_super_to_dev(sb);
+	ylc = yaffs_dev_to_lc(ydev);
+	return ylc;
+}
+
+static inline struct super_block *yaffs_work_to_sb(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct yaffs_LinuxContext *ylc;
+
+	dwork = container_of(work, struct delayed_work, work);
+	ylc = container_of(dwork, struct yaffs_LinuxContext, sb_sync_dwork);
+	return ylc->superBlock;
+}
+
+static void yaffs_sb_sync_dwork_func(struct work_struct *work)
+{
+	struct super_block *sb = yaffs_work_to_sb(work);
+
+	yaffs_write_super(sb);
+}
+
+static void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc)
+{
+	INIT_DELAYED_WORK(&ylc->sb_sync_dwork, yaffs_sb_sync_dwork_func);
+}
+
+static void yaffs_cancel_sb_sync_dwork(struct super_block *sb)
+{
+	struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+	cancel_delayed_work_sync(&ylc->sb_sync_dwork);
+}
+
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+	struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+	return !!ylc->sb_dirty;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+	struct yaffs_LinuxContext *ylc = yaffs_sb_to_ylc(sb);
+
+	if (ylc->sb_dirty == dirty)
+		return;
+
+	ylc->sb_dirty = dirty;
+	if (dirty)
+		queue_delayed_work(system_long_wq, &ylc->sb_sync_dwork,
+				   msecs_to_jiffies(5000));
+}
+#else
+static inline bool yaffs_sb_is_dirty(struct super_block *sb)
+{
+	return !!sb->s_dirt;
+}
+
+static inline void yaffs_sb_set_dirty(struct super_block *sb, int dirty)
+{
+	sb->s_dirt = dirty;
+}
+
+static inline void yaffs_init_sb_sync_dwork(struct yaffs_LinuxContext *ylc) {}
+static inline void yaffs_cancel_sb_sync_dwork(struct super_block *sb) {}
+#endif /* >= 3.6.0 */
+
 static struct address_space_operations yaffs_file_address_operations = {
 	.readpage = yaffs_readpage,
 	.writepage = yaffs_writepage,
@@ -553,7 +631,9 @@ static const struct super_operations yaf
 	.clear_inode = yaffs_clear_inode,
 #endif
 	.sync_fs = yaffs_sync_fs,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
 	.write_super = yaffs_write_super,
+#endif
 };
 
 
@@ -2340,7 +2420,7 @@ static int yaffs_do_sync_fs(struct super
 	T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
 		(TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
 		gc_urgent,
-		sb->s_dirt ? "dirty" : "clean",
+		yaffs_sb_is_dirty(sb) ? "dirty" : "clean",
 		request_checkpoint ? "checkpoint requested" : "no checkpoint",
 		oneshot_checkpoint ? " one-shot" : "" ));
 
@@ -2349,9 +2429,9 @@ static int yaffs_do_sync_fs(struct super
 			oneshot_checkpoint) &&
 			!dev->is_checkpointed;
 
-	if (sb->s_dirt || do_checkpoint) {
+	if (yaffs_sb_is_dirty(sb) || do_checkpoint) {
 		yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
-		sb->s_dirt = 0;
+		yaffs_sb_set_dirty(sb, 0);
 		if(oneshot_checkpoint)
 			yaffs_auto_checkpoint &= ~4;
 	}
@@ -2627,6 +2707,8 @@ static void yaffs_put_super(struct super
 
 	yaffs_flush_super(sb,1);
 
+	yaffs_cancel_sb_sync_dwork(sb);
+
 	if (yaffs_dev_to_lc(dev)->putSuperFunc)
 		yaffs_dev_to_lc(dev)->putSuperFunc(sb);
 
@@ -2665,7 +2747,7 @@ static void yaffs_touch_super(yaffs_dev_
 
 	T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb));
 	if (sb)
-		sb->s_dirt = 1;
+		yaffs_sb_set_dirty(sb, 1);
 }
 
 typedef struct {
@@ -2991,6 +3073,8 @@ static struct super_block *yaffs_interna
 	context->dev = dev;
 	context->superBlock = sb;
 
+	yaffs_init_sb_sync_dwork(context);
+
 	dev->read_only = read_only;
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
@@ -3177,7 +3261,7 @@ static struct super_block *yaffs_interna
 		return NULL;
 	}
 	sb->s_root = root;
-	sb->s_dirt = !dev->is_checkpointed;
+	yaffs_sb_set_dirty(sb, !dev->is_checkpointed);
 	T(YAFFS_TRACE_ALWAYS,
 		(TSTR("yaffs_read_super: is_checkpointed %d\n"),
 		dev->is_checkpointed));
--- a/fs/yaffs2/yaffs_linux.h
+++ b/fs/yaffs2/yaffs_linux.h
@@ -34,6 +34,11 @@ struct yaffs_LinuxContext {
 
 	struct task_struct *readdirProcess;
 	unsigned mount_id;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+	struct delayed_work sb_sync_dwork;	/* superblock write-out work */
+	int sb_dirty;				/* superblock is dirty */
+#endif
 };
 
 #define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context))
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -49,6 +49,9 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/xattr.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+#include <linux/workqueue.h>
+#endif
 
 #define YCHAR char
 #define YUCHAR unsigned char