aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/nodelist.h
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-04-24 22:23:42 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-24 22:23:42 -0400
commitdf8e96f39103adf5a13332d784040a2c62667243 (patch)
tree01d7259260f628f4075c39c1cc7804b72998a601 /fs/jffs2/nodelist.h
parent44b998e1eb254edc87177819ee693690fac68b7f (diff)
[JFFS2] Improve read_inode memory usage, v2.
We originally used to read every node and allocate a jffs2_tmp_dnode_info structure for each, before processing them in (reverse) version order and discarding the ones which are obsoleted by later nodes. With huge logfiles, this behaviour caused memory problems. For example, a file involved in OLPC trac #1292 has 1822391 nodes, and would cause the XO machine to run out of memory during the first stage of read_inode(). Instead of just inserting nodes into a tree in version order as we find them, we now put them into a tree in order of their offset within the file, which allows us to immediately discard nodes which are completely obsoleted. We don't use a full tree with 'fragments' pointing to the real data structure, as we do in the normal fragtree. We sort only on the start address, and add an 'overlapped' flag to the tmp_dnode_info to indicate that the node in question is (partially) overlapped by another. When the scan is complete, we start at the end of the file, adding each node to a real fragtree as before. Where the node is non-overlapped, we just add it (it doesn't matter that it's not the latest version; there is no overlap). When the node at the end of the tree _is_ overlapped, we sort it and all its overlapping nodes into version order and then add them to the fragtree in that order. This 'early discard' reduces the peak allocation of tmp_dnode_info structures from 1.8M to a mere 62872 (3.5%) in the degenerate case referenced above. This version of the patch also correctly rememembers the highest node version# seen for an inode when it's scanned. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'fs/jffs2/nodelist.h')
-rw-r--r--fs/jffs2/nodelist.h25
1 files changed, 23 insertions, 2 deletions
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 382662cc61e7..e5c8f2be8e22 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -225,7 +225,20 @@ struct jffs2_tmp_dnode_info
225 uint32_t version; 225 uint32_t version;
226 uint32_t data_crc; 226 uint32_t data_crc;
227 uint32_t partial_crc; 227 uint32_t partial_crc;
228 uint32_t csize; 228 uint16_t csize;
229 uint16_t overlapped;
230};
231
232/* Temporary data structure used during readinode. */
233struct jffs2_readinode_info
234{
235 struct rb_root tn_root;
236 struct jffs2_tmp_dnode_info *mdata_tn;
237 uint32_t highest_version;
238 uint32_t latest_mctime;
239 uint32_t mctime_ver;
240 struct jffs2_full_dirent *fds;
241 struct jffs2_raw_node_ref *latest_ref;
229}; 242};
230 243
231struct jffs2_full_dirent 244struct jffs2_full_dirent
@@ -328,6 +341,15 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
328#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) 341#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
329#define frag_erase(frag, list) rb_erase(&frag->rb, list); 342#define frag_erase(frag, list) rb_erase(&frag->rb, list);
330 343
344#define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
345#define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
346#define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
347#define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb)
348#define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb)
349#define tn_erase(tn, list) rb_erase(&tn->rb, list);
350#define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb)
351#define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb)
352
331/* nodelist.c */ 353/* nodelist.c */
332void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); 354void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
333void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); 355void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
@@ -343,7 +365,6 @@ struct rb_node *rb_prev(struct rb_node *);
343void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); 365void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
344int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); 366int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
345void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); 367void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
346int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn);
347struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, 368struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
348 struct jffs2_eraseblock *jeb, 369 struct jffs2_eraseblock *jeb,
349 uint32_t ofs, uint32_t len, 370 uint32_t ofs, uint32_t len,