diff options
author | David Woodhouse <dwmw2@infradead.org> | 2005-07-05 17:03:10 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-07-06 08:07:54 -0400 |
commit | 9dee7503ce3fc38911b9873216619190cf688128 (patch) | |
tree | 4a980e7afd14722a81472600ed13e147ff69f923 /fs/jffs2/nodelist.c | |
parent | 10c96f2ec37f5369a785cf8c5a065a15e323c743 (diff) |
[JFFS2] Optimise jffs2_add_tn_to_list
Use an rbtree instead of a simple linked list. We were wasting
an amazing amount of time in jffs2_add_tn_to_list().
Thanks to Artem Bityuckiy and Jarkko Jlavinen for noticing.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2/nodelist.c')
-rw-r--r-- | fs/jffs2/nodelist.c | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 8a8e4b863824..be38cc5c35cd 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.94 2005/04/13 13:22:35 dwmw2 Exp $ | 10 | * $Id: nodelist.c,v 1.95 2005/07/05 21:03:07 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -58,27 +58,61 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
58 | /* Put a new tmp_dnode_info into the list, keeping the list in | 58 | /* Put a new tmp_dnode_info into the list, keeping the list in |
59 | order of increasing version | 59 | order of increasing version |
60 | */ | 60 | */ |
61 | static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) | 61 | |
62 | static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | ||
62 | { | 63 | { |
63 | struct jffs2_tmp_dnode_info **prev = list; | 64 | struct rb_node **p = &list->rb_node; |
64 | 65 | struct rb_node * parent = NULL; | |
65 | while ((*prev) && (*prev)->version < tn->version) { | 66 | struct jffs2_tmp_dnode_info *this; |
66 | prev = &((*prev)->next); | 67 | |
67 | } | 68 | while (*p) { |
68 | tn->next = (*prev); | 69 | parent = *p; |
69 | *prev = tn; | 70 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); |
71 | |||
72 | if (tn->version < this->version) | ||
73 | p = &(*p)->rb_left; | ||
74 | else if (tn->version > this->version) | ||
75 | p = &(*p)->rb_right; | ||
76 | else if (tn < this) | ||
77 | p = &(*p)->rb_left; | ||
78 | else | ||
79 | p = &(*p)->rb_right; | ||
80 | } | ||
81 | |||
82 | rb_link_node(&tn->rb, parent, p); | ||
83 | rb_insert_color(&tn->rb, list); | ||
70 | } | 84 | } |
71 | 85 | ||
72 | static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) | 86 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) |
73 | { | 87 | { |
74 | struct jffs2_tmp_dnode_info *next; | 88 | struct rb_node *this; |
89 | struct jffs2_tmp_dnode_info *tn; | ||
90 | |||
91 | this = list->rb_node; | ||
75 | 92 | ||
76 | while (tn) { | 93 | /* Now at bottom of tree */ |
77 | next = tn; | 94 | while (this) { |
78 | tn = tn->next; | 95 | if (this->rb_left) |
79 | jffs2_free_full_dnode(next->fn); | 96 | this = this->rb_left; |
80 | jffs2_free_tmp_dnode_info(next); | 97 | else if (this->rb_right) |
98 | this = this->rb_right; | ||
99 | else { | ||
100 | tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); | ||
101 | jffs2_free_full_dnode(tn->fn); | ||
102 | jffs2_free_tmp_dnode_info(tn); | ||
103 | |||
104 | this = this->rb_parent; | ||
105 | if (!this) | ||
106 | break; | ||
107 | |||
108 | if (this->rb_left == &tn->rb) | ||
109 | this->rb_left = NULL; | ||
110 | else if (this->rb_right == &tn->rb) | ||
111 | this->rb_right = NULL; | ||
112 | else BUG(); | ||
113 | } | ||
81 | } | 114 | } |
115 | list->rb_node = NULL; | ||
82 | } | 116 | } |
83 | 117 | ||
84 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) | 118 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) |
@@ -108,12 +142,13 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r | |||
108 | with this ino, returning the former in order of version */ | 142 | with this ino, returning the former in order of version */ |
109 | 143 | ||
110 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 144 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
111 | struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, | 145 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, |
112 | uint32_t *highest_version, uint32_t *latest_mctime, | 146 | uint32_t *highest_version, uint32_t *latest_mctime, |
113 | uint32_t *mctime_ver) | 147 | uint32_t *mctime_ver) |
114 | { | 148 | { |
115 | struct jffs2_raw_node_ref *ref, *valid_ref; | 149 | struct jffs2_raw_node_ref *ref, *valid_ref; |
116 | struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; | 150 | struct jffs2_tmp_dnode_info *tn; |
151 | struct rb_root ret_tn = RB_ROOT; | ||
117 | struct jffs2_full_dirent *fd, *ret_fd = NULL; | 152 | struct jffs2_full_dirent *fd, *ret_fd = NULL; |
118 | union jffs2_node_union node; | 153 | union jffs2_node_union node; |
119 | size_t retlen; | 154 | size_t retlen; |
@@ -450,7 +485,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
450 | return 0; | 485 | return 0; |
451 | 486 | ||
452 | free_out: | 487 | free_out: |
453 | jffs2_free_tmp_dnode_info_list(ret_tn); | 488 | jffs2_free_tmp_dnode_info_list(&ret_tn); |
454 | jffs2_free_full_dirent_list(ret_fd); | 489 | jffs2_free_full_dirent_list(ret_fd); |
455 | return err; | 490 | return err; |
456 | } | 491 | } |