diff options
author | Artem B. Bityutskiy <dedekind@infradead.org> | 2005-07-27 10:46:14 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-11-06 11:50:45 -0500 |
commit | f97117d15361b3a6aeaf9e347a287ef3f54b58f9 (patch) | |
tree | 614ff5f6fa693e1e475430eff9687e40b96b8555 /fs/jffs2/nodelist.c | |
parent | f538c96ba2a3fdf7744ecf9fdffac14b1ec4be32 (diff) |
[JFFS2] Move scattered function into related files
Move functions to read inodes into readinode.c
Move functions to handle fragtree and dentry lists into nodelist.[ch]
Signed-off-by: Artem B. Bityutskiy <dedekind@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2/nodelist.c')
-rw-r--r-- | fs/jffs2/nodelist.c | 717 |
1 files changed, 230 insertions, 487 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 9d08d3388186..8373d312b195 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.c,v 1.100 2005/07/22 10:32:08 dedekind Exp $ | 10 | * $Id: nodelist.c,v 1.101 2005/07/27 14:46:11 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -55,515 +55,284 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
55 | }); | 55 | }); |
56 | } | 56 | } |
57 | 57 | ||
58 | /* | 58 | void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) |
59 | * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in | ||
60 | * order of increasing version. | ||
61 | */ | ||
62 | static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | ||
63 | { | 59 | { |
64 | struct rb_node **p = &list->rb_node; | 60 | if (this->node) { |
65 | struct rb_node * parent = NULL; | 61 | this->node->frags--; |
66 | struct jffs2_tmp_dnode_info *this; | 62 | if (!this->node->frags) { |
67 | 63 | /* The node has no valid frags left. It's totally obsoleted */ | |
68 | while (*p) { | 64 | D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", |
69 | parent = *p; | 65 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); |
70 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); | 66 | jffs2_mark_node_obsolete(c, this->node->raw); |
71 | 67 | jffs2_free_full_dnode(this->node); | |
72 | /* There may actually be a collision here, but it doesn't | 68 | } else { |
73 | actually matter. As long as the two nodes with the same | 69 | D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", |
74 | version are together, it's all fine. */ | 70 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, |
75 | if (tn->version < this->version) | 71 | this->node->frags)); |
76 | p = &(*p)->rb_left; | 72 | mark_ref_normal(this->node->raw); |
77 | else | 73 | } |
78 | p = &(*p)->rb_right; | 74 | |
79 | } | 75 | } |
80 | 76 | jffs2_free_node_frag(this); | |
81 | rb_link_node(&tn->rb, parent, p); | ||
82 | rb_insert_color(&tn->rb, list); | ||
83 | } | 77 | } |
84 | 78 | ||
85 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) | 79 | static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) |
86 | { | 80 | { |
87 | struct rb_node *this; | 81 | struct rb_node *parent = &base->rb; |
88 | struct jffs2_tmp_dnode_info *tn; | 82 | struct rb_node **link = &parent; |
89 | 83 | ||
90 | this = list->rb_node; | 84 | D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, |
85 | newfrag->ofs, newfrag->ofs+newfrag->size, base)); | ||
91 | 86 | ||
92 | /* Now at bottom of tree */ | 87 | while (*link) { |
93 | while (this) { | 88 | parent = *link; |
94 | if (this->rb_left) | 89 | base = rb_entry(parent, struct jffs2_node_frag, rb); |
95 | this = this->rb_left; | 90 | |
96 | else if (this->rb_right) | 91 | D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); |
97 | this = this->rb_right; | 92 | if (newfrag->ofs > base->ofs) |
93 | link = &base->rb.rb_right; | ||
94 | else if (newfrag->ofs < base->ofs) | ||
95 | link = &base->rb.rb_left; | ||
98 | else { | 96 | else { |
99 | tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); | 97 | printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); |
100 | jffs2_free_full_dnode(tn->fn); | 98 | BUG(); |
101 | jffs2_free_tmp_dnode_info(tn); | ||
102 | |||
103 | this = this->rb_parent; | ||
104 | if (!this) | ||
105 | break; | ||
106 | |||
107 | if (this->rb_left == &tn->rb) | ||
108 | this->rb_left = NULL; | ||
109 | else if (this->rb_right == &tn->rb) | ||
110 | this->rb_right = NULL; | ||
111 | else BUG(); | ||
112 | } | 99 | } |
113 | } | 100 | } |
114 | list->rb_node = NULL; | 101 | |
102 | rb_link_node(&newfrag->rb, &base->rb, link); | ||
115 | } | 103 | } |
116 | 104 | ||
117 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) | 105 | /* Doesn't set inode->i_size */ |
106 | static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) | ||
118 | { | 107 | { |
119 | struct jffs2_full_dirent *next; | 108 | struct jffs2_node_frag *this; |
109 | uint32_t lastend; | ||
120 | 110 | ||
121 | while (fd) { | 111 | /* Skip all the nodes which are completed before this one starts */ |
122 | next = fd->next; | 112 | this = jffs2_lookup_node_frag(list, newfrag->node->ofs); |
123 | jffs2_free_full_dirent(fd); | ||
124 | fd = next; | ||
125 | } | ||
126 | } | ||
127 | 113 | ||
128 | /* Returns first valid node after 'ref'. May return 'ref' */ | 114 | if (this) { |
129 | static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) | 115 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", |
130 | { | 116 | this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); |
131 | while (ref && ref->next_in_ino) { | 117 | lastend = this->ofs + this->size; |
132 | if (!ref_obsolete(ref)) | 118 | } else { |
133 | return ref; | 119 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); |
134 | D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); | 120 | lastend = 0; |
135 | ref = ref->next_in_ino; | ||
136 | } | 121 | } |
137 | return NULL; | 122 | |
138 | } | 123 | /* See if we ran off the end of the list */ |
124 | if (lastend <= newfrag->ofs) { | ||
125 | /* We did */ | ||
126 | |||
127 | /* Check if 'this' node was on the same page as the new node. | ||
128 | If so, both 'this' and the new node get marked REF_NORMAL so | ||
129 | the GC can take a look. | ||
130 | */ | ||
131 | if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { | ||
132 | if (this->node) | ||
133 | mark_ref_normal(this->node->raw); | ||
134 | mark_ref_normal(newfrag->node->raw); | ||
135 | } | ||
139 | 136 | ||
140 | /* | 137 | if (lastend < newfrag->node->ofs) { |
141 | * Helper function for jffs2_get_inode_nodes(). | 138 | /* ... and we need to put a hole in before the new node */ |
142 | * It is called every time an directory entry node is found. | 139 | struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); |
143 | * | 140 | if (!holefrag) { |
144 | * Returns: 0 on succes; | 141 | jffs2_free_node_frag(newfrag); |
145 | * 1 if the node should be marked obsolete; | 142 | return -ENOMEM; |
146 | * negative error code on failure. | 143 | } |
147 | */ | 144 | holefrag->ofs = lastend; |
148 | static inline int | 145 | holefrag->size = newfrag->node->ofs - lastend; |
149 | read_direntry(struct jffs2_sb_info *c, | 146 | holefrag->node = NULL; |
150 | struct jffs2_raw_node_ref *ref, | 147 | if (this) { |
151 | struct jffs2_raw_dirent *rd, | 148 | /* By definition, the 'this' node has no right-hand child, |
152 | uint32_t read, | 149 | because there are no frags with offset greater than it. |
153 | struct jffs2_full_dirent **fdp, | 150 | So that's where we want to put the hole */ |
154 | int32_t *latest_mctime, | 151 | D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); |
155 | uint32_t *mctime_ver) | 152 | rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); |
156 | { | 153 | } else { |
157 | struct jffs2_full_dirent *fd; | 154 | D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); |
158 | 155 | rb_link_node(&holefrag->rb, NULL, &list->rb_node); | |
159 | /* The direntry nodes are checked during the flash scanning */ | 156 | } |
160 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); | 157 | rb_insert_color(&holefrag->rb, list); |
161 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | 158 | this = holefrag; |
162 | BUG_ON(ref_obsolete(ref)); | 159 | } |
163 | 160 | if (this) { | |
164 | /* Sanity check */ | 161 | /* By definition, the 'this' node has no right-hand child, |
165 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { | 162 | because there are no frags with offset greater than it. |
166 | printk(KERN_ERR "Error! Illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", | 163 | So that's where we want to put new fragment */ |
167 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); | 164 | D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); |
168 | return 1; | 165 | rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); |
166 | } else { | ||
167 | D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); | ||
168 | rb_link_node(&newfrag->rb, NULL, &list->rb_node); | ||
169 | } | ||
170 | rb_insert_color(&newfrag->rb, list); | ||
171 | return 0; | ||
169 | } | 172 | } |
170 | |||
171 | fd = jffs2_alloc_full_dirent(rd->nsize + 1); | ||
172 | if (unlikely(!fd)) | ||
173 | return -ENOMEM; | ||
174 | |||
175 | fd->raw = ref; | ||
176 | fd->version = je32_to_cpu(rd->version); | ||
177 | fd->ino = je32_to_cpu(rd->ino); | ||
178 | fd->type = rd->type; | ||
179 | 173 | ||
180 | /* Pick out the mctime of the latest dirent */ | 174 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", |
181 | if(fd->version > *mctime_ver) { | 175 | this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); |
182 | *mctime_ver = fd->version; | ||
183 | *latest_mctime = je32_to_cpu(rd->mctime); | ||
184 | } | ||
185 | 176 | ||
186 | /* | 177 | /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, |
187 | * Copy as much of the name as possible from the raw | 178 | * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs |
188 | * dirent we've already read from the flash. | ||
189 | */ | 179 | */ |
190 | if (read > sizeof(*rd)) | 180 | if (newfrag->ofs > this->ofs) { |
191 | memcpy(&fd->name[0], &rd->name[0], | 181 | /* This node isn't completely obsoleted. The start of it remains valid */ |
192 | min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); | 182 | |
193 | 183 | /* Mark the new node and the partially covered node REF_NORMAL -- let | |
194 | /* Do we need to copy any more of the name directly from the flash? */ | 184 | the GC take a look at them */ |
195 | if (rd->nsize + sizeof(*rd) > read) { | 185 | mark_ref_normal(newfrag->node->raw); |
196 | /* FIXME: point() */ | 186 | if (this->node) |
197 | int err; | 187 | mark_ref_normal(this->node->raw); |
198 | int already = read - sizeof(*rd); | 188 | |
189 | if (this->ofs + this->size > newfrag->ofs + newfrag->size) { | ||
190 | /* The new node splits 'this' frag into two */ | ||
191 | struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); | ||
192 | if (!newfrag2) { | ||
193 | jffs2_free_node_frag(newfrag); | ||
194 | return -ENOMEM; | ||
195 | } | ||
196 | D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); | ||
197 | if (this->node) | ||
198 | printk("phys 0x%08x\n", ref_offset(this->node->raw)); | ||
199 | else | ||
200 | printk("hole\n"); | ||
201 | ) | ||
202 | |||
203 | /* New second frag pointing to this's node */ | ||
204 | newfrag2->ofs = newfrag->ofs + newfrag->size; | ||
205 | newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; | ||
206 | newfrag2->node = this->node; | ||
207 | if (this->node) | ||
208 | this->node->frags++; | ||
209 | |||
210 | /* Adjust size of original 'this' */ | ||
211 | this->size = newfrag->ofs - this->ofs; | ||
212 | |||
213 | /* Now, we know there's no node with offset | ||
214 | greater than this->ofs but smaller than | ||
215 | newfrag2->ofs or newfrag->ofs, for obvious | ||
216 | reasons. So we can do a tree insert from | ||
217 | 'this' to insert newfrag, and a tree insert | ||
218 | from newfrag to insert newfrag2. */ | ||
219 | jffs2_fragtree_insert(newfrag, this); | ||
220 | rb_insert_color(&newfrag->rb, list); | ||
199 | 221 | ||
200 | err = jffs2_flash_read(c, (ref_offset(ref)) + read, | 222 | jffs2_fragtree_insert(newfrag2, newfrag); |
201 | rd->nsize - already, &read, &fd->name[already]); | 223 | rb_insert_color(&newfrag2->rb, list); |
202 | if (unlikely(read != rd->nsize - already) && likely(!err)) | ||
203 | return -EIO; | ||
204 | 224 | ||
205 | if (unlikely(err)) { | 225 | return 0; |
206 | printk(KERN_WARNING "Read remainder of name: error %d\n", err); | ||
207 | jffs2_free_full_dirent(fd); | ||
208 | return -EIO; | ||
209 | } | 226 | } |
210 | } | 227 | /* New node just reduces 'this' frag in size, doesn't split it */ |
211 | 228 | this->size = newfrag->ofs - this->ofs; | |
212 | fd->nhash = full_name_hash(fd->name, rd->nsize); | ||
213 | fd->next = NULL; | ||
214 | fd->name[rd->nsize] = '\0'; | ||
215 | |||
216 | /* | ||
217 | * Wheee. We now have a complete jffs2_full_dirent structure, with | ||
218 | * the name in it and everything. Link it into the list | ||
219 | */ | ||
220 | D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino)); | ||
221 | |||
222 | jffs2_add_fd_to_list(c, fd, fdp); | ||
223 | 229 | ||
224 | return 0; | 230 | /* Again, we know it lives down here in the tree */ |
225 | } | 231 | jffs2_fragtree_insert(newfrag, this); |
226 | 232 | rb_insert_color(&newfrag->rb, list); | |
227 | /* | 233 | } else { |
228 | * Helper function for jffs2_get_inode_nodes(). | 234 | /* New frag starts at the same point as 'this' used to. Replace |
229 | * It is called every time an inode node is found. | 235 | it in the tree without doing a delete and insertion */ |
230 | * | 236 | D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", |
231 | * Returns: 0 on succes; | 237 | newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, |
232 | * 1 if the node should be marked obsolete; | 238 | this, this->ofs, this->ofs+this->size)); |
233 | * negative error code on failure. | ||
234 | */ | ||
235 | static inline int | ||
236 | read_dnode(struct jffs2_sb_info *c, | ||
237 | struct jffs2_raw_node_ref *ref, | ||
238 | struct jffs2_raw_inode *rd, | ||
239 | uint32_t read, | ||
240 | struct rb_root *tnp, | ||
241 | int32_t *latest_mctime, | ||
242 | uint32_t *mctime_ver) | ||
243 | { | ||
244 | struct jffs2_eraseblock *jeb; | ||
245 | struct jffs2_tmp_dnode_info *tn; | ||
246 | 239 | ||
247 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | 240 | rb_replace_node(&this->rb, &newfrag->rb, list); |
248 | BUG_ON(ref_obsolete(ref)); | ||
249 | |||
250 | /* If we've never checked the CRCs on this node, check them now */ | ||
251 | if (ref_flags(ref) == REF_UNCHECKED) { | ||
252 | uint32_t crc, len; | ||
253 | |||
254 | crc = crc32(0, rd, sizeof(*rd) - 8); | ||
255 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { | ||
256 | printk(KERN_WARNING "Header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", | ||
257 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); | ||
258 | return 1; | ||
259 | } | ||
260 | 241 | ||
261 | /* Sanity checks */ | 242 | if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { |
262 | if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || | 243 | D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); |
263 | unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) { | 244 | jffs2_obsolete_node_frag(c, this); |
264 | printk(KERN_WARNING "Inode corrupted at %#08x, totlen %d, #ino %d, version %d, " | ||
265 | "isize %d, csize %d, dsize %d \n", | ||
266 | ref_offset(ref), je32_to_cpu(rd->totlen), je32_to_cpu(rd->ino), | ||
267 | je32_to_cpu(rd->version), je32_to_cpu(rd->isize), | ||
268 | je32_to_cpu(rd->csize), je32_to_cpu(rd->dsize)); | ||
269 | return 1; | ||
270 | } | ||
271 | |||
272 | if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) { | ||
273 | unsigned char *buf = NULL; | ||
274 | uint32_t pointed = 0; | ||
275 | int err; | ||
276 | #ifndef __ECOS | ||
277 | if (c->mtd->point) { | ||
278 | err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), | ||
279 | &read, &buf); | ||
280 | if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) { | ||
281 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", read)); | ||
282 | c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), | ||
283 | je32_to_cpu(rd->csize)); | ||
284 | } else if (unlikely(err)){ | ||
285 | D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); | ||
286 | } else | ||
287 | pointed = 1; /* succefully pointed to device */ | ||
288 | } | ||
289 | #endif | ||
290 | if(!pointed){ | ||
291 | buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL); | ||
292 | if (!buf) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), | ||
296 | &read, buf); | ||
297 | if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err)) | ||
298 | err = -EIO; | ||
299 | if (err) { | ||
300 | kfree(buf); | ||
301 | return err; | ||
302 | } | ||
303 | } | ||
304 | crc = crc32(0, buf, je32_to_cpu(rd->csize)); | ||
305 | if(!pointed) | ||
306 | kfree(buf); | ||
307 | #ifndef __ECOS | ||
308 | else | ||
309 | c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize)); | ||
310 | #endif | ||
311 | |||
312 | if (crc != je32_to_cpu(rd->data_crc)) { | ||
313 | printk(KERN_NOTICE "Data CRC failed on node at %#08x: read %#08x, calculated %#08x\n", | ||
314 | ref_offset(ref), je32_to_cpu(rd->data_crc), crc); | ||
315 | return 1; | ||
316 | } | ||
317 | |||
318 | } | ||
319 | |||
320 | /* Mark the node as having been checked and fix the accounting accordingly */ | ||
321 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
322 | len = ref_totlen(c, jeb, ref); | ||
323 | |||
324 | spin_lock(&c->erase_completion_lock); | ||
325 | jeb->used_size += len; | ||
326 | jeb->unchecked_size -= len; | ||
327 | c->used_size += len; | ||
328 | c->unchecked_size -= len; | ||
329 | |||
330 | /* If node covers at least a whole page, or if it starts at the | ||
331 | beginning of a page and runs to the end of the file, or if | ||
332 | it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. | ||
333 | |||
334 | If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) | ||
335 | when the overlapping node(s) get added to the tree anyway. | ||
336 | */ | ||
337 | if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) || | ||
338 | ( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) && | ||
339 | (je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) { | ||
340 | D1(printk(KERN_DEBUG "Marking node at %#08x REF_PRISTINE\n", ref_offset(ref))); | ||
341 | ref->flash_offset = ref_offset(ref) | REF_PRISTINE; | ||
342 | } else { | 245 | } else { |
343 | D1(printk(KERN_DEBUG "Marking node at %#08x REF_NORMAL\n", ref_offset(ref))); | 246 | this->ofs += newfrag->size; |
344 | ref->flash_offset = ref_offset(ref) | REF_NORMAL; | 247 | this->size -= newfrag->size; |
248 | |||
249 | jffs2_fragtree_insert(this, newfrag); | ||
250 | rb_insert_color(&this->rb, list); | ||
251 | return 0; | ||
345 | } | 252 | } |
346 | spin_unlock(&c->erase_completion_lock); | ||
347 | } | 253 | } |
348 | 254 | /* OK, now we have newfrag added in the correct place in the tree, but | |
349 | tn = jffs2_alloc_tmp_dnode_info(); | 255 | frag_next(newfrag) may be a fragment which is overlapped by it |
350 | if (!tn) { | 256 | */ |
351 | D1(printk(KERN_DEBUG "alloc tn failed\n")); | 257 | while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { |
352 | return -ENOMEM; | 258 | /* 'this' frag is obsoleted completely. */ |
259 | D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); | ||
260 | rb_erase(&this->rb, list); | ||
261 | jffs2_obsolete_node_frag(c, this); | ||
353 | } | 262 | } |
263 | /* Now we're pointing at the first frag which isn't totally obsoleted by | ||
264 | the new frag */ | ||
354 | 265 | ||
355 | tn->fn = jffs2_alloc_full_dnode(); | 266 | if (!this || newfrag->ofs + newfrag->size == this->ofs) { |
356 | if (!tn->fn) { | 267 | return 0; |
357 | D1(printk(KERN_DEBUG "alloc fn failed\n")); | ||
358 | jffs2_free_tmp_dnode_info(tn); | ||
359 | return -ENOMEM; | ||
360 | } | 268 | } |
361 | 269 | /* Still some overlap but we don't need to move it in the tree */ | |
362 | tn->version = je32_to_cpu(rd->version); | 270 | this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); |
363 | tn->fn->ofs = je32_to_cpu(rd->offset); | 271 | this->ofs = newfrag->ofs + newfrag->size; |
364 | tn->fn->raw = ref; | 272 | |
365 | 273 | /* And mark them REF_NORMAL so the GC takes a look at them */ | |
366 | /* There was a bug where we wrote hole nodes out with | 274 | if (this->node) |
367 | csize/dsize swapped. Deal with it */ | 275 | mark_ref_normal(this->node->raw); |
368 | if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && je32_to_cpu(rd->csize)) | 276 | mark_ref_normal(newfrag->node->raw); |
369 | tn->fn->size = je32_to_cpu(rd->csize); | ||
370 | else // normal case... | ||
371 | tn->fn->size = je32_to_cpu(rd->dsize); | ||
372 | |||
373 | D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %#04x, dsize %#04x\n", | ||
374 | ref_offset(ref), je32_to_cpu(rd->version), | ||
375 | je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize))); | ||
376 | |||
377 | jffs2_add_tn_to_tree(tn, tnp); | ||
378 | 277 | ||
379 | return 0; | 278 | return 0; |
380 | } | 279 | } |
381 | 280 | ||
382 | /* | 281 | /* Given an inode, probably with existing list of fragments, add the new node |
383 | * Helper function for jffs2_get_inode_nodes(). | 282 | * to the fragment list. |
384 | * It is called every time an unknown node is found. | ||
385 | * | ||
386 | * Returns: 0 on succes; | ||
387 | * 1 if the node should be marked obsolete; | ||
388 | * negative error code on failure. | ||
389 | */ | 283 | */ |
390 | static inline int | 284 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) |
391 | read_unknown(struct jffs2_sb_info *c, | ||
392 | struct jffs2_raw_node_ref *ref, | ||
393 | struct jffs2_unknown_node *un, | ||
394 | uint32_t read) | ||
395 | { | 285 | { |
396 | /* We don't mark unknown nodes as REF_UNCHECKED */ | 286 | int ret; |
397 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); | 287 | struct jffs2_node_frag *newfrag; |
398 | |||
399 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); | ||
400 | 288 | ||
401 | if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { | 289 | D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); |
402 | 290 | ||
403 | /* Hmmm. This should have been caught at scan time. */ | 291 | if (unlikely(!fn->size)) |
404 | printk(KERN_WARNING "Warning! Node header CRC failed at %#08x. " | 292 | return 0; |
405 | "But it must have been OK earlier.\n", ref_offset(ref)); | ||
406 | D1(printk(KERN_DEBUG "Node was: { %#04x, %#04x, %#08x, %#08x }\n", | ||
407 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), | ||
408 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc))); | ||
409 | return 1; | ||
410 | } else { | ||
411 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { | ||
412 | 293 | ||
413 | case JFFS2_FEATURE_INCOMPAT: | 294 | newfrag = jffs2_alloc_node_frag(); |
414 | printk(KERN_NOTICE "Unknown INCOMPAT nodetype %#04X at %#08x\n", | 295 | if (unlikely(!newfrag)) |
415 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 296 | return -ENOMEM; |
416 | /* EEP */ | ||
417 | BUG(); | ||
418 | break; | ||
419 | |||
420 | case JFFS2_FEATURE_ROCOMPAT: | ||
421 | printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %#04X at %#08x\n", | ||
422 | je16_to_cpu(un->nodetype), ref_offset(ref)); | ||
423 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); | ||
424 | break; | ||
425 | |||
426 | case JFFS2_FEATURE_RWCOMPAT_COPY: | ||
427 | printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", | ||
428 | je16_to_cpu(un->nodetype), ref_offset(ref)); | ||
429 | break; | ||
430 | |||
431 | case JFFS2_FEATURE_RWCOMPAT_DELETE: | ||
432 | printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", | ||
433 | je16_to_cpu(un->nodetype), ref_offset(ref)); | ||
434 | return 1; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated | ||
442 | with this ino, returning the former in order of version */ | ||
443 | 297 | ||
444 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 298 | D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", |
445 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, | 299 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); |
446 | uint32_t *highest_version, uint32_t *latest_mctime, | ||
447 | uint32_t *mctime_ver) | ||
448 | { | ||
449 | struct jffs2_raw_node_ref *ref, *valid_ref; | ||
450 | struct rb_root ret_tn = RB_ROOT; | ||
451 | struct jffs2_full_dirent *ret_fd = NULL; | ||
452 | union jffs2_node_union node; | ||
453 | size_t retlen; | ||
454 | int err; | ||
455 | |||
456 | *mctime_ver = 0; | ||
457 | 300 | ||
458 | D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino)); | 301 | newfrag->ofs = fn->ofs; |
459 | 302 | newfrag->size = fn->size; | |
460 | spin_lock(&c->erase_completion_lock); | 303 | newfrag->node = fn; |
461 | 304 | newfrag->node->frags = 1; | |
462 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); | 305 | |
463 | 306 | ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); | |
464 | if (!valid_ref && (f->inocache->ino != 1)) | 307 | if (unlikely(ret)) |
465 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); | 308 | return ret; |
466 | 309 | ||
467 | while (valid_ref) { | 310 | /* If we now share a page with other nodes, mark either previous |
468 | /* We can hold a pointer to a non-obsolete node without the spinlock, | 311 | or next node REF_NORMAL, as appropriate. */ |
469 | but _obsolete_ nodes may disappear at any time, if the block | 312 | if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { |
470 | they're in gets erased. So if we mark 'ref' obsolete while we're | 313 | struct jffs2_node_frag *prev = frag_prev(newfrag); |
471 | not holding the lock, it can go away immediately. For that reason, | 314 | |
472 | we find the next valid node first, before processing 'ref'. | 315 | mark_ref_normal(fn->raw); |
473 | */ | 316 | /* If we don't start at zero there's _always_ a previous */ |
474 | ref = valid_ref; | 317 | if (prev->node) |
475 | valid_ref = jffs2_first_valid_node(ref->next_in_ino); | 318 | mark_ref_normal(prev->node->raw); |
476 | spin_unlock(&c->erase_completion_lock); | 319 | } |
477 | |||
478 | cond_resched(); | ||
479 | |||
480 | /* FIXME: point() */ | ||
481 | err = jffs2_flash_read(c, (ref_offset(ref)), | ||
482 | min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), | ||
483 | &retlen, (void *)&node); | ||
484 | if (err) { | ||
485 | printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); | ||
486 | goto free_out; | ||
487 | } | ||
488 | |||
489 | switch (je16_to_cpu(node.u.nodetype)) { | ||
490 | |||
491 | case JFFS2_NODETYPE_DIRENT: | ||
492 | D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); | ||
493 | |||
494 | if (retlen < sizeof(node.d)) { | ||
495 | printk(KERN_WARNING "Warning! Short read dirent at %#08x\n", ref_offset(ref)); | ||
496 | err = -EIO; | ||
497 | goto free_out; | ||
498 | } | ||
499 | |||
500 | err = read_direntry(c, ref, &node.d, retlen, &ret_fd, latest_mctime, mctime_ver); | ||
501 | if (err == 1) { | ||
502 | jffs2_mark_node_obsolete(c, ref); | ||
503 | break; | ||
504 | } else if (unlikely(err)) | ||
505 | goto free_out; | ||
506 | |||
507 | if (je32_to_cpu(node.d.version) > *highest_version) | ||
508 | *highest_version = je32_to_cpu(node.d.version); | ||
509 | |||
510 | break; | ||
511 | |||
512 | case JFFS2_NODETYPE_INODE: | ||
513 | D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); | ||
514 | |||
515 | if (retlen < sizeof(node.i)) { | ||
516 | printk(KERN_WARNING "Warning! Short read dnode at %#08x\n", ref_offset(ref)); | ||
517 | err = -EIO; | ||
518 | goto free_out; | ||
519 | } | ||
520 | |||
521 | err = read_dnode(c, ref, &node.i, retlen, &ret_tn, latest_mctime, mctime_ver); | ||
522 | if (err == 1) { | ||
523 | jffs2_mark_node_obsolete(c, ref); | ||
524 | break; | ||
525 | } else if (unlikely(err)) | ||
526 | goto free_out; | ||
527 | |||
528 | if (je32_to_cpu(node.i.version) > *highest_version) | ||
529 | *highest_version = je32_to_cpu(node.i.version); | ||
530 | |||
531 | D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", | ||
532 | je32_to_cpu(node.i.version), *highest_version)); | ||
533 | |||
534 | break; | ||
535 | |||
536 | default: | ||
537 | /* Check we've managed to read at least the common node header */ | ||
538 | if (retlen < sizeof(struct jffs2_unknown_node)) { | ||
539 | printk(KERN_WARNING "Warning! Short read unknown node at %#08x\n", | ||
540 | ref_offset(ref)); | ||
541 | return -EIO; | ||
542 | } | ||
543 | |||
544 | err = read_unknown(c, ref, &node.u, retlen); | ||
545 | if (err == 1) { | ||
546 | jffs2_mark_node_obsolete(c, ref); | ||
547 | break; | ||
548 | } else if (unlikely(err)) | ||
549 | goto free_out; | ||
550 | 320 | ||
321 | if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { | ||
322 | struct jffs2_node_frag *next = frag_next(newfrag); | ||
323 | |||
324 | if (next) { | ||
325 | mark_ref_normal(fn->raw); | ||
326 | if (next->node) | ||
327 | mark_ref_normal(next->node->raw); | ||
551 | } | 328 | } |
552 | spin_lock(&c->erase_completion_lock); | ||
553 | |||
554 | } | 329 | } |
555 | spin_unlock(&c->erase_completion_lock); | 330 | jffs2_dbg_fragtree_paranoia_check_nolock(f); |
556 | *tnp = ret_tn; | 331 | jffs2_dbg_dump_fragtree_nolock(f); |
557 | *fdp = ret_fd; | ||
558 | |||
559 | return 0; | 332 | return 0; |
560 | |||
561 | free_out: | ||
562 | jffs2_free_tmp_dnode_info_list(&ret_tn); | ||
563 | jffs2_free_full_dirent_list(ret_fd); | ||
564 | return err; | ||
565 | } | 333 | } |
566 | 334 | ||
335 | |||
567 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) | 336 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) |
568 | { | 337 | { |
569 | spin_lock(&c->inocache_lock); | 338 | spin_lock(&c->inocache_lock); |
@@ -773,29 +542,3 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) | |||
773 | cond_resched(); | 542 | cond_resched(); |
774 | } | 543 | } |
775 | } | 544 | } |
776 | |||
777 | void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) | ||
778 | { | ||
779 | struct rb_node *parent = &base->rb; | ||
780 | struct rb_node **link = &parent; | ||
781 | |||
782 | D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, | ||
783 | newfrag->ofs, newfrag->ofs+newfrag->size, base)); | ||
784 | |||
785 | while (*link) { | ||
786 | parent = *link; | ||
787 | base = rb_entry(parent, struct jffs2_node_frag, rb); | ||
788 | |||
789 | D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); | ||
790 | if (newfrag->ofs > base->ofs) | ||
791 | link = &base->rb.rb_right; | ||
792 | else if (newfrag->ofs < base->ofs) | ||
793 | link = &base->rb.rb_left; | ||
794 | else { | ||
795 | printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); | ||
796 | BUG(); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | rb_link_node(&newfrag->rb, &base->rb, link); | ||
801 | } | ||