Blame view
fs/jffs2/gc.c
43.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* * JFFS2 -- Journalling Flash File System, Version 2. * |
c00c310ea [JFFS2] Tidy up l... |
4 |
* Copyright © 2001-2007 Red Hat, Inc. |
6088c0587 jffs2: Update cop... |
5 |
* Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 9 10 |
* * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * |
1da177e4c Linux-2.6.12-rc2 |
11 |
*/ |
5a528957e jffs2: Use pr_fmt... |
12 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 20 21 |
#include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/slab.h> #include <linux/pagemap.h> #include <linux/crc32.h> #include <linux/compiler.h> #include <linux/stat.h> #include "nodelist.h" #include "compr.h" |
182ec4eee [JFFS2] Clean up ... |
22 |
static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, |
1da177e4c Linux-2.6.12-rc2 |
23 24 |
struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw); |
182ec4eee [JFFS2] Clean up ... |
25 |
static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
26 |
struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); |
182ec4eee [JFFS2] Clean up ... |
27 |
static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
28 |
struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); |
182ec4eee [JFFS2] Clean up ... |
29 |
static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end); static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end); static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f); /* Called with erase_completion_lock held */ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) { struct jffs2_eraseblock *ret; struct list_head *nextlist = NULL; int n = jiffies % 128; /* Pick an eraseblock to garbage collect next. This is where we'll put the clever wear-levelling algorithms. Eventually. */ /* We possibly want to favour the dirtier blocks more when the number of free blocks is low. */ |
a42163d7c [JFFS2] Improve g... |
51 |
again: |
1da177e4c Linux-2.6.12-rc2 |
52 |
if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { |
9c261b33a jffs2: Convert mo... |
53 54 |
jffs2_dbg(1, "Picking block from bad_used_list to GC next "); |
1da177e4c Linux-2.6.12-rc2 |
55 56 |
nextlist = &c->bad_used_list; } else if (n < 50 && !list_empty(&c->erasable_list)) { |
182ec4eee [JFFS2] Clean up ... |
57 |
/* Note that most of them will have gone directly to be erased. |
1da177e4c Linux-2.6.12-rc2 |
58 |
So don't favour the erasable_list _too_ much. */ |
9c261b33a jffs2: Convert mo... |
59 60 |
jffs2_dbg(1, "Picking block from erasable_list to GC next "); |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 |
nextlist = &c->erasable_list; } else if (n < 110 && !list_empty(&c->very_dirty_list)) { /* Most of the time, pick one off the very_dirty list */ |
9c261b33a jffs2: Convert mo... |
64 65 |
jffs2_dbg(1, "Picking block from very_dirty_list to GC next "); |
1da177e4c Linux-2.6.12-rc2 |
66 67 |
nextlist = &c->very_dirty_list; } else if (n < 126 && !list_empty(&c->dirty_list)) { |
9c261b33a jffs2: Convert mo... |
68 69 |
jffs2_dbg(1, "Picking block from dirty_list to GC next "); |
1da177e4c Linux-2.6.12-rc2 |
70 71 |
nextlist = &c->dirty_list; } else if (!list_empty(&c->clean_list)) { |
9c261b33a jffs2: Convert mo... |
72 73 |
jffs2_dbg(1, "Picking block from clean_list to GC next "); |
1da177e4c Linux-2.6.12-rc2 |
74 75 |
nextlist = &c->clean_list; } else if (!list_empty(&c->dirty_list)) { |
9c261b33a jffs2: Convert mo... |
76 77 |
jffs2_dbg(1, "Picking block from dirty_list to GC next (clean_list was empty) "); |
1da177e4c Linux-2.6.12-rc2 |
78 79 80 |
nextlist = &c->dirty_list; } else if (!list_empty(&c->very_dirty_list)) { |
9c261b33a jffs2: Convert mo... |
81 82 |
jffs2_dbg(1, "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty) "); |
1da177e4c Linux-2.6.12-rc2 |
83 84 |
nextlist = &c->very_dirty_list; } else if (!list_empty(&c->erasable_list)) { |
9c261b33a jffs2: Convert mo... |
85 86 |
jffs2_dbg(1, "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty) "); |
1da177e4c Linux-2.6.12-rc2 |
87 88 |
nextlist = &c->erasable_list; |
a42163d7c [JFFS2] Improve g... |
89 90 |
} else if (!list_empty(&c->erasable_pending_wbuf_list)) { /* There are blocks are wating for the wbuf sync */ |
9c261b33a jffs2: Convert mo... |
91 92 |
jffs2_dbg(1, "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks "); |
3cceb9f6c [JFFS2] Prevent d... |
93 |
spin_unlock(&c->erase_completion_lock); |
a42163d7c [JFFS2] Improve g... |
94 |
jffs2_flush_wbuf_pad(c); |
3cceb9f6c [JFFS2] Prevent d... |
95 |
spin_lock(&c->erase_completion_lock); |
a42163d7c [JFFS2] Improve g... |
96 |
goto again; |
1da177e4c Linux-2.6.12-rc2 |
97 98 |
} else { /* Eep. All were empty */ |
5a528957e jffs2: Use pr_fmt... |
99 100 |
jffs2_dbg(1, "No clean, dirty _or_ erasable blocks to GC from! Where are they all? "); |
1da177e4c Linux-2.6.12-rc2 |
101 102 103 104 105 106 107 108 |
return NULL; } ret = list_entry(nextlist->next, struct jffs2_eraseblock, list); list_del(&ret->list); c->gcblock = ret; ret->gc_node = ret->first_node; if (!ret->gc_node) { |
da320f055 jffs2: Convert pr... |
109 110 111 |
pr_warn("Eep. ret->gc_node for block at 0x%08x is NULL ", ret->offset); |
1da177e4c Linux-2.6.12-rc2 |
112 113 |
BUG(); } |
182ec4eee [JFFS2] Clean up ... |
114 |
|
1da177e4c Linux-2.6.12-rc2 |
115 116 |
/* Have we accidentally picked a clean block with wasted space ? */ if (ret->wasted_size) { |
9c261b33a jffs2: Convert mo... |
117 118 119 |
jffs2_dbg(1, "Converting wasted_size %08x to dirty_size ", ret->wasted_size); |
1da177e4c Linux-2.6.12-rc2 |
120 121 122 123 124 |
ret->dirty_size += ret->wasted_size; c->wasted_size -= ret->wasted_size; c->dirty_size += ret->wasted_size; ret->wasted_size = 0; } |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 128 129 130 131 132 133 134 135 136 137 |
return ret; } /* jffs2_garbage_collect_pass * Make a single attempt to progress GC. Move one node, and possibly * start erasing one eraseblock. */ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) { struct jffs2_inode_info *f; struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; |
2665ea842 [JFFS2] Check whe... |
138 |
uint32_t gcblock_dirty; |
1da177e4c Linux-2.6.12-rc2 |
139 |
int ret = 0, inum, nlink; |
aa98d7cf5 [JFFS2][XATTR] XA... |
140 |
int xattr = 0; |
1da177e4c Linux-2.6.12-rc2 |
141 |
|
ced220703 [JFFS2] semaphore... |
142 |
if (mutex_lock_interruptible(&c->alloc_sem)) |
1da177e4c Linux-2.6.12-rc2 |
143 |
return -EINTR; |
5817b9dc9 jffs2: Improve po... |
144 |
|
1da177e4c Linux-2.6.12-rc2 |
145 |
for (;;) { |
5817b9dc9 jffs2: Improve po... |
146 147 148 |
/* We can't start doing GC until we've finished checking the node CRCs etc. */ int bucket, want_ino; |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 |
spin_lock(&c->erase_completion_lock); if (!c->unchecked_size) break; |
1da177e4c Linux-2.6.12-rc2 |
152 |
spin_unlock(&c->erase_completion_lock); |
aa98d7cf5 [JFFS2][XATTR] XA... |
153 154 |
if (!xattr) xattr = jffs2_verify_xattr(c); |
1da177e4c Linux-2.6.12-rc2 |
155 |
spin_lock(&c->inocache_lock); |
5817b9dc9 jffs2: Improve po... |
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
/* Instead of doing the inodes in numeric order, doing a lookup * in the hash for each possible number, just walk the hash * buckets of *existing* inodes. This means that we process * them out-of-order, but it can be a lot faster if there's * a sparse inode# space. Which there often is. */ want_ino = c->check_ino; for (bucket = c->check_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) { for (ic = c->inocache_list[bucket]; ic; ic = ic->next) { if (ic->ino < want_ino) continue; if (ic->state != INO_STATE_CHECKEDABSENT && ic->state != INO_STATE_PRESENT) goto got_next; /* with inocache_lock held */ jffs2_dbg(1, "Skipping ino #%u already checked ", ic->ino); } want_ino = 0; } |
1da177e4c Linux-2.6.12-rc2 |
177 |
|
5817b9dc9 jffs2: Improve po... |
178 179 180 |
/* Point c->check_ino past the end of the last bucket. */ c->check_ino = ((c->highest_ino + c->inocache_hashsize + 1) & ~c->inocache_hashsize) - 1; |
1da177e4c Linux-2.6.12-rc2 |
181 |
|
5817b9dc9 jffs2: Improve po... |
182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
spin_unlock(&c->inocache_lock); pr_crit("Checked all inodes but still 0x%x bytes of unchecked space? ", c->unchecked_size); jffs2_dbg_dump_block_lists_nolock(c); mutex_unlock(&c->alloc_sem); return -ENOSPC; got_next: /* For next time round the loop, we want c->checked_ino to indicate * the *next* one we want to check. And since we're walking the * buckets rather than doing it sequentially, it's: */ c->check_ino = ic->ino + c->inocache_hashsize; |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
27c72b040 [JFFS2] Track par... |
197 |
if (!ic->pino_nlink) { |
9c261b33a jffs2: Convert mo... |
198 199 200 |
jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero ", ic->ino); |
1da177e4c Linux-2.6.12-rc2 |
201 |
spin_unlock(&c->inocache_lock); |
355ed4e14 [JFFS2][XATTR] Fi... |
202 |
jffs2_xattr_delete_inode(c, ic); |
1da177e4c Linux-2.6.12-rc2 |
203 204 205 206 207 |
continue; } switch(ic->state) { case INO_STATE_CHECKEDABSENT: case INO_STATE_PRESENT: |
1da177e4c Linux-2.6.12-rc2 |
208 209 210 211 212 |
spin_unlock(&c->inocache_lock); continue; case INO_STATE_GC: case INO_STATE_CHECKING: |
da320f055 jffs2: Convert pr... |
213 214 215 |
pr_warn("Inode #%u is in state %d during CRC check phase! ", ic->ino, ic->state); |
1da177e4c Linux-2.6.12-rc2 |
216 217 218 219 220 |
spin_unlock(&c->inocache_lock); BUG(); case INO_STATE_READING: /* We need to wait for it to finish, lest we move on |
182ec4eee [JFFS2] Clean up ... |
221 |
and trigger the BUG() above while we haven't yet |
1da177e4c Linux-2.6.12-rc2 |
222 |
finished checking all its nodes */ |
9c261b33a jffs2: Convert mo... |
223 224 225 |
jffs2_dbg(1, "Waiting for ino #%u to finish reading ", ic->ino); |
d96fb997c [JFFS2] Fix race ... |
226 227 |
/* We need to come back again for the _same_ inode. We've made no progress in this case, but that should be OK */ |
5817b9dc9 jffs2: Improve po... |
228 |
c->check_ino = ic->ino; |
d96fb997c [JFFS2] Fix race ... |
229 |
|
ced220703 [JFFS2] semaphore... |
230 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
231 232 233 234 235 236 237 238 239 240 241 |
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); return 0; default: BUG(); case INO_STATE_UNCHECKED: ; } ic->state = INO_STATE_CHECKING; spin_unlock(&c->inocache_lock); |
9c261b33a jffs2: Convert mo... |
242 243 244 |
jffs2_dbg(1, "%s(): triggering inode scan of ino#%u ", __func__, ic->ino); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 |
ret = jffs2_do_crccheck_inode(c, ic); if (ret) |
da320f055 jffs2: Convert pr... |
248 249 250 |
pr_warn("Returned error for crccheck of ino #%u. Expect badness... ", ic->ino); |
1da177e4c Linux-2.6.12-rc2 |
251 252 |
jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); |
ced220703 [JFFS2] semaphore... |
253 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
254 255 |
return ret; } |
0717bf841 jffs2: Erase pend... |
256 257 258 259 |
/* If there are any blocks which need erasing, erase them now */ if (!list_empty(&c->erase_complete_list) || !list_empty(&c->erase_pending_list)) { spin_unlock(&c->erase_completion_lock); |
81cfc9f1f jffs2: Fix seriou... |
260 |
mutex_unlock(&c->alloc_sem); |
9c261b33a jffs2: Convert mo... |
261 262 |
jffs2_dbg(1, "%s(): erasing pending blocks ", __func__); |
81cfc9f1f jffs2: Fix seriou... |
263 |
if (jffs2_erase_pending_blocks(c, 1)) |
0717bf841 jffs2: Erase pend... |
264 |
return 0; |
81cfc9f1f jffs2: Fix seriou... |
265 |
|
9c261b33a jffs2: Convert mo... |
266 267 |
jffs2_dbg(1, "No progress from erasing block; doing GC anyway "); |
81cfc9f1f jffs2: Fix seriou... |
268 |
mutex_lock(&c->alloc_sem); |
226bb7df3 jffs2: Fix lock a... |
269 |
spin_lock(&c->erase_completion_lock); |
0717bf841 jffs2: Erase pend... |
270 |
} |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 274 275 276 277 |
/* First, work out which block we're garbage-collecting */ jeb = c->gcblock; if (!jeb) jeb = jffs2_find_gc_block(c); if (!jeb) { |
422b12023 [JFFS2] Fix jffs2... |
278 |
/* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */ |
0717bf841 jffs2: Erase pend... |
279 |
if (c->nr_erasing_blocks) { |
422b12023 [JFFS2] Fix jffs2... |
280 281 282 283 |
spin_unlock(&c->erase_completion_lock); mutex_unlock(&c->alloc_sem); return -EAGAIN; } |
5a528957e jffs2: Use pr_fmt... |
284 285 |
jffs2_dbg(1, "Couldn't find erase block to garbage collect! "); |
1da177e4c Linux-2.6.12-rc2 |
286 |
spin_unlock(&c->erase_completion_lock); |
ced220703 [JFFS2] semaphore... |
287 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
288 289 |
return -EIO; } |
9c261b33a jffs2: Convert mo... |
290 291 292 |
jffs2_dbg(1, "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x ", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); |
1da177e4c Linux-2.6.12-rc2 |
293 294 295 296 297 |
D1(if (c->nextblock) printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x ", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); if (!jeb->used_size) { |
ced220703 [JFFS2] semaphore... |
298 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
299 300 301 302 |
goto eraseit; } raw = jeb->gc_node; |
2665ea842 [JFFS2] Check whe... |
303 |
gcblock_dirty = jeb->dirty_size; |
182ec4eee [JFFS2] Clean up ... |
304 |
|
1da177e4c Linux-2.6.12-rc2 |
305 |
while(ref_obsolete(raw)) { |
9c261b33a jffs2: Convert mo... |
306 307 308 |
jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping ", ref_offset(raw)); |
99988f7bb [JFFS2] Introduce... |
309 |
raw = ref_next(raw); |
1da177e4c Linux-2.6.12-rc2 |
310 |
if (unlikely(!raw)) { |
da320f055 jffs2: Convert pr... |
311 312 313 314 315 316 |
pr_warn("eep. End of raw list while still supposedly nodes to GC "); pr_warn("erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x ", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); |
1da177e4c Linux-2.6.12-rc2 |
317 318 |
jeb->gc_node = raw; spin_unlock(&c->erase_completion_lock); |
ced220703 [JFFS2] semaphore... |
319 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 323 |
BUG(); } } jeb->gc_node = raw; |
9c261b33a jffs2: Convert mo... |
324 325 326 |
jffs2_dbg(1, "Going to garbage collect node at 0x%08x ", ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
327 328 329 |
if (!raw->next_in_ino) { /* Inode-less node. Clean marker, snapshot or something like that */ |
1da177e4c Linux-2.6.12-rc2 |
330 |
spin_unlock(&c->erase_completion_lock); |
6171586a7 [JFFS2] Correct h... |
331 332 333 334 335 336 337 |
if (ref_flags(raw) == REF_PRISTINE) { /* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */ jffs2_garbage_collect_pristine(c, NULL, raw); } else { /* Just mark it obsolete */ jffs2_mark_node_obsolete(c, raw); } |
ced220703 [JFFS2] semaphore... |
338 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
339 340 341 342 |
goto eraseit_lock; } ic = jffs2_raw_ref_to_ic(raw); |
084702e00 [JFFS2][XATTR] Re... |
343 |
#ifdef CONFIG_JFFS2_FS_XATTR |
aa98d7cf5 [JFFS2][XATTR] XA... |
344 |
/* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. |
084702e00 [JFFS2][XATTR] Re... |
345 346 347 |
* We can decide whether this node is inode or xattr by ic->class. */ if (ic->class == RAWNODE_CLASS_XATTR_DATUM || ic->class == RAWNODE_CLASS_XATTR_REF) { |
084702e00 [JFFS2][XATTR] Re... |
348 349 350 |
spin_unlock(&c->erase_completion_lock); if (ic->class == RAWNODE_CLASS_XATTR_DATUM) { |
c9f700f84 [JFFS2][XATTR] us... |
351 |
ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw); |
084702e00 [JFFS2][XATTR] Re... |
352 |
} else { |
c9f700f84 [JFFS2][XATTR] us... |
353 |
ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); |
084702e00 [JFFS2][XATTR] Re... |
354 |
} |
2665ea842 [JFFS2] Check whe... |
355 |
goto test_gcnode; |
084702e00 [JFFS2][XATTR] Re... |
356 357 |
} #endif |
aa98d7cf5 [JFFS2][XATTR] XA... |
358 |
|
1da177e4c Linux-2.6.12-rc2 |
359 |
/* We need to hold the inocache. Either the erase_completion_lock or |
182ec4eee [JFFS2] Clean up ... |
360 |
the inocache_lock are sufficient; we trade down since the inocache_lock |
1da177e4c Linux-2.6.12-rc2 |
361 362 363 364 |
causes less contention. */ spin_lock(&c->inocache_lock); spin_unlock(&c->erase_completion_lock); |
9c261b33a jffs2: Convert mo... |
365 366 367 368 |
jffs2_dbg(1, "%s(): collecting from block @0x%08x. Node @0x%08x(%d), ino #%u ", __func__, jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino); |
1da177e4c Linux-2.6.12-rc2 |
369 370 371 372 373 374 375 376 377 378 379 380 |
/* Three possibilities: 1. Inode is already in-core. We must iget it and do proper updating to its fragtree, etc. 2. Inode is not in-core, node is REF_PRISTINE. We lock the inocache to prevent a read_inode(), copy the node intact. 3. Inode is not in-core, node is not pristine. We must iget() and take the slow path. */ switch(ic->state) { case INO_STATE_CHECKEDABSENT: |
182ec4eee [JFFS2] Clean up ... |
381 |
/* It's been checked, but it's not currently in-core. |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 385 386 387 |
We can just copy any pristine nodes, but have to prevent anyone else from doing read_inode() while we're at it, so we set the state accordingly */ if (ref_flags(raw) == REF_PRISTINE) ic->state = INO_STATE_GC; else { |
9c261b33a jffs2: Convert mo... |
388 389 390 |
jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading. ", ic->ino); |
1da177e4c Linux-2.6.12-rc2 |
391 392 393 394 395 396 397 398 399 400 401 |
} break; case INO_STATE_PRESENT: /* It's in-core. GC must iget() it. */ break; case INO_STATE_UNCHECKED: case INO_STATE_CHECKING: case INO_STATE_GC: /* Should never happen. We should have finished checking |
182ec4eee [JFFS2] Clean up ... |
402 403 |
by the time we actually start doing any GC, and since we're holding the alloc_sem, no other garbage collection |
1da177e4c Linux-2.6.12-rc2 |
404 405 |
can happen. */ |
da320f055 jffs2: Convert pr... |
406 407 408 |
pr_crit("Inode #%u already in state %d in jffs2_garbage_collect_pass()! ", ic->ino, ic->state); |
ced220703 [JFFS2] semaphore... |
409 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
410 411 412 413 414 415 416 417 418 |
spin_unlock(&c->inocache_lock); BUG(); case INO_STATE_READING: /* Someone's currently trying to read it. We must wait for them to finish and then go through the full iget() route to do the GC. However, sometimes read_inode() needs to get the alloc_sem() (for marking nodes invalid) so we must drop the alloc_sem before sleeping. */ |
ced220703 [JFFS2] semaphore... |
419 |
mutex_unlock(&c->alloc_sem); |
9c261b33a jffs2: Convert mo... |
420 421 422 |
jffs2_dbg(1, "%s(): waiting for ino #%u in state %d ", __func__, ic->ino, ic->state); |
1da177e4c Linux-2.6.12-rc2 |
423 |
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
182ec4eee [JFFS2] Clean up ... |
424 |
/* And because we dropped the alloc_sem we must start again from the |
1da177e4c Linux-2.6.12-rc2 |
425 426 |
beginning. Ponder chance of livelock here -- we're returning success without actually making any progress. |
182ec4eee [JFFS2] Clean up ... |
427 |
Q: What are the chances that the inode is back in INO_STATE_READING |
1da177e4c Linux-2.6.12-rc2 |
428 429 |
again by the time we next enter this function? And that this happens enough times to cause a real delay? |
182ec4eee [JFFS2] Clean up ... |
430 |
A: Small enough that I don't care :) |
1da177e4c Linux-2.6.12-rc2 |
431 432 433 434 435 |
*/ return 0; } /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the |
182ec4eee [JFFS2] Clean up ... |
436 |
node intact, and we don't have to muck about with the fragtree etc. |
1da177e4c Linux-2.6.12-rc2 |
437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
because we know it's not in-core. If it _was_ in-core, we go through all the iget() crap anyway */ if (ic->state == INO_STATE_GC) { spin_unlock(&c->inocache_lock); ret = jffs2_garbage_collect_pristine(c, ic, raw); spin_lock(&c->inocache_lock); ic->state = INO_STATE_CHECKEDABSENT; wake_up(&c->inocache_wq); if (ret != -EBADFD) { spin_unlock(&c->inocache_lock); |
2665ea842 [JFFS2] Check whe... |
451 |
goto test_gcnode; |
1da177e4c Linux-2.6.12-rc2 |
452 453 454 455 456 457 458 459 460 461 462 463 464 |
} /* Fall through if it wanted us to, with inocache_lock held */ } /* Prevent the fairly unlikely race where the gcblock is entirely obsoleted by the final close of a file which had the only valid nodes in the block, followed by erasure, followed by freeing of the ic because the erased block(s) held _all_ the nodes of that inode.... never been seen but it's vaguely possible. */ inum = ic->ino; |
27c72b040 [JFFS2] Track par... |
465 |
nlink = ic->pino_nlink; |
1da177e4c Linux-2.6.12-rc2 |
466 |
spin_unlock(&c->inocache_lock); |
1b690b487 [JFFS2] Invert la... |
467 |
f = jffs2_gc_fetch_inode(c, inum, !nlink); |
1da177e4c Linux-2.6.12-rc2 |
468 469 470 471 472 473 474 475 476 477 478 479 |
if (IS_ERR(f)) { ret = PTR_ERR(f); goto release_sem; } if (!f) { ret = 0; goto release_sem; } ret = jffs2_garbage_collect_live(c, jeb, raw, f); jffs2_gc_release_inode(c, f); |
2665ea842 [JFFS2] Check whe... |
480 481 482 |
test_gcnode: if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { /* Eep. This really should never happen. GC is broken */ |
da320f055 jffs2: Convert pr... |
483 484 485 |
pr_err("Error garbage collecting node at %08x! ", ref_offset(jeb->gc_node)); |
2665ea842 [JFFS2] Check whe... |
486 |
ret = -ENOSPC; |
4fc8a6078 [JFFS2] Remove st... |
487 |
} |
1da177e4c Linux-2.6.12-rc2 |
488 |
release_sem: |
ced220703 [JFFS2] semaphore... |
489 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 493 494 495 496 |
eraseit_lock: /* If we've finished this block, start it erasing */ spin_lock(&c->erase_completion_lock); eraseit: if (c->gcblock && !c->gcblock->used_size) { |
9c261b33a jffs2: Convert mo... |
497 498 499 |
jffs2_dbg(1, "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list ", c->gcblock->offset); |
1da177e4c Linux-2.6.12-rc2 |
500 501 502 503 |
/* We're GC'ing an empty block? */ list_add_tail(&c->gcblock->list, &c->erase_pending_list); c->gcblock = NULL; c->nr_erasing_blocks++; |
ae3b6ba06 jffs2: Use jffs2_... |
504 |
jffs2_garbage_collect_trigger(c); |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
} spin_unlock(&c->erase_completion_lock); return ret; } static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f) { struct jffs2_node_frag *frag; struct jffs2_full_dnode *fn = NULL; struct jffs2_full_dirent *fd; uint32_t start = 0, end = 0, nrfrags = 0; int ret = 0; |
ced220703 [JFFS2] semaphore... |
519 |
mutex_lock(&f->sem); |
1da177e4c Linux-2.6.12-rc2 |
520 521 522 523 524 525 526 527 |
/* Now we have the lock for this inode. Check that it's still the one at the head of the list. */ spin_lock(&c->erase_completion_lock); if (c->gcblock != jeb) { spin_unlock(&c->erase_completion_lock); |
9c261b33a jffs2: Convert mo... |
528 529 |
jffs2_dbg(1, "GC block is no longer gcblock. Restart "); |
1da177e4c Linux-2.6.12-rc2 |
530 531 532 533 |
goto upnout; } if (ref_obsolete(raw)) { spin_unlock(&c->erase_completion_lock); |
9c261b33a jffs2: Convert mo... |
534 535 |
jffs2_dbg(1, "node to be GC'd was obsoleted in the meantime. "); |
1da177e4c Linux-2.6.12-rc2 |
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
/* They'll call again */ goto upnout; } spin_unlock(&c->erase_completion_lock); /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */ if (f->metadata && f->metadata->raw == raw) { fn = f->metadata; ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); goto upnout; } /* FIXME. Read node and do lookup? */ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { if (frag->node && frag->node->raw == raw) { fn = frag->node; end = frag->ofs + frag->size; if (!nrfrags++) start = frag->ofs; if (nrfrags == frag->node->frags) break; /* We've found them all */ } } if (fn) { if (ref_flags(raw) == REF_PRISTINE) { ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); if (!ret) { /* Urgh. Return it sensibly. */ frag->node->raw = f->inocache->nodes; |
182ec4eee [JFFS2] Clean up ... |
565 |
} |
1da177e4c Linux-2.6.12-rc2 |
566 567 568 569 |
if (ret != -EBADFD) goto upnout; } /* We found a datanode. Do the GC */ |
09cbfeaf1 mm, fs: get rid o... |
570 |
if((start >> PAGE_SHIFT) < ((end-1) >> PAGE_SHIFT)) { |
1da177e4c Linux-2.6.12-rc2 |
571 572 573 574 575 576 577 578 |
/* It crosses a page boundary. Therefore, it must be a hole. */ ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); } else { /* It could still be a hole. But we GC the page this way anyway */ ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end); } goto upnout; } |
182ec4eee [JFFS2] Clean up ... |
579 |
|
1da177e4c Linux-2.6.12-rc2 |
580 581 582 583 584 585 586 587 588 589 590 |
/* Wasn't a dnode. Try dirent */ for (fd = f->dents; fd; fd=fd->next) { if (fd->raw == raw) break; } if (fd && fd->ino) { ret = jffs2_garbage_collect_dirent(c, jeb, f, fd); } else if (fd) { ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); } else { |
da320f055 jffs2: Convert pr... |
591 592 593 |
pr_warn("Raw node at 0x%08x wasn't in node lists for ino #%u ", ref_offset(raw), f->inocache->ino); |
1da177e4c Linux-2.6.12-rc2 |
594 |
if (ref_obsolete(raw)) { |
da320f055 jffs2: Convert pr... |
595 596 |
pr_warn("But it's obsolete so we don't mind too much "); |
1da177e4c Linux-2.6.12-rc2 |
597 |
} else { |
e0c8e42f8 [JFFS2] Debug cod... |
598 599 |
jffs2_dbg_dump_node(c, ref_offset(raw)); BUG(); |
1da177e4c Linux-2.6.12-rc2 |
600 601 602 |
} } upnout: |
ced220703 [JFFS2] semaphore... |
603 |
mutex_unlock(&f->sem); |
1da177e4c Linux-2.6.12-rc2 |
604 605 606 |
return ret; } |
182ec4eee [JFFS2] Clean up ... |
607 |
static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, |
1da177e4c Linux-2.6.12-rc2 |
608 609 610 611 |
struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw) { union jffs2_node_union *node; |
1da177e4c Linux-2.6.12-rc2 |
612 613 614 615 616 |
size_t retlen; int ret; uint32_t phys_ofs, alloclen; uint32_t crc, rawlen; int retried = 0; |
9c261b33a jffs2: Convert mo... |
617 618 619 |
jffs2_dbg(1, "Going to GC REF_PRISTINE node at 0x%08x ", ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
620 |
|
6171586a7 [JFFS2] Correct h... |
621 |
alloclen = rawlen = ref_totlen(c, c->gcblock, raw); |
1da177e4c Linux-2.6.12-rc2 |
622 623 624 625 |
/* Ask for a small amount of space (or the totlen if smaller) because we don't want to force wastage of the end of a block if splitting would work. */ |
6171586a7 [JFFS2] Correct h... |
626 627 |
if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; |
9fe4854cd [JFFS2] Remove fl... |
628 |
ret = jffs2_reserve_space_gc(c, alloclen, &alloclen, rawlen); |
6171586a7 [JFFS2] Correct h... |
629 |
/* 'rawlen' is not the exact summary size; it is only an upper estimation */ |
e631ddba5 [JFFS2] Add erase... |
630 |
|
1da177e4c Linux-2.6.12-rc2 |
631 632 633 634 635 636 637 638 639 640 |
if (ret) return ret; if (alloclen < rawlen) { /* Doesn't fit untouched. We'll go the old route and split it */ return -EBADFD; } node = kmalloc(rawlen, GFP_KERNEL); if (!node) |
ef53cb02f [JFFS2] Whitespac... |
641 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
642 643 644 645 646 647 648 649 650 |
ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); if (!ret && retlen != rawlen) ret = -EIO; if (ret) goto out_node; crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); if (je32_to_cpu(node->u.hdr_crc) != crc) { |
da320f055 jffs2: Convert pr... |
651 652 653 |
pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x ", ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
654 655 656 657 658 659 660 |
goto bail; } switch(je16_to_cpu(node->u.nodetype)) { case JFFS2_NODETYPE_INODE: crc = crc32(0, node, sizeof(node->i)-8); if (je32_to_cpu(node->i.node_crc) != crc) { |
da320f055 jffs2: Convert pr... |
661 662 663 664 |
pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x ", ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
665 666 667 668 669 670 |
goto bail; } if (je32_to_cpu(node->i.dsize)) { crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); if (je32_to_cpu(node->i.data_crc) != crc) { |
da320f055 jffs2: Convert pr... |
671 672 673 674 |
pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x ", ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
675 676 677 678 679 680 681 682 |
goto bail; } } break; case JFFS2_NODETYPE_DIRENT: crc = crc32(0, node, sizeof(node->d)-8); if (je32_to_cpu(node->d.node_crc) != crc) { |
da320f055 jffs2: Convert pr... |
683 684 685 686 |
pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x ", ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
687 688 |
goto bail; } |
b534e70cf [JFFS2] Handle di... |
689 |
if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { |
da320f055 jffs2: Convert pr... |
690 691 692 |
pr_warn("Name in dirent node at 0x%08x contains zeroes ", ref_offset(raw)); |
b534e70cf [JFFS2] Handle di... |
693 694 |
goto bail; } |
1da177e4c Linux-2.6.12-rc2 |
695 696 697 |
if (node->d.nsize) { crc = crc32(0, node->d.name, node->d.nsize); if (je32_to_cpu(node->d.name_crc) != crc) { |
da320f055 jffs2: Convert pr... |
698 699 700 701 |
pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x ", ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
702 703 704 705 706 |
goto bail; } } break; default: |
6171586a7 [JFFS2] Correct h... |
707 708 |
/* If it's inode-less, we don't _know_ what it is. Just copy it intact */ if (ic) { |
da320f055 jffs2: Convert pr... |
709 710 711 |
pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x ", ref_offset(raw), je16_to_cpu(node->u.nodetype)); |
6171586a7 [JFFS2] Correct h... |
712 713 |
goto bail; } |
1da177e4c Linux-2.6.12-rc2 |
714 |
} |
1da177e4c Linux-2.6.12-rc2 |
715 716 |
/* OK, all the CRCs are good; this node can just be copied as-is. */ retry: |
2f785402f [JFFS2] Reduce vi... |
717 |
phys_ofs = write_ofs(c); |
1da177e4c Linux-2.6.12-rc2 |
718 719 720 721 |
ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); if (ret || (retlen != rawlen)) { |
da320f055 jffs2: Convert pr... |
722 723 724 |
pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd ", rawlen, phys_ofs, ret, retlen); |
1da177e4c Linux-2.6.12-rc2 |
725 |
if (retlen) { |
2f785402f [JFFS2] Reduce vi... |
726 |
jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); |
1da177e4c Linux-2.6.12-rc2 |
727 |
} else { |
da320f055 jffs2: Convert pr... |
728 729 730 |
pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero ", phys_ofs); |
1da177e4c Linux-2.6.12-rc2 |
731 |
} |
2f785402f [JFFS2] Reduce vi... |
732 |
if (!retried) { |
1da177e4c Linux-2.6.12-rc2 |
733 734 735 736 737 |
/* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; retried = 1; |
9c261b33a jffs2: Convert mo... |
738 739 |
jffs2_dbg(1, "Retrying failed write of REF_PRISTINE node. "); |
182ec4eee [JFFS2] Clean up ... |
740 |
|
730554d94 [JFFS2] Debug cod... |
741 742 |
jffs2_dbg_acct_sanity_check(c,jeb); jffs2_dbg_acct_paranoia_check(c, jeb); |
1da177e4c Linux-2.6.12-rc2 |
743 |
|
9fe4854cd [JFFS2] Remove fl... |
744 |
ret = jffs2_reserve_space_gc(c, rawlen, &dummy, rawlen); |
e631ddba5 [JFFS2] Add erase... |
745 746 |
/* this is not the exact summary size of it, it is only an upper estimation */ |
1da177e4c Linux-2.6.12-rc2 |
747 748 |
if (!ret) { |
9c261b33a jffs2: Convert mo... |
749 750 751 |
jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write. ", phys_ofs); |
1da177e4c Linux-2.6.12-rc2 |
752 |
|
730554d94 [JFFS2] Debug cod... |
753 754 |
jffs2_dbg_acct_sanity_check(c,jeb); jffs2_dbg_acct_paranoia_check(c, jeb); |
1da177e4c Linux-2.6.12-rc2 |
755 756 757 |
goto retry; } |
9c261b33a jffs2: Convert mo... |
758 759 760 |
jffs2_dbg(1, "Failed to allocate space to retry failed write: %d! ", ret); |
1da177e4c Linux-2.6.12-rc2 |
761 |
} |
1da177e4c Linux-2.6.12-rc2 |
762 763 764 765 |
if (!ret) ret = -EIO; goto out_node; } |
2f785402f [JFFS2] Reduce vi... |
766 |
jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic); |
1da177e4c Linux-2.6.12-rc2 |
767 |
|
1da177e4c Linux-2.6.12-rc2 |
768 |
jffs2_mark_node_obsolete(c, raw); |
9c261b33a jffs2: Convert mo... |
769 770 771 |
jffs2_dbg(1, "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded ", ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
772 773 774 775 776 777 778 779 |
out_node: kfree(node); return ret; bail: ret = -EBADFD; goto out_node; } |
182ec4eee [JFFS2] Clean up ... |
780 |
static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
781 782 783 784 |
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; |
8557fd51c [JFFS2] Fix race ... |
785 |
struct jffs2_node_frag *last_frag; |
aef9ab478 [JFFS2] Support n... |
786 |
union jffs2_device_node dev; |
2e16cfca6 jffs2: Fix long-s... |
787 788 |
char *mdata = NULL; int mdatalen = 0; |
9fe4854cd [JFFS2] Remove fl... |
789 |
uint32_t alloclen, ilen; |
1da177e4c Linux-2.6.12-rc2 |
790 791 792 793 794 |
int ret; if (S_ISBLK(JFFS2_F_I_MODE(f)) || S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ |
aef9ab478 [JFFS2] Support n... |
795 |
mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); |
1da177e4c Linux-2.6.12-rc2 |
796 |
mdata = (char *)&dev; |
9c261b33a jffs2: Convert mo... |
797 798 799 |
jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t ", __func__, mdatalen); |
1da177e4c Linux-2.6.12-rc2 |
800 801 802 803 |
} else if (S_ISLNK(JFFS2_F_I_MODE(f))) { mdatalen = fn->size; mdata = kmalloc(fn->size, GFP_KERNEL); if (!mdata) { |
da320f055 jffs2: Convert pr... |
804 805 |
pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata() "); |
1da177e4c Linux-2.6.12-rc2 |
806 807 808 809 |
return -ENOMEM; } ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen); if (ret) { |
da320f055 jffs2: Convert pr... |
810 811 812 |
pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d ", ret); |
1da177e4c Linux-2.6.12-rc2 |
813 814 815 |
kfree(mdata); return ret; } |
9c261b33a jffs2: Convert mo... |
816 817 818 |
jffs2_dbg(1, "%s(): Writing %d bites of symlink target ", __func__, mdatalen); |
1da177e4c Linux-2.6.12-rc2 |
819 820 |
} |
182ec4eee [JFFS2] Clean up ... |
821 |
|
9fe4854cd [JFFS2] Remove fl... |
822 |
ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &alloclen, |
e631ddba5 [JFFS2] Add erase... |
823 |
JFFS2_SUMMARY_INODE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
824 |
if (ret) { |
da320f055 jffs2: Convert pr... |
825 826 827 |
pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d ", sizeof(ri) + mdatalen, ret); |
1da177e4c Linux-2.6.12-rc2 |
828 829 |
goto out; } |
182ec4eee [JFFS2] Clean up ... |
830 |
|
8557fd51c [JFFS2] Fix race ... |
831 832 833 834 835 836 837 |
last_frag = frag_last(&f->fragtree); if (last_frag) /* Fetch the inode length from the fragtree rather then * from i_size since i_size may have not been updated yet */ ilen = last_frag->ofs + last_frag->size; else ilen = JFFS2_F_I_SIZE(f); |
182ec4eee [JFFS2] Clean up ... |
838 |
|
1da177e4c Linux-2.6.12-rc2 |
839 840 841 842 843 844 845 846 847 848 849 |
memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
8557fd51c [JFFS2] Fix race ... |
850 |
ri.isize = cpu_to_je32(ilen); |
1da177e4c Linux-2.6.12-rc2 |
851 852 853 854 855 856 857 858 859 |
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); ri.offset = cpu_to_je32(0); ri.csize = cpu_to_je32(mdatalen); ri.dsize = cpu_to_je32(mdatalen); ri.compr = JFFS2_COMPR_NONE; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); |
9fe4854cd [JFFS2] Remove fl... |
860 |
new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC); |
1da177e4c Linux-2.6.12-rc2 |
861 862 |
if (IS_ERR(new_fn)) { |
da320f055 jffs2: Convert pr... |
863 864 |
pr_warn("Error writing new dnode: %ld ", PTR_ERR(new_fn)); |
1da177e4c Linux-2.6.12-rc2 |
865 866 867 868 869 870 871 872 873 874 875 |
ret = PTR_ERR(new_fn); goto out; } jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); f->metadata = new_fn; out: if (S_ISLNK(JFFS2_F_I_MODE(f))) kfree(mdata); return ret; } |
182ec4eee [JFFS2] Clean up ... |
876 |
static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
877 878 879 880 |
struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { struct jffs2_full_dirent *new_fd; struct jffs2_raw_dirent rd; |
9fe4854cd [JFFS2] Remove fl... |
881 |
uint32_t alloclen; |
1da177e4c Linux-2.6.12-rc2 |
882 883 884 885 886 887 888 889 890 891 892 |
int ret; rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd.nsize = strlen(fd->name); rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); rd.pino = cpu_to_je32(f->inocache->ino); rd.version = cpu_to_je32(++f->highest_version); rd.ino = cpu_to_je32(fd->ino); |
3a69e0cd2 [JFFS2] Fix JFFS2... |
893 894 895 896 |
/* If the times on this inode were set by explicit utime() they can be different, so refrain from splatting them. */ if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f)) rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f)); |
182ec4eee [JFFS2] Clean up ... |
897 |
else |
3a69e0cd2 [JFFS2] Fix JFFS2... |
898 |
rd.mctime = cpu_to_je32(0); |
1da177e4c Linux-2.6.12-rc2 |
899 900 901 |
rd.type = fd->type; rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); |
182ec4eee [JFFS2] Clean up ... |
902 |
|
9fe4854cd [JFFS2] Remove fl... |
903 |
ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &alloclen, |
e631ddba5 [JFFS2] Add erase... |
904 |
JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize)); |
1da177e4c Linux-2.6.12-rc2 |
905 |
if (ret) { |
da320f055 jffs2: Convert pr... |
906 907 908 |
pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d ", sizeof(rd)+rd.nsize, ret); |
1da177e4c Linux-2.6.12-rc2 |
909 910 |
return ret; } |
9fe4854cd [JFFS2] Remove fl... |
911 |
new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, ALLOC_GC); |
1da177e4c Linux-2.6.12-rc2 |
912 913 |
if (IS_ERR(new_fd)) { |
da320f055 jffs2: Convert pr... |
914 915 916 |
pr_warn("jffs2_write_dirent in garbage_collect_dirent failed: %ld ", PTR_ERR(new_fd)); |
1da177e4c Linux-2.6.12-rc2 |
917 918 919 920 921 |
return PTR_ERR(new_fd); } jffs2_add_fd_to_list(c, new_fd, &f->dents); return 0; } |
182ec4eee [JFFS2] Clean up ... |
922 |
static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
1da177e4c Linux-2.6.12-rc2 |
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 |
struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { struct jffs2_full_dirent **fdp = &f->dents; int found = 0; /* On a medium where we can't actually mark nodes obsolete pernamently, such as NAND flash, we need to work out whether this deletion dirent is still needed to actively delete a 'real' dirent with the same name that's still somewhere else on the flash. */ if (!jffs2_can_mark_obsolete(c)) { struct jffs2_raw_dirent *rd; struct jffs2_raw_node_ref *raw; int ret; size_t retlen; int name_len = strlen(fd->name); uint32_t name_crc = crc32(0, fd->name, name_len); uint32_t rawlen = ref_totlen(c, jeb, fd->raw); rd = kmalloc(rawlen, GFP_KERNEL); if (!rd) return -ENOMEM; /* Prevent the erase code from nicking the obsolete node refs while we're looking at them. I really don't like this extra lock but can't see any alternative. Suggestions on a postcard to... */ |
ced220703 [JFFS2] semaphore... |
949 |
mutex_lock(&c->erase_free_sem); |
1da177e4c Linux-2.6.12-rc2 |
950 951 |
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { |
aba54da3d [JFFS2] add cond_... |
952 |
cond_resched(); |
1da177e4c Linux-2.6.12-rc2 |
953 954 955 956 957 958 959 |
/* We only care about obsolete ones */ if (!(ref_obsolete(raw))) continue; /* Any dirent with the same name is going to have the same length... */ if (ref_totlen(c, NULL, raw) != rawlen) continue; |
182ec4eee [JFFS2] Clean up ... |
960 |
/* Doesn't matter if there's one in the same erase block. We're going to |
1da177e4c Linux-2.6.12-rc2 |
961 |
delete it too at the same time. */ |
3be36675d [JFFS2] Core chan... |
962 |
if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) |
1da177e4c Linux-2.6.12-rc2 |
963 |
continue; |
9c261b33a jffs2: Convert mo... |
964 965 966 |
jffs2_dbg(1, "Check potential deletion dirent at %08x ", ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
967 968 969 970 971 |
/* This is an obsolete node belonging to the same directory, and it's of the right length. We need to take a closer look...*/ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd); if (ret) { |
da320f055 jffs2: Convert pr... |
972 973 974 |
pr_warn("%s(): Read error (%d) reading obsolete node at %08x ", __func__, ret, ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
975 976 977 978 |
/* If we can't read it, we don't need to continue to obsolete it. Continue */ continue; } if (retlen != rawlen) { |
da320f055 jffs2: Convert pr... |
979 980 981 982 |
pr_warn("%s(): Short read (%zd not %u) reading header from obsolete node at %08x ", __func__, retlen, rawlen, ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
continue; } if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) continue; /* If the name CRC doesn't match, skip */ if (je32_to_cpu(rd->name_crc) != name_crc) continue; /* If the name length doesn't match, or it's another deletion dirent, skip */ if (rd->nsize != name_len || !je32_to_cpu(rd->ino)) continue; /* OK, check the actual name now */ if (memcmp(rd->name, fd->name, name_len)) continue; /* OK. The name really does match. There really is still an older node on the flash which our deletion dirent obsoletes. So we have to write out a new deletion dirent to replace it */ |
ced220703 [JFFS2] semaphore... |
1004 |
mutex_unlock(&c->erase_free_sem); |
1da177e4c Linux-2.6.12-rc2 |
1005 |
|
9c261b33a jffs2: Convert mo... |
1006 1007 1008 1009 |
jffs2_dbg(1, "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u ", ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)); |
1da177e4c Linux-2.6.12-rc2 |
1010 1011 1012 1013 |
kfree(rd); return jffs2_garbage_collect_dirent(c, jeb, f, fd); } |
ced220703 [JFFS2] semaphore... |
1014 |
mutex_unlock(&c->erase_free_sem); |
1da177e4c Linux-2.6.12-rc2 |
1015 1016 |
kfree(rd); } |
182ec4eee [JFFS2] Clean up ... |
1017 |
/* FIXME: If we're deleting a dirent which contains the current mtime and ctime, |
3a69e0cd2 [JFFS2] Fix JFFS2... |
1018 |
we should update the metadata node with those times accordingly */ |
1da177e4c Linux-2.6.12-rc2 |
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
/* No need for it any more. Just mark it obsolete and remove it from the list */ while (*fdp) { if ((*fdp) == fd) { found = 1; *fdp = fd->next; break; } fdp = &(*fdp)->next; } if (!found) { |
da320f055 jffs2: Convert pr... |
1029 1030 1031 |
pr_warn("Deletion dirent \"%s\" not found in list for ino #%u ", fd->name, f->inocache->ino); |
1da177e4c Linux-2.6.12-rc2 |
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 |
} jffs2_mark_node_obsolete(c, fd->raw); jffs2_free_full_dirent(fd); return 0; } static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end) { struct jffs2_raw_inode ri; struct jffs2_node_frag *frag; struct jffs2_full_dnode *new_fn; |
9fe4854cd [JFFS2] Remove fl... |
1045 |
uint32_t alloclen, ilen; |
1da177e4c Linux-2.6.12-rc2 |
1046 |
int ret; |
9c261b33a jffs2: Convert mo... |
1047 1048 1049 |
jffs2_dbg(1, "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x ", f->inocache->ino, start, end); |
182ec4eee [JFFS2] Clean up ... |
1050 |
|
1da177e4c Linux-2.6.12-rc2 |
1051 1052 1053 1054 1055 |
memset(&ri, 0, sizeof(ri)); if(fn->frags > 1) { size_t readlen; uint32_t crc; |
182ec4eee [JFFS2] Clean up ... |
1056 |
/* It's partially obsoleted by a later write. So we have to |
1da177e4c Linux-2.6.12-rc2 |
1057 1058 1059 |
write it out again with the _same_ version as before */ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { |
da320f055 jffs2: Convert pr... |
1060 1061 1062 |
pr_warn("Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node ", ret, readlen); |
1da177e4c Linux-2.6.12-rc2 |
1063 1064 1065 |
goto fill; } if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { |
da320f055 jffs2: Convert pr... |
1066 1067 1068 1069 |
pr_warn("%s(): Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x) ", __func__, ref_offset(fn->raw), je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE); |
1da177e4c Linux-2.6.12-rc2 |
1070 1071 1072 |
return -EIO; } if (je32_to_cpu(ri.totlen) != sizeof(ri)) { |
da320f055 jffs2: Convert pr... |
1073 1074 1075 1076 |
pr_warn("%s(): Node at 0x%08x had totlen 0x%x instead of expected 0x%zx ", __func__, ref_offset(fn->raw), je32_to_cpu(ri.totlen), sizeof(ri)); |
1da177e4c Linux-2.6.12-rc2 |
1077 1078 1079 1080 |
return -EIO; } crc = crc32(0, &ri, sizeof(ri)-8); if (crc != je32_to_cpu(ri.node_crc)) { |
da320f055 jffs2: Convert pr... |
1081 1082 1083 1084 |
pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x ", __func__, ref_offset(fn->raw), je32_to_cpu(ri.node_crc), crc); |
1da177e4c Linux-2.6.12-rc2 |
1085 |
/* FIXME: We could possibly deal with this by writing new holes for each frag */ |
da320f055 jffs2: Convert pr... |
1086 1087 1088 |
pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost ", start, end, f->inocache->ino); |
1da177e4c Linux-2.6.12-rc2 |
1089 1090 1091 |
goto fill; } if (ri.compr != JFFS2_COMPR_ZERO) { |
da320f055 jffs2: Convert pr... |
1092 1093 1094 1095 1096 1097 |
pr_warn("%s(): Node 0x%08x wasn't a hole node! ", __func__, ref_offset(fn->raw)); pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost ", start, end, f->inocache->ino); |
1da177e4c Linux-2.6.12-rc2 |
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 |
goto fill; } } else { fill: ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri.totlen = cpu_to_je32(sizeof(ri)); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); ri.offset = cpu_to_je32(start); ri.dsize = cpu_to_je32(end - start); ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } |
182ec4eee [JFFS2] Clean up ... |
1114 |
|
8557fd51c [JFFS2] Fix race ... |
1115 1116 1117 1118 1119 1120 1121 |
frag = frag_last(&f->fragtree); if (frag) /* Fetch the inode length from the fragtree rather then * from i_size since i_size may have not been updated yet */ ilen = frag->ofs + frag->size; else ilen = JFFS2_F_I_SIZE(f); |
1da177e4c Linux-2.6.12-rc2 |
1122 1123 1124 |
ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
8557fd51c [JFFS2] Fix race ... |
1125 |
ri.isize = cpu_to_je32(ilen); |
1da177e4c Linux-2.6.12-rc2 |
1126 1127 1128 1129 1130 |
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); ri.data_crc = cpu_to_je32(0); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); |
9fe4854cd [JFFS2] Remove fl... |
1131 1132 |
ret = jffs2_reserve_space_gc(c, sizeof(ri), &alloclen, JFFS2_SUMMARY_INODE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
1133 |
if (ret) { |
da320f055 jffs2: Convert pr... |
1134 1135 1136 |
pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d ", sizeof(ri), ret); |
1da177e4c Linux-2.6.12-rc2 |
1137 1138 |
return ret; } |
9fe4854cd [JFFS2] Remove fl... |
1139 |
new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_GC); |
1da177e4c Linux-2.6.12-rc2 |
1140 1141 |
if (IS_ERR(new_fn)) { |
da320f055 jffs2: Convert pr... |
1142 1143 |
pr_warn("Error writing new hole node: %ld ", PTR_ERR(new_fn)); |
1da177e4c Linux-2.6.12-rc2 |
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 |
return PTR_ERR(new_fn); } if (je32_to_cpu(ri.version) == f->highest_version) { jffs2_add_full_dnode_to_inode(c, f, new_fn); if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); f->metadata = NULL; } return 0; } |
182ec4eee [JFFS2] Clean up ... |
1155 |
/* |
1da177e4c Linux-2.6.12-rc2 |
1156 1157 |
* We should only get here in the case where the node we are * replacing had more than one frag, so we kept the same version |
182ec4eee [JFFS2] Clean up ... |
1158 |
* number as before. (Except in case of error -- see 'goto fill;' |
1da177e4c Linux-2.6.12-rc2 |
1159 1160 1161 |
* above.) */ D1(if(unlikely(fn->frags <= 1)) { |
da320f055 jffs2: Convert pr... |
1162 1163 1164 1165 |
pr_warn("%s(): Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d ", __func__, fn->frags, je32_to_cpu(ri.version), f->highest_version, je32_to_cpu(ri.ino)); |
1da177e4c Linux-2.6.12-rc2 |
1166 1167 1168 1169 |
}); /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ mark_ref_normal(new_fn->raw); |
182ec4eee [JFFS2] Clean up ... |
1170 |
for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); |
1da177e4c Linux-2.6.12-rc2 |
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 |
frag; frag = frag_next(frag)) { if (frag->ofs > fn->size + fn->ofs) break; if (frag->node == fn) { frag->node = new_fn; new_fn->frags++; fn->frags--; } } if (fn->frags) { |
da320f055 jffs2: Convert pr... |
1181 1182 |
pr_warn("%s(): Old node still has frags! ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
1183 1184 1185 |
BUG(); } if (!new_fn->frags) { |
da320f055 jffs2: Convert pr... |
1186 1187 |
pr_warn("%s(): New node has no frags! ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
1188 1189 |
BUG(); } |
182ec4eee [JFFS2] Clean up ... |
1190 |
|
1da177e4c Linux-2.6.12-rc2 |
1191 1192 |
jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); |
182ec4eee [JFFS2] Clean up ... |
1193 |
|
1da177e4c Linux-2.6.12-rc2 |
1194 1195 |
return 0; } |
25dc30b4c [JFFS2] fix spars... |
1196 |
static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb, |
1da177e4c Linux-2.6.12-rc2 |
1197 1198 1199 1200 1201 |
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end) { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; |
9fe4854cd [JFFS2] Remove fl... |
1202 |
uint32_t alloclen, offset, orig_end, orig_start; |
1da177e4c Linux-2.6.12-rc2 |
1203 1204 1205 1206 |
int ret = 0; unsigned char *comprbuf = NULL, *writebuf; unsigned long pg; unsigned char *pg_ptr; |
182ec4eee [JFFS2] Clean up ... |
1207 |
|
1da177e4c Linux-2.6.12-rc2 |
1208 |
memset(&ri, 0, sizeof(ri)); |
9c261b33a jffs2: Convert mo... |
1209 1210 1211 |
jffs2_dbg(1, "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x ", f->inocache->ino, start, end); |
1da177e4c Linux-2.6.12-rc2 |
1212 1213 1214 1215 1216 1217 1218 |
orig_end = end; orig_start = start; if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { /* Attempt to do some merging. But only expand to cover logically adjacent frags if the block containing them is already considered |
182ec4eee [JFFS2] Clean up ... |
1219 1220 |
to be dirty. Otherwise we end up with GC just going round in circles dirtying the nodes it already wrote out, especially |
1da177e4c Linux-2.6.12-rc2 |
1221 1222 1223 1224 1225 |
on NAND where we have small eraseblocks and hence a much higher chance of nodes having to be split to cross boundaries. */ struct jffs2_node_frag *frag; uint32_t min, max; |
09cbfeaf1 mm, fs: get rid o... |
1226 1227 |
min = start & ~(PAGE_SIZE-1); max = min + PAGE_SIZE; |
1da177e4c Linux-2.6.12-rc2 |
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 |
frag = jffs2_lookup_node_frag(&f->fragtree, start); /* BUG_ON(!frag) but that'll happen anyway... */ BUG_ON(frag->ofs != start); /* First grow down... */ while((frag = frag_prev(frag)) && frag->ofs >= min) { /* If the previous frag doesn't even reach the beginning, there's excessive fragmentation. Just merge. */ if (frag->ofs > min) { |
9c261b33a jffs2: Convert mo... |
1241 1242 1243 |
jffs2_dbg(1, "Expanding down to cover partial frag (0x%x-0x%x) ", frag->ofs, frag->ofs+frag->size); |
1da177e4c Linux-2.6.12-rc2 |
1244 1245 1246 1247 1248 |
start = frag->ofs; continue; } /* OK. This frag holds the first byte of the page. */ if (!frag->node || !frag->node->raw) { |
9c261b33a jffs2: Convert mo... |
1249 1250 1251 |
jffs2_dbg(1, "First frag in page is hole (0x%x-0x%x). Not expanding down. ", frag->ofs, frag->ofs+frag->size); |
1da177e4c Linux-2.6.12-rc2 |
1252 1253 |
break; } else { |
182ec4eee [JFFS2] Clean up ... |
1254 |
/* OK, it's a frag which extends to the beginning of the page. Does it live |
1da177e4c Linux-2.6.12-rc2 |
1255 1256 1257 1258 1259 1260 1261 1262 1263 |
in a block which is still considered clean? If so, don't obsolete it. If not, cover it anyway. */ struct jffs2_raw_node_ref *raw = frag->node->raw; struct jffs2_eraseblock *jeb; jeb = &c->blocks[raw->flash_offset / c->sector_size]; if (jeb == c->gcblock) { |
9c261b33a jffs2: Convert mo... |
1264 1265 1266 1267 1268 |
jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x ", frag->ofs, frag->ofs + frag->size, ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
1269 1270 1271 1272 |
start = frag->ofs; break; } if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { |
9c261b33a jffs2: Convert mo... |
1273 1274 1275 1276 1277 |
jffs2_dbg(1, "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x ", frag->ofs, frag->ofs + frag->size, jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
1278 1279 |
break; } |
9c261b33a jffs2: Convert mo... |
1280 1281 1282 1283 1284 |
jffs2_dbg(1, "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x ", frag->ofs, frag->ofs + frag->size, jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
start = frag->ofs; break; } } /* ... then up */ /* Find last frag which is actually part of the node we're to GC. */ frag = jffs2_lookup_node_frag(&f->fragtree, end-1); while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { /* If the previous frag doesn't even reach the beginning, there's lots of fragmentation. Just merge. */ if (frag->ofs+frag->size < max) { |
9c261b33a jffs2: Convert mo... |
1300 1301 1302 |
jffs2_dbg(1, "Expanding up to cover partial frag (0x%x-0x%x) ", frag->ofs, frag->ofs+frag->size); |
1da177e4c Linux-2.6.12-rc2 |
1303 1304 1305 1306 1307 |
end = frag->ofs + frag->size; continue; } if (!frag->node || !frag->node->raw) { |
9c261b33a jffs2: Convert mo... |
1308 1309 1310 |
jffs2_dbg(1, "Last frag in page is hole (0x%x-0x%x). Not expanding up. ", frag->ofs, frag->ofs+frag->size); |
1da177e4c Linux-2.6.12-rc2 |
1311 1312 |
break; } else { |
182ec4eee [JFFS2] Clean up ... |
1313 |
/* OK, it's a frag which extends to the beginning of the page. Does it live |
1da177e4c Linux-2.6.12-rc2 |
1314 1315 1316 1317 1318 1319 1320 1321 1322 |
in a block which is still considered clean? If so, don't obsolete it. If not, cover it anyway. */ struct jffs2_raw_node_ref *raw = frag->node->raw; struct jffs2_eraseblock *jeb; jeb = &c->blocks[raw->flash_offset / c->sector_size]; if (jeb == c->gcblock) { |
9c261b33a jffs2: Convert mo... |
1323 1324 1325 1326 1327 |
jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x ", frag->ofs, frag->ofs + frag->size, ref_offset(raw)); |
1da177e4c Linux-2.6.12-rc2 |
1328 1329 1330 1331 |
end = frag->ofs + frag->size; break; } if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { |
9c261b33a jffs2: Convert mo... |
1332 1333 1334 1335 1336 |
jffs2_dbg(1, "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x ", frag->ofs, frag->ofs + frag->size, jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
1337 1338 |
break; } |
9c261b33a jffs2: Convert mo... |
1339 1340 1341 1342 1343 |
jffs2_dbg(1, "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x ", frag->ofs, frag->ofs + frag->size, jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
1344 1345 1346 1347 |
end = frag->ofs + frag->size; break; } } |
9c261b33a jffs2: Convert mo... |
1348 1349 1350 |
jffs2_dbg(1, "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x) ", orig_start, orig_end, start, end); |
1da177e4c Linux-2.6.12-rc2 |
1351 |
|
8557fd51c [JFFS2] Fix race ... |
1352 |
D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); |
1da177e4c Linux-2.6.12-rc2 |
1353 1354 1355 |
BUG_ON(end < orig_end); BUG_ON(start > orig_start); } |
182ec4eee [JFFS2] Clean up ... |
1356 |
|
49e91e707 jffs2: Fix page l... |
1357 1358 1359 1360 1361 1362 1363 1364 1365 |
/* The rules state that we must obtain the page lock *before* f->sem, so * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's * actually going to *change* so we're safe; we only allow reading. * * It is important to note that jffs2_write_begin() will ensure that its * page is marked Uptodate before allocating space. That means that if we * end up here trying to GC the *same* page that jffs2_write_begin() is * trying to write out, read_cache_page() will not deadlock. */ mutex_unlock(&f->sem); |
1da177e4c Linux-2.6.12-rc2 |
1366 |
pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); |
49e91e707 jffs2: Fix page l... |
1367 |
mutex_lock(&f->sem); |
1da177e4c Linux-2.6.12-rc2 |
1368 1369 |
if (IS_ERR(pg_ptr)) { |
da320f055 jffs2: Convert pr... |
1370 1371 1372 |
pr_warn("read_cache_page() returned error: %ld ", PTR_ERR(pg_ptr)); |
1da177e4c Linux-2.6.12-rc2 |
1373 1374 1375 1376 1377 1378 1379 1380 |
return PTR_ERR(pg_ptr); } offset = start; while(offset < orig_end) { uint32_t datalen; uint32_t cdatalen; uint16_t comprtype = JFFS2_COMPR_NONE; |
9fe4854cd [JFFS2] Remove fl... |
1381 |
ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, |
e631ddba5 [JFFS2] Add erase... |
1382 |
&alloclen, JFFS2_SUMMARY_INODE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
1383 1384 |
if (ret) { |
da320f055 jffs2: Convert pr... |
1385 1386 1387 |
pr_warn("jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d ", sizeof(ri) + JFFS2_MIN_DATA_LEN, ret); |
1da177e4c Linux-2.6.12-rc2 |
1388 1389 1390 1391 |
break; } cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); datalen = end - offset; |
09cbfeaf1 mm, fs: get rid o... |
1392 |
writebuf = pg_ptr + (offset & (PAGE_SIZE -1)); |
1da177e4c Linux-2.6.12-rc2 |
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 |
comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); ri.offset = cpu_to_je32(offset); ri.csize = cpu_to_je32(cdatalen); ri.dsize = cpu_to_je32(datalen); ri.compr = comprtype & 0xff; ri.usercompr = (comprtype >> 8) & 0xff; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); |
182ec4eee [JFFS2] Clean up ... |
1417 |
|
9fe4854cd [JFFS2] Remove fl... |
1418 |
new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, ALLOC_GC); |
1da177e4c Linux-2.6.12-rc2 |
1419 1420 1421 1422 |
jffs2_free_comprbuf(comprbuf, writebuf); if (IS_ERR(new_fn)) { |
da320f055 jffs2: Convert pr... |
1423 1424 1425 |
pr_warn("Error writing new dnode: %ld ", PTR_ERR(new_fn)); |
1da177e4c Linux-2.6.12-rc2 |
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 |
ret = PTR_ERR(new_fn); break; } ret = jffs2_add_full_dnode_to_inode(c, f, new_fn); offset += datalen; if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); f->metadata = NULL; } } jffs2_gc_release_page(c, pg_ptr, &pg); return ret; } |