blob: d626eb2113e1cf2647c5041b2c065e77024d730d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
David Woodhousec00c3102007-04-25 14:16:47 +01004 * Copyright © 2001-2007 Red Hat, Inc.
5 * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
7 * Created by David Woodhouse <dwmw2@infradead.org>
8 * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
9 *
10 * For licensing information, see the file 'LICENCE' in this directory.
11 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/mtd/mtd.h>
17#include <linux/crc32.h>
18#include <linux/mtd/nand.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080019#include <linux/jiffies.h>
Al Viro914e2632006-10-18 13:55:46 -040020#include <linux/sched.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080021
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "nodelist.h"
23
24/* For testing write failures */
25#undef BREAKME
26#undef BREAKMEHEADER
27
28#ifdef BREAKME
29static unsigned char *brokenbuf;
30#endif
31
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +010032#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
33#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* max. erase failures before we mark a block bad */
36#define MAX_ERASE_FAILURES 2
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038struct jffs2_inodirty {
39 uint32_t ino;
40 struct jffs2_inodirty *next;
41};
42
43static struct jffs2_inodirty inodirty_nomem;
44
45static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
46{
47 struct jffs2_inodirty *this = c->wbuf_inodes;
48
49 /* If a malloc failed, consider _everything_ dirty */
50 if (this == &inodirty_nomem)
51 return 1;
52
53 /* If ino == 0, _any_ non-GC writes mean 'yes' */
54 if (this && !ino)
55 return 1;
56
57 /* Look to see if the inode in question is pending in the wbuf */
58 while (this) {
59 if (this->ino == ino)
60 return 1;
61 this = this->next;
62 }
63 return 0;
64}
65
66static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
67{
68 struct jffs2_inodirty *this;
69
70 this = c->wbuf_inodes;
71
72 if (this != &inodirty_nomem) {
73 while (this) {
74 struct jffs2_inodirty *next = this->next;
75 kfree(this);
76 this = next;
77 }
78 }
79 c->wbuf_inodes = NULL;
80}
81
82static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
83{
84 struct jffs2_inodirty *new;
85
86 /* Mark the superblock dirty so that kupdated will flush... */
Joakim Tjernlund64a5c2e2010-05-19 17:13:19 +010087 jffs2_dirty_trigger(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89 if (jffs2_wbuf_pending_for_ino(c, ino))
90 return;
91
92 new = kmalloc(sizeof(*new), GFP_KERNEL);
93 if (!new) {
Joe Perches9c261b32012-02-15 15:56:43 -080094 jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 jffs2_clear_wbuf_ino_list(c);
96 c->wbuf_inodes = &inodirty_nomem;
97 return;
98 }
99 new->ino = ino;
100 new->next = c->wbuf_inodes;
101 c->wbuf_inodes = new;
102 return;
103}
104
105static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
106{
107 struct list_head *this, *next;
108 static int n;
109
110 if (list_empty(&c->erasable_pending_wbuf_list))
111 return;
112
113 list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
114 struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
115
Joe Perches9c261b32012-02-15 15:56:43 -0800116 jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n",
117 jeb->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 list_del(this);
119 if ((jiffies + (n++)) & 127) {
120 /* Most of the time, we just erase it immediately. Otherwise we
121 spend ages scanning it on mount, etc. */
Joe Perches9c261b32012-02-15 15:56:43 -0800122 jffs2_dbg(1, "...and adding to erase_pending_list\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 list_add_tail(&jeb->list, &c->erase_pending_list);
124 c->nr_erasing_blocks++;
David Woodhouseae3b6ba2010-05-19 17:05:14 +0100125 jffs2_garbage_collect_trigger(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 } else {
127 /* Sometimes, however, we leave it elsewhere so it doesn't get
128 immediately reused, and we spread the load a bit. */
Joe Perches9c261b32012-02-15 15:56:43 -0800129 jffs2_dbg(1, "...and adding to erasable_list\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 list_add_tail(&jeb->list, &c->erasable_list);
131 }
132 }
133}
134
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000135#define REFILE_NOTEMPTY 0
136#define REFILE_ANYWAY 1
137
138static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
Joe Perches9c261b32012-02-15 15:56:43 -0800140 jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 /* File the existing block on the bad_used_list.... */
143 if (c->nextblock == jeb)
144 c->nextblock = NULL;
145 else /* Not sure this should ever happen... need more coffee */
146 list_del(&jeb->list);
147 if (jeb->first_node) {
Joe Perches9c261b32012-02-15 15:56:43 -0800148 jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n",
149 jeb->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 list_add(&jeb->list, &c->bad_used_list);
151 } else {
Estelle Hammache9b88f472005-01-28 18:53:05 +0000152 BUG_ON(allow_empty == REFILE_NOTEMPTY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 /* It has to have had some nodes or we couldn't be here */
Joe Perches9c261b32012-02-15 15:56:43 -0800154 jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n",
155 jeb->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 list_add(&jeb->list, &c->erase_pending_list);
157 c->nr_erasing_blocks++;
David Woodhouseae3b6ba2010-05-19 17:05:14 +0100158 jffs2_garbage_collect_trigger(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
David Woodhouse9bfeb692006-05-26 21:19:05 +0100161 if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) {
162 uint32_t oldfree = jeb->free_size;
163
164 jffs2_link_node_ref(c, jeb,
165 (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE,
166 oldfree, NULL);
167 /* convert to wasted */
168 c->wasted_size += oldfree;
169 jeb->wasted_size += oldfree;
170 c->dirty_size -= oldfree;
171 jeb->dirty_size -= oldfree;
172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100174 jffs2_dbg_dump_block_lists_nolock(c);
175 jffs2_dbg_acct_sanity_check_nolock(c,jeb);
176 jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
178
David Woodhouse9bfeb692006-05-26 21:19:05 +0100179static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c,
180 struct jffs2_inode_info *f,
181 struct jffs2_raw_node_ref *raw,
182 union jffs2_node_union *node)
183{
184 struct jffs2_node_frag *frag;
185 struct jffs2_full_dirent *fd;
186
187 dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n",
188 node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype));
189
190 BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 &&
191 je16_to_cpu(node->u.magic) != 0);
192
193 switch (je16_to_cpu(node->u.nodetype)) {
194 case JFFS2_NODETYPE_INODE:
David Woodhouseddc58bd2006-05-27 13:15:16 +0100195 if (f->metadata && f->metadata->raw == raw) {
196 dbg_noderef("Will replace ->raw in f->metadata at %p\n", f->metadata);
197 return &f->metadata->raw;
198 }
David Woodhouse9bfeb692006-05-26 21:19:05 +0100199 frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset));
200 BUG_ON(!frag);
201 /* Find a frag which refers to the full_dnode we want to modify */
202 while (!frag->node || frag->node->raw != raw) {
203 frag = frag_next(frag);
204 BUG_ON(!frag);
205 }
206 dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node);
207 return &frag->node->raw;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100208
209 case JFFS2_NODETYPE_DIRENT:
210 for (fd = f->dents; fd; fd = fd->next) {
211 if (fd->raw == raw) {
212 dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd);
213 return &fd->raw;
214 }
215 }
216 BUG();
David Woodhouseddc58bd2006-05-27 13:15:16 +0100217
David Woodhouse9bfeb692006-05-26 21:19:05 +0100218 default:
219 dbg_noderef("Don't care about replacing raw for nodetype %x\n",
220 je16_to_cpu(node->u.nodetype));
221 break;
222 }
223 return NULL;
224}
225
David Woodhousea6bc4322007-07-11 14:23:54 +0100226#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
227static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
228 uint32_t ofs)
229{
230 int ret;
231 size_t retlen;
232 char *eccstr;
233
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200234 ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
David Woodhousea6bc4322007-07-11 14:23:54 +0100235 if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
236 printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
237 return ret;
238 } else if (retlen != c->wbuf_pagesize) {
239 printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
240 return -EIO;
241 }
242 if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
243 return 0;
244
245 if (ret == -EUCLEAN)
246 eccstr = "corrected";
247 else if (ret == -EBADMSG)
248 eccstr = "correction failed";
249 else
250 eccstr = "OK or unused";
251
252 printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
253 eccstr, c->wbuf_ofs);
254 print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
255 c->wbuf, c->wbuf_pagesize, 0);
256
257 printk(KERN_WARNING "Read back:\n");
258 print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
259 c->wbuf_verify, c->wbuf_pagesize, 0);
260
261 return -EIO;
262}
263#else
264#define jffs2_verify_write(c,b,o) (0)
265#endif
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267/* Recover from failure to write wbuf. Recover the nodes up to the
268 * wbuf, not the one which we were starting to try to write. */
269
270static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
271{
272 struct jffs2_eraseblock *jeb, *new_jeb;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100273 struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 size_t retlen;
275 int ret;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100276 int nr_refile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 unsigned char *buf;
278 uint32_t start, end, ofs, len;
279
David Woodhouse046b8b92006-05-25 01:50:35 +0100280 jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 spin_lock(&c->erase_completion_lock);
Vitaly Wool180bfb32007-03-06 17:01:04 +0300283 if (c->wbuf_ofs % c->mtd->erasesize)
284 jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
285 else
286 jffs2_block_refile(c, jeb, REFILE_ANYWAY);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100287 spin_unlock(&c->erase_completion_lock);
288
289 BUG_ON(!ref_obsolete(jeb->last_node));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 /* Find the first node to be recovered, by skipping over every
292 node which ends before the wbuf starts, or which is obsolete. */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100293 for (next = raw = jeb->first_node; next; raw = next) {
294 next = ref_next(raw);
295
296 if (ref_obsolete(raw) ||
297 (next && ref_offset(next) <= c->wbuf_ofs)) {
298 dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
299 ref_offset(raw), ref_flags(raw),
300 (ref_offset(raw) + ref_totlen(c, jeb, raw)),
301 c->wbuf_ofs);
302 continue;
303 }
304 dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n",
305 ref_offset(raw), ref_flags(raw),
306 (ref_offset(raw) + ref_totlen(c, jeb, raw)));
307
308 first_raw = raw;
309 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311
David Woodhouse9bfeb692006-05-26 21:19:05 +0100312 if (!first_raw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 /* All nodes were obsolete. Nothing to recover. */
Joe Perches9c261b32012-02-15 15:56:43 -0800314 jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n");
David Woodhouse9bfeb692006-05-26 21:19:05 +0100315 c->wbuf_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return;
317 }
318
David Woodhouse9bfeb692006-05-26 21:19:05 +0100319 start = ref_offset(first_raw);
320 end = ref_offset(jeb->last_node);
321 nr_refile = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
David Woodhouse9bfeb692006-05-26 21:19:05 +0100323 /* Count the number of refs which need to be copied */
324 while ((raw = ref_next(raw)) != jeb->last_node)
325 nr_refile++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
David Woodhouse9bfeb692006-05-26 21:19:05 +0100327 dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n",
328 start, end, end - start, nr_refile);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 buf = NULL;
331 if (start < c->wbuf_ofs) {
332 /* First affected node was already partially written.
333 * Attempt to reread the old data into our buffer. */
334
335 buf = kmalloc(end - start, GFP_KERNEL);
336 if (!buf) {
337 printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
338
339 goto read_failed;
340 }
341
342 /* Do the read... */
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200343 ret = mtd_read(c->mtd, start, c->wbuf_ofs - start, &retlen,
344 buf);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000345
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +0200346 /* ECC recovered ? */
347 if ((ret == -EUCLEAN || ret == -EBADMSG) &&
348 (retlen == c->wbuf_ofs - start))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 ret = 0;
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +0200350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (ret || retlen != c->wbuf_ofs - start) {
352 printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
353
354 kfree(buf);
355 buf = NULL;
356 read_failed:
David Woodhouse9bfeb692006-05-26 21:19:05 +0100357 first_raw = ref_next(first_raw);
358 nr_refile--;
359 while (first_raw && ref_obsolete(first_raw)) {
360 first_raw = ref_next(first_raw);
361 nr_refile--;
362 }
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 /* If this was the only node to be recovered, give up */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100365 if (!first_raw) {
366 c->wbuf_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 /* It wasn't. Go on and try to recover nodes complete in the wbuf */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100371 start = ref_offset(first_raw);
372 dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n",
373 start, end, end - start, nr_refile);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 } else {
376 /* Read succeeded. Copy the remaining data from the wbuf */
377 memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
378 }
379 }
380 /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
381 Either 'buf' contains the data, or we find it in the wbuf */
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* ... and get an allocation of space from a shiny new block instead */
David Woodhouse9fe48542006-05-23 00:38:06 +0100384 ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 if (ret) {
386 printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
Estelle Hammache9b88f472005-01-28 18:53:05 +0000387 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return;
389 }
David Woodhouse9bfeb692006-05-26 21:19:05 +0100390
Adrian Hunter7f762ab2007-04-04 13:47:53 +0300391 /* The summary is not recovered, so it must be disabled for this erase block */
392 jffs2_sum_disable_collecting(c->summary);
393
David Woodhouse9bfeb692006-05-26 21:19:05 +0100394 ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
395 if (ret) {
396 printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
397 kfree(buf);
398 return;
399 }
400
David Woodhouse9fe48542006-05-23 00:38:06 +0100401 ofs = write_ofs(c);
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (end-start >= c->wbuf_pagesize) {
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000404 /* Need to do another write immediately, but it's possible
Estelle Hammache9b88f472005-01-28 18:53:05 +0000405 that this is just because the wbuf itself is completely
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000406 full, and there's nothing earlier read back from the
407 flash. Hence 'buf' isn't necessarily what we're writing
Estelle Hammache9b88f472005-01-28 18:53:05 +0000408 from. */
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000409 unsigned char *rewrite_buf = buf?:c->wbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
411
Joe Perches9c261b32012-02-15 15:56:43 -0800412 jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n",
413 towrite, ofs);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415#ifdef BREAKMEHEADER
416 static int breakme;
417 if (breakme++ == 20) {
418 printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
419 breakme = 0;
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200420 mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ret = -EIO;
422 } else
423#endif
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200424 ret = mtd_write(c->mtd, ofs, towrite, &retlen,
425 rewrite_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
David Woodhousea6bc4322007-07-11 14:23:54 +0100427 if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 /* Argh. We tried. Really we did. */
429 printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
Estelle Hammache9b88f472005-01-28 18:53:05 +0000430 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
David Woodhouse2f785402006-05-24 02:04:45 +0100432 if (retlen)
David Woodhouse9bfeb692006-05-26 21:19:05 +0100433 jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return;
436 }
437 printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
438
439 c->wbuf_len = (end - start) - towrite;
440 c->wbuf_ofs = ofs + towrite;
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000441 memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 } else {
444 /* OK, now we're left with the dregs in whichever buffer we're using */
445 if (buf) {
446 memcpy(c->wbuf, buf, end-start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 } else {
448 memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
449 }
450 c->wbuf_ofs = ofs;
451 c->wbuf_len = end - start;
452 }
453
454 /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
455 new_jeb = &c->blocks[ofs / c->sector_size];
456
457 spin_lock(&c->erase_completion_lock);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100458 for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) {
459 uint32_t rawlen = ref_totlen(c, jeb, raw);
460 struct jffs2_inode_cache *ic;
461 struct jffs2_raw_node_ref *new_ref;
462 struct jffs2_raw_node_ref **adjust_ref = NULL;
463 struct jffs2_inode_info *f = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Joe Perches9c261b32012-02-15 15:56:43 -0800465 jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n",
466 rawlen, ref_offset(raw), ref_flags(raw), ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
David Woodhouse9bfeb692006-05-26 21:19:05 +0100468 ic = jffs2_raw_ref_to_ic(raw);
469
470 /* Ick. This XATTR mess should be fixed shortly... */
471 if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) {
472 struct jffs2_xattr_datum *xd = (void *)ic;
473 BUG_ON(xd->node != raw);
474 adjust_ref = &xd->node;
475 raw->next_in_ino = NULL;
476 ic = NULL;
477 } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) {
478 struct jffs2_xattr_datum *xr = (void *)ic;
479 BUG_ON(xr->node != raw);
480 adjust_ref = &xr->node;
481 raw->next_in_ino = NULL;
482 ic = NULL;
483 } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) {
484 struct jffs2_raw_node_ref **p = &ic->nodes;
485
486 /* Remove the old node from the per-inode list */
487 while (*p && *p != (void *)ic) {
488 if (*p == raw) {
489 (*p) = (raw->next_in_ino);
490 raw->next_in_ino = NULL;
491 break;
492 }
493 p = &((*p)->next_in_ino);
494 }
495
496 if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) {
497 /* If it's an in-core inode, then we have to adjust any
498 full_dirent or full_dnode structure to point to the
499 new version instead of the old */
David Woodhouse27c72b02008-05-01 18:47:17 +0100500 f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100501 if (IS_ERR(f)) {
502 /* Should never happen; it _must_ be present */
503 JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
504 ic->ino, PTR_ERR(f));
505 BUG();
506 }
507 /* We don't lock f->sem. There's a number of ways we could
508 end up in here with it already being locked, and nobody's
509 going to modify it on us anyway because we hold the
510 alloc_sem. We're only changing one ->raw pointer too,
511 which we can get away with without upsetting readers. */
512 adjust_ref = jffs2_incore_replace_raw(c, f, raw,
513 (void *)(buf?:c->wbuf) + (ref_offset(raw) - start));
514 } else if (unlikely(ic->state != INO_STATE_PRESENT &&
515 ic->state != INO_STATE_CHECKEDABSENT &&
516 ic->state != INO_STATE_GC)) {
517 JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state);
518 BUG();
519 }
520 }
521
522 new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic);
523
524 if (adjust_ref) {
525 BUG_ON(*adjust_ref != raw);
526 *adjust_ref = new_ref;
527 }
528 if (f)
529 jffs2_gc_release_inode(c, f);
530
531 if (!ref_obsolete(raw)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 jeb->dirty_size += rawlen;
533 jeb->used_size -= rawlen;
534 c->dirty_size += rawlen;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100535 c->used_size -= rawlen;
536 raw->flash_offset = ref_offset(raw) | REF_OBSOLETE;
537 BUG_ON(raw->next_in_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 ofs += rawlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
541
David Woodhouse9bfeb692006-05-26 21:19:05 +0100542 kfree(buf);
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 /* Fix up the original jeb now it's on the bad_list */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100545 if (first_raw == jeb->first_node) {
Joe Perches9c261b32012-02-15 15:56:43 -0800546 jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n",
547 jeb->offset);
Akinobu Mitaf1166292006-06-26 00:24:46 -0700548 list_move(&jeb->list, &c->erase_pending_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 c->nr_erasing_blocks++;
David Woodhouseae3b6ba2010-05-19 17:05:14 +0100550 jffs2_garbage_collect_trigger(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100553 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100554 jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100556 jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100557 jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 spin_unlock(&c->erase_completion_lock);
560
Joe Perches9c261b32012-02-15 15:56:43 -0800561 jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n",
562 c->wbuf_ofs, c->wbuf_len);
David Woodhouse9bfeb692006-05-26 21:19:05 +0100563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
566/* Meaning of pad argument:
567 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
568 1: Pad, do not adjust nextblock free_size
569 2: Pad, adjust nextblock free_size
570*/
571#define NOPAD 0
572#define PAD_NOACCOUNT 1
573#define PAD_ACCOUNTING 2
574
575static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
576{
David Woodhouse9bfeb692006-05-26 21:19:05 +0100577 struct jffs2_eraseblock *wbuf_jeb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 int ret;
579 size_t retlen;
580
Andrew Victor3be36672005-02-09 09:09:05 +0000581 /* Nothing to do if not write-buffering the flash. In particular, we shouldn't
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 del_timer() the timer we never initialised. */
Andrew Victor3be36672005-02-09 09:09:05 +0000583 if (!jffs2_is_writebuffered(c))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return 0;
585
Alexey Khoroshilov51b11e32011-06-28 00:21:30 +0400586 if (!mutex_is_locked(&c->alloc_sem)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
588 BUG();
589 }
590
Andrew Victor3be36672005-02-09 09:09:05 +0000591 if (!c->wbuf_len) /* already checked c->wbuf above */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return 0;
593
David Woodhouse9bfeb692006-05-26 21:19:05 +0100594 wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
595 if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1))
David Woodhouse2f785402006-05-24 02:04:45 +0100596 return -ENOMEM;
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 /* claim remaining space on the page
599 this happens, if we have a change to a new block,
600 or if fsync forces us to flush the writebuffer.
601 if we have a switch to next page, we will not have
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000602 enough remaining space for this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 */
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +0100604 if (pad ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 c->wbuf_len = PAD(c->wbuf_len);
606
607 /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
608 with 8 byte page size */
609 memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
612 struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
613 padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
614 padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
615 padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
616 padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
617 }
618 }
619 /* else jffs2_flash_writev has actually filled in the rest of the
620 buffer for us, and will deal with the node refs etc. later. */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622#ifdef BREAKME
623 static int breakme;
624 if (breakme++ == 20) {
625 printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
626 breakme = 0;
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200627 mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
628 brokenbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 ret = -EIO;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000630 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631#endif
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000632
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200633 ret = mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
634 &retlen, c->wbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
David Woodhousea6bc4322007-07-11 14:23:54 +0100636 if (ret) {
637 printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
638 goto wfail;
639 } else if (retlen != c->wbuf_pagesize) {
640 printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
641 retlen, c->wbuf_pagesize);
642 ret = -EIO;
643 goto wfail;
644 } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
645 wfail:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 jffs2_wbuf_recover(c);
647
648 return ret;
649 }
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 /* Adjust free size of the block if we padded. */
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +0100652 if (pad) {
David Woodhouse0bcc0992006-05-21 13:00:54 +0100653 uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Joe Perches9c261b32012-02-15 15:56:43 -0800655 jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
656 (wbuf_jeb == c->nextblock) ? "next" : "",
657 wbuf_jeb->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000659 /* wbuf_pagesize - wbuf_len is the amount of space that's to be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 padded. If there is less free space in the block than that,
661 something screwed up */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100662 if (wbuf_jeb->free_size < waste) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
David Woodhouse0bcc0992006-05-21 13:00:54 +0100664 c->wbuf_ofs, c->wbuf_len, waste);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
David Woodhouse9bfeb692006-05-26 21:19:05 +0100666 wbuf_jeb->offset, wbuf_jeb->free_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 BUG();
668 }
David Woodhouse0bcc0992006-05-21 13:00:54 +0100669
670 spin_lock(&c->erase_completion_lock);
671
David Woodhouse9bfeb692006-05-26 21:19:05 +0100672 jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL);
David Woodhouse0bcc0992006-05-21 13:00:54 +0100673 /* FIXME: that made it count as dirty. Convert to wasted */
David Woodhouse9bfeb692006-05-26 21:19:05 +0100674 wbuf_jeb->dirty_size -= waste;
David Woodhouse0bcc0992006-05-21 13:00:54 +0100675 c->dirty_size -= waste;
David Woodhouse9bfeb692006-05-26 21:19:05 +0100676 wbuf_jeb->wasted_size += waste;
David Woodhouse0bcc0992006-05-21 13:00:54 +0100677 c->wasted_size += waste;
678 } else
679 spin_lock(&c->erase_completion_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 /* Stick any now-obsoleted blocks on the erase_pending_list */
682 jffs2_refile_wbuf_blocks(c);
683 jffs2_clear_wbuf_ino_list(c);
684 spin_unlock(&c->erase_completion_lock);
685
686 memset(c->wbuf,0xff,c->wbuf_pagesize);
687 /* adjust write buffer offset, else we get a non contiguous write bug */
Alexander Belyakov5bf17232008-10-17 19:19:13 +0400688 c->wbuf_ofs += c->wbuf_pagesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 c->wbuf_len = 0;
690 return 0;
691}
692
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000693/* Trigger garbage collection to flush the write-buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000695 outstanding. If ino arg non-zero, do it only if a write for the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 given inode is outstanding. */
697int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
698{
699 uint32_t old_wbuf_ofs;
700 uint32_t old_wbuf_len;
701 int ret = 0;
702
Joe Perches9c261b32012-02-15 15:56:43 -0800703 jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
David Woodhouse8aee6ac2005-02-02 22:12:08 +0000705 if (!c->wbuf)
706 return 0;
707
David Woodhouseced22072008-04-22 15:13:40 +0100708 mutex_lock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (!jffs2_wbuf_pending_for_ino(c, ino)) {
Joe Perches9c261b32012-02-15 15:56:43 -0800710 jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino);
David Woodhouseced22072008-04-22 15:13:40 +0100711 mutex_unlock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return 0;
713 }
714
715 old_wbuf_ofs = c->wbuf_ofs;
716 old_wbuf_len = c->wbuf_len;
717
718 if (c->unchecked_size) {
719 /* GC won't make any progress for a while */
Joe Perches9c261b32012-02-15 15:56:43 -0800720 jffs2_dbg(1, "%s(): padding. Not finished checking\n",
721 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 down_write(&c->wbuf_sem);
723 ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000724 /* retry flushing wbuf in case jffs2_wbuf_recover
725 left some data in the wbuf */
726 if (ret)
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000727 ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 up_write(&c->wbuf_sem);
729 } else while (old_wbuf_len &&
730 old_wbuf_ofs == c->wbuf_ofs) {
731
David Woodhouseced22072008-04-22 15:13:40 +0100732 mutex_unlock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Joe Perches9c261b32012-02-15 15:56:43 -0800734 jffs2_dbg(1, "%s(): calls gc pass\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 ret = jffs2_garbage_collect_pass(c);
737 if (ret) {
738 /* GC failed. Flush it with padding instead */
David Woodhouseced22072008-04-22 15:13:40 +0100739 mutex_lock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 down_write(&c->wbuf_sem);
741 ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000742 /* retry flushing wbuf in case jffs2_wbuf_recover
743 left some data in the wbuf */
744 if (ret)
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000745 ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 up_write(&c->wbuf_sem);
747 break;
748 }
David Woodhouseced22072008-04-22 15:13:40 +0100749 mutex_lock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
751
Joe Perches9c261b32012-02-15 15:56:43 -0800752 jffs2_dbg(1, "%s(): ends...\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
David Woodhouseced22072008-04-22 15:13:40 +0100754 mutex_unlock(&c->alloc_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return ret;
756}
757
758/* Pad write-buffer to end and write it, wasting space. */
759int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
760{
761 int ret;
762
David Woodhouse8aee6ac2005-02-02 22:12:08 +0000763 if (!c->wbuf)
764 return 0;
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 down_write(&c->wbuf_sem);
767 ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
Estelle Hammache7f716cf2005-01-24 21:24:18 +0000768 /* retry - maybe wbuf recover left some data in wbuf. */
769 if (ret)
770 ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 up_write(&c->wbuf_sem);
772
773 return ret;
774}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200776static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf,
777 size_t len)
778{
779 if (len && !c->wbuf_len && (len >= c->wbuf_pagesize))
780 return 0;
781
782 if (len > (c->wbuf_pagesize - c->wbuf_len))
783 len = c->wbuf_pagesize - c->wbuf_len;
784 memcpy(c->wbuf + c->wbuf_len, buf, len);
785 c->wbuf_len += (uint32_t) len;
786 return len;
787}
788
789int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
790 unsigned long count, loff_t to, size_t *retlen,
791 uint32_t ino)
792{
793 struct jffs2_eraseblock *jeb;
794 size_t wbuf_retlen, donelen = 0;
795 uint32_t outvec_to = to;
796 int ret, invec;
797
798 /* If not writebuffered flash, don't bother */
Andrew Victor3be36672005-02-09 09:09:05 +0000799 if (!jffs2_is_writebuffered(c))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000801
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 down_write(&c->wbuf_sem);
803
804 /* If wbuf_ofs is not initialized, set it to target address */
805 if (c->wbuf_ofs == 0xFFFFFFFF) {
806 c->wbuf_ofs = PAGE_DIV(to);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000807 c->wbuf_len = PAGE_MOD(to);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 memset(c->wbuf,0xff,c->wbuf_pagesize);
809 }
810
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200811 /*
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200812 * Sanity checks on target address. It's permitted to write
813 * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to
814 * write at the beginning of a new erase block. Anything else,
815 * and you die. New block starts at xxx000c (0-b = block
816 * header)
817 */
Andrew Victor3be36672005-02-09 09:09:05 +0000818 if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 /* It's a write to a new block */
820 if (c->wbuf_len) {
Joe Perches9c261b32012-02-15 15:56:43 -0800821 jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n",
822 __func__, (unsigned long)to, c->wbuf_ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200824 if (ret)
825 goto outerr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 }
827 /* set pointer to new block */
828 c->wbuf_ofs = PAGE_DIV(to);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000829 c->wbuf_len = PAGE_MOD(to);
830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
833 /* We're not writing immediately after the writebuffer. Bad. */
Joe Perches9c261b32012-02-15 15:56:43 -0800834 printk(KERN_CRIT "%s(): Non-contiguous write to %08lx\n",
835 __func__, (unsigned long)to);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (c->wbuf_len)
837 printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200838 c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 BUG();
840 }
841
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200842 /* adjust alignment offset */
843 if (c->wbuf_len != PAGE_MOD(to)) {
844 c->wbuf_len = PAGE_MOD(to);
845 /* take care of alignment to next page */
846 if (!c->wbuf_len) {
847 c->wbuf_len = c->wbuf_pagesize;
848 ret = __jffs2_flush_wbuf(c, NOPAD);
849 if (ret)
850 goto outerr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852 }
853
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200854 for (invec = 0; invec < count; invec++) {
855 int vlen = invecs[invec].iov_len;
856 uint8_t *v = invecs[invec].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200858 wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200860 if (c->wbuf_len == c->wbuf_pagesize) {
861 ret = __jffs2_flush_wbuf(c, NOPAD);
862 if (ret)
863 goto outerr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200865 vlen -= wbuf_retlen;
866 outvec_to += wbuf_retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 donelen += wbuf_retlen;
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200868 v += wbuf_retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200870 if (vlen >= c->wbuf_pagesize) {
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200871 ret = mtd_write(c->mtd, outvec_to, PAGE_DIV(vlen),
872 &wbuf_retlen, v);
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200873 if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
874 goto outfile;
875
876 vlen -= wbuf_retlen;
877 outvec_to += wbuf_retlen;
878 c->wbuf_ofs = outvec_to;
879 donelen += wbuf_retlen;
880 v += wbuf_retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200883 wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
884 if (c->wbuf_len == c->wbuf_pagesize) {
885 ret = __jffs2_flush_wbuf(c, NOPAD);
886 if (ret)
887 goto outerr;
888 }
889
890 outvec_to += wbuf_retlen;
891 donelen += wbuf_retlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
893
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200894 /*
895 * If there's a remainder in the wbuf and it's a non-GC write,
896 * remember that the wbuf affects this ino
897 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 *retlen = donelen;
899
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100900 if (jffs2_sum_active()) {
901 int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
902 if (res)
903 return res;
904 }
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (c->wbuf_len && ino)
907 jffs2_wbuf_dirties_inode(c, ino);
908
909 ret = 0;
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200910 up_write(&c->wbuf_sem);
911 return ret;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000912
Thomas Gleixnerdcb09322006-05-23 11:49:14 +0200913outfile:
914 /*
915 * At this point we have no problem, c->wbuf is empty. However
916 * refile nextblock to avoid writing again to same address.
917 */
918
919 spin_lock(&c->erase_completion_lock);
920
921 jeb = &c->blocks[outvec_to / c->sector_size];
922 jffs2_block_refile(c, jeb, REFILE_ANYWAY);
923
924 spin_unlock(&c->erase_completion_lock);
925
926outerr:
927 *retlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 up_write(&c->wbuf_sem);
929 return ret;
930}
931
932/*
933 * This is the entry for flash write.
934 * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev
935*/
David Woodhouse9bfeb692006-05-26 21:19:05 +0100936int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
937 size_t *retlen, const u_char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938{
939 struct kvec vecs[1];
940
Andrew Victor3be36672005-02-09 09:09:05 +0000941 if (!jffs2_is_writebuffered(c))
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100942 return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 vecs[0].iov_base = (unsigned char *) buf;
945 vecs[0].iov_len = len;
946 return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
947}
948
949/*
950 Handle readback from writebuffer and ECC failure return
951*/
952int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
953{
954 loff_t orbf = 0, owbf = 0, lwbf = 0;
955 int ret;
956
Andrew Victor3be36672005-02-09 09:09:05 +0000957 if (!jffs2_is_writebuffered(c))
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200958 return mtd_read(c->mtd, ofs, len, retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Andrew Victor3be36672005-02-09 09:09:05 +0000960 /* Read flash */
Artem B. Bityuckiy894214d2005-04-05 13:51:58 +0100961 down_read(&c->wbuf_sem);
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200962 ret = mtd_read(c->mtd, ofs, len, retlen, buf);
Andrew Victor3be36672005-02-09 09:09:05 +0000963
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +0200964 if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
965 if (ret == -EBADMSG)
966 printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"
967 " returned ECC error\n", len, ofs);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000968 /*
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +0200969 * We have the raw data without ECC correction in the buffer,
970 * maybe we are lucky and all data or parts are correct. We
971 * check the node. If data are corrupted node check will sort
972 * it out. We keep this block, it will fail on write or erase
973 * and the we mark it bad. Or should we do that now? But we
974 * should give him a chance. Maybe we had a system crash or
975 * power loss before the ecc write or a erase was completed.
Andrew Victor3be36672005-02-09 09:09:05 +0000976 * So we return success. :)
977 */
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +0200978 ret = 0;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000979 }
Andrew Victor3be36672005-02-09 09:09:05 +0000980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 /* if no writebuffer available or write buffer empty, return */
982 if (!c->wbuf_pagesize || !c->wbuf_len)
Artem B. Bityuckiy894214d2005-04-05 13:51:58 +0100983 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /* if we read in a different block, return */
Andrew Victor3be36672005-02-09 09:09:05 +0000986 if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
Artem B. Bityuckiy894214d2005-04-05 13:51:58 +0100987 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (ofs >= c->wbuf_ofs) {
990 owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
991 if (owbf > c->wbuf_len) /* is read beyond write buffer ? */
992 goto exit;
993 lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000994 if (lwbf > len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 lwbf = len;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000996 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
998 if (orbf > len) /* is write beyond write buffer ? */
999 goto exit;
Thomas Gleixner9a1fcdf2006-05-29 14:56:39 +02001000 lwbf = len - orbf; /* number of bytes to copy */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001001 if (lwbf > c->wbuf_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 lwbf = c->wbuf_len;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (lwbf > 0)
1005 memcpy(buf+orbf,c->wbuf+owbf,lwbf);
1006
1007exit:
1008 up_read(&c->wbuf_sem);
1009 return ret;
1010}
1011
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001012#define NR_OOB_SCAN_PAGES 4
1013
David Woodhouse09b3fba2007-08-09 17:28:20 +08001014/* For historical reasons we use only 8 bytes for OOB clean marker */
1015#define OOB_CM_SIZE 8
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001016
1017static const struct jffs2_unknown_node oob_cleanmarker =
1018{
David Woodhouse566865a2007-04-23 12:07:17 +01001019 .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK),
1020 .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
1021 .totlen = constant_cpu_to_je32(8)
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001022};
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024/*
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001025 * Check, if the out of band area is empty. This function knows about the clean
1026 * marker and if it is present in OOB, treats the OOB as empty anyway.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001028int jffs2_check_oob_empty(struct jffs2_sb_info *c,
1029 struct jffs2_eraseblock *jeb, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001031 int i, ret;
1032 int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001033 struct mtd_oob_ops ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Brian Norris0612b9d2011-08-30 18:45:40 -07001035 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001036 ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001037 ops.oobbuf = c->oobbuf;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001038 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001039 ops.datbuf = NULL;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001040
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +02001041 ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001042 if (ret || ops.oobretlen != ops.ooblen) {
Andrew Morton7be26bf2007-02-17 16:02:10 -08001043 printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
1044 " bytes, read %zd bytes, error %d\n",
1045 jeb->offset, ops.ooblen, ops.oobretlen, ret);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001046 if (!ret)
1047 ret = -EIO;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001048 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001050
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001051 for(i = 0; i < ops.ooblen; i++) {
1052 if (mode && i < cmlen)
1053 /* Yeah, we know about the cleanmarker */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 continue;
1055
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001056 if (ops.oobbuf[i] != 0xFF) {
Joe Perches9c261b32012-02-15 15:56:43 -08001057 jffs2_dbg(2, "Found %02x at %x in OOB for "
1058 "%08x\n", ops.oobbuf[i], i, jeb->offset);
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001059 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061 }
1062
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001063 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064}
1065
1066/*
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001067 * Check for a valid cleanmarker.
1068 * Returns: 0 if a valid cleanmarker was found
David Woodhouseef53cb02007-07-10 10:01:22 +01001069 * 1 if no cleanmarker was found
1070 * negative error code if an error occurred
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001071 */
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001072int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
1073 struct jffs2_eraseblock *jeb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001075 struct mtd_oob_ops ops;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001076 int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Brian Norris0612b9d2011-08-30 18:45:40 -07001078 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001079 ops.ooblen = cmlen;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001080 ops.oobbuf = c->oobbuf;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001081 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001082 ops.datbuf = NULL;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001083
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +02001084 ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001085 if (ret || ops.oobretlen != ops.ooblen) {
Andrew Morton7be26bf2007-02-17 16:02:10 -08001086 printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
1087 " bytes, read %zd bytes, error %d\n",
1088 jeb->offset, ops.ooblen, ops.oobretlen, ret);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001089 if (!ret)
1090 ret = -EIO;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001091 return ret;
1092 }
1093
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001094 return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001097int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
1098 struct jffs2_eraseblock *jeb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001100 int ret;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001101 struct mtd_oob_ops ops;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001102 int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Brian Norris0612b9d2011-08-30 18:45:40 -07001104 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001105 ops.ooblen = cmlen;
1106 ops.oobbuf = (uint8_t *)&oob_cleanmarker;
1107 ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001108 ops.datbuf = NULL;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001109
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +02001110 ret = mtd_write_oob(c->mtd, jeb->offset, &ops);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001111 if (ret || ops.oobretlen != ops.ooblen) {
Andrew Morton7be26bf2007-02-17 16:02:10 -08001112 printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"
1113 " bytes, read %zd bytes, error %d\n",
1114 jeb->offset, ops.ooblen, ops.oobretlen, ret);
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001115 if (!ret)
1116 ret = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return ret;
1118 }
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return 0;
1121}
1122
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001123/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 * On NAND we try to mark this block bad. If the block was erased more
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001125 * than MAX_ERASE_FAILURES we mark it finally bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 * Don't care about failures. This block remains on the erase-pending
1127 * or badblock list as long as nobody manipulates the flash with
1128 * a bootloader or something like that.
1129 */
1130
1131int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
1132{
1133 int ret;
1134
1135 /* if the count is < max, we try to write the counter to the 2nd page oob area */
1136 if( ++jeb->bad_count < MAX_ERASE_FAILURES)
1137 return 0;
1138
Artem Bityutskiy0feba822007-03-08 10:35:10 +02001139 printk(KERN_WARNING "JFFS2: marking eraseblock at %08x\n as bad", bad_offset);
Artem Bityutskiy5942ddb2011-12-23 19:37:38 +02001140 ret = mtd_block_markbad(c->mtd, bad_offset);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 if (ret) {
Joe Perches9c261b32012-02-15 15:56:43 -08001143 jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n",
1144 __func__, jeb->offset, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return ret;
1146 }
1147 return 1;
1148}
1149
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001150int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02001152 struct nand_ecclayout *oinfo = c->mtd->ecclayout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (!c->mtd->oobsize)
1155 return 0;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 /* Cleanmarker is out-of-band, so inline size zero */
1158 c->cleanmarker_size = 0;
1159
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001160 if (!oinfo || oinfo->oobavail == 0) {
1161 printk(KERN_ERR "inconsistent device description\n");
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02001162 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02001164
Joe Perches9c261b32012-02-15 15:56:43 -08001165 jffs2_dbg(1, "JFFS2 using OOB on NAND\n");
Thomas Gleixner5bd34c02006-05-27 22:16:10 +02001166
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001167 c->oobavail = oinfo->oobavail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 /* Initialise write buffer */
1170 init_rwsem(&c->wbuf_sem);
Joern Engel28318772006-05-22 23:18:05 +02001171 c->wbuf_pagesize = c->mtd->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 c->wbuf_ofs = 0xFFFFFFFF;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001173
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1175 if (!c->wbuf)
1176 return -ENOMEM;
1177
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001178 c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->oobavail, GFP_KERNEL);
1179 if (!c->oobbuf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 kfree(c->wbuf);
1181 return -ENOMEM;
1182 }
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001183
David Woodhousea6bc4322007-07-11 14:23:54 +01001184#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1185 c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1186 if (!c->wbuf_verify) {
1187 kfree(c->oobbuf);
1188 kfree(c->wbuf);
1189 return -ENOMEM;
1190 }
1191#endif
Artem Bityutskiya7a6ace12007-01-31 11:38:53 +02001192 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193}
1194
1195void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
1196{
David Woodhousea6bc4322007-07-11 14:23:54 +01001197#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1198 kfree(c->wbuf_verify);
1199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 kfree(c->wbuf);
Thomas Gleixner8593fbc2006-05-29 03:26:58 +02001201 kfree(c->oobbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
Andrew Victor8f15fd52005-02-09 09:17:45 +00001204int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
1205 c->cleanmarker_size = 0; /* No cleanmarkers needed */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001206
Andrew Victor8f15fd52005-02-09 09:17:45 +00001207 /* Initialize write buffer */
1208 init_rwsem(&c->wbuf_sem);
Andrew Victor8f15fd52005-02-09 09:17:45 +00001209
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001210
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001211 c->wbuf_pagesize = c->mtd->erasesize;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001212
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001213 /* Find a suitable c->sector_size
1214 * - Not too much sectors
1215 * - Sectors have to be at least 4 K + some bytes
1216 * - All known dataflashes have erase sizes of 528 or 1056
1217 * - we take at least 8 eraseblocks and want to have at least 8K size
1218 * - The concatenation should be a power of 2
1219 */
Andrew Victor8f15fd52005-02-09 09:17:45 +00001220
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001221 c->sector_size = 8 * c->mtd->erasesize;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001222
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001223 while (c->sector_size < 8192) {
1224 c->sector_size *= 2;
1225 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001226
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001227 /* It may be necessary to adjust the flash size */
1228 c->flash_size = c->mtd->size;
1229
1230 if ((c->flash_size % c->sector_size) != 0) {
1231 c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
1232 printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size);
1233 };
Thomas Gleixner182ec4e2005-11-07 11:16:07 +00001234
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001235 c->wbuf_ofs = 0xFFFFFFFF;
Andrew Victor8f15fd52005-02-09 09:17:45 +00001236 c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1237 if (!c->wbuf)
1238 return -ENOMEM;
1239
michaelcca15842008-04-18 13:44:17 -07001240#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1241 c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1242 if (!c->wbuf_verify) {
1243 kfree(c->oobbuf);
1244 kfree(c->wbuf);
1245 return -ENOMEM;
1246 }
1247#endif
1248
Artem B. Bityutskiydaba5cc2005-09-30 14:59:17 +01001249 printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
Andrew Victor8f15fd52005-02-09 09:17:45 +00001250
1251 return 0;
1252}
1253
1254void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
michaelcca15842008-04-18 13:44:17 -07001255#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1256 kfree(c->wbuf_verify);
1257#endif
Andrew Victor8f15fd52005-02-09 09:17:45 +00001258 kfree(c->wbuf);
1259}
Andrew Victor8f15fd52005-02-09 09:17:45 +00001260
Nicolas Pitre59da7212005-08-06 05:51:33 +01001261int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
Joern Engelc8b229d2006-05-22 23:18:12 +02001262 /* Cleanmarker currently occupies whole programming regions,
1263 * either one or 2 for 8Byte STMicro flashes. */
1264 c->cleanmarker_size = max(16u, c->mtd->writesize);
Nicolas Pitre59da7212005-08-06 05:51:33 +01001265
1266 /* Initialize write buffer */
1267 init_rwsem(&c->wbuf_sem);
Joern Engel28318772006-05-22 23:18:05 +02001268 c->wbuf_pagesize = c->mtd->writesize;
Nicolas Pitre59da7212005-08-06 05:51:33 +01001269 c->wbuf_ofs = 0xFFFFFFFF;
1270
1271 c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1272 if (!c->wbuf)
1273 return -ENOMEM;
1274
Massimo Cirillobc8cec02009-08-27 10:44:09 +02001275#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1276 c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1277 if (!c->wbuf_verify) {
1278 kfree(c->wbuf);
1279 return -ENOMEM;
1280 }
1281#endif
Nicolas Pitre59da7212005-08-06 05:51:33 +01001282 return 0;
1283}
1284
1285void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
Massimo Cirillobc8cec02009-08-27 10:44:09 +02001286#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
1287 kfree(c->wbuf_verify);
1288#endif
Nicolas Pitre59da7212005-08-06 05:51:33 +01001289 kfree(c->wbuf);
1290}
Artem Bityutskiy0029da32006-10-04 19:15:21 +03001291
1292int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
1293 c->cleanmarker_size = 0;
1294
1295 if (c->mtd->writesize == 1)
1296 /* We do not need write-buffer */
1297 return 0;
1298
1299 init_rwsem(&c->wbuf_sem);
1300
1301 c->wbuf_pagesize = c->mtd->writesize;
1302 c->wbuf_ofs = 0xFFFFFFFF;
1303 c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1304 if (!c->wbuf)
1305 return -ENOMEM;
1306
1307 printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
1308
1309 return 0;
1310}
1311
1312void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) {
1313 kfree(c->wbuf);
1314}