Commit 71bce256bf2e2aaddf54a2f4ac216329c74be3ad
Committed by
Christoph Hellwig
1 parent
bfd4bda097
Exists in
master
and in
7 other branches
[XFS] Move the XFS inode to the front of its hash list on a cache hit
SGI Modid: xfs-linux:xfs-kern:21915a Signed-off-by: Nathan Scott <nathans@sgi.com> Signed-off-by: Christoph Hellwig <hch@sgi.com>
Showing 1 changed file with 50 additions and 1 deletions Side-by-side Diff
fs/xfs/xfs_iget.c
... | ... | @@ -136,6 +136,40 @@ |
136 | 136 | } |
137 | 137 | |
138 | 138 | /* |
139 | + * Try to move an inode to the front of its hash list if possible | |
140 | + * (and if its not there already). Called right after obtaining | |
141 | + * the list version number and then dropping the read_lock on the | |
142 | + * hash list in question (which is done right after looking up the | |
143 | + * inode in question...). | |
144 | + */ | |
145 | +STATIC void | |
146 | +xfs_ihash_promote( | |
147 | + xfs_ihash_t *ih, | |
148 | + xfs_inode_t *ip, | |
149 | + ulong version) | |
150 | +{ | |
151 | + xfs_inode_t *iq; | |
152 | + | |
153 | + if ((ip->i_prevp != &ih->ih_next) && write_trylock(&ih->ih_lock)) { | |
154 | + if (likely(version == ih->ih_version)) { | |
155 | + /* remove from list */ | |
156 | + if ((iq = ip->i_next)) { | |
157 | + iq->i_prevp = ip->i_prevp; | |
158 | + } | |
159 | + *ip->i_prevp = iq; | |
160 | + | |
161 | + /* insert at list head */ | |
162 | + iq = ih->ih_next; | |
163 | + iq->i_prevp = &ip->i_next; | |
164 | + ip->i_next = iq; | |
165 | + ip->i_prevp = &ih->ih_next; | |
166 | + ih->ih_next = ip; | |
167 | + } | |
168 | + write_unlock(&ih->ih_lock); | |
169 | + } | |
170 | +} | |
171 | + | |
172 | +/* | |
139 | 173 | * Look up an inode by number in the given file system. |
140 | 174 | * The inode is looked up in the hash table for the file system |
141 | 175 | * represented by the mount point parameter mp. Each bucket of |
142 | 176 | |
... | ... | @@ -229,7 +263,9 @@ |
229 | 263 | XFS_STATS_INC(xs_ig_found); |
230 | 264 | |
231 | 265 | ip->i_flags &= ~XFS_IRECLAIMABLE; |
266 | + version = ih->ih_version; | |
232 | 267 | read_unlock(&ih->ih_lock); |
268 | + xfs_ihash_promote(ih, ip, version); | |
233 | 269 | |
234 | 270 | XFS_MOUNT_ILOCK(mp); |
235 | 271 | list_del_init(&ip->i_reclaim); |
236 | 272 | |
... | ... | @@ -259,8 +295,15 @@ |
259 | 295 | inode_vp, vp); |
260 | 296 | } |
261 | 297 | |
298 | + /* | |
299 | + * Inode cache hit: if ip is not at the front of | |
300 | + * its hash chain, move it there now. | |
301 | + * Do this with the lock held for update, but | |
302 | + * do statistics after releasing the lock. | |
303 | + */ | |
304 | + version = ih->ih_version; | |
262 | 305 | read_unlock(&ih->ih_lock); |
263 | - | |
306 | + xfs_ihash_promote(ih, ip, version); | |
264 | 307 | XFS_STATS_INC(xs_ig_found); |
265 | 308 | |
266 | 309 | finish_inode: |
... | ... | @@ -547,6 +590,7 @@ |
547 | 590 | { |
548 | 591 | xfs_ihash_t *ih; |
549 | 592 | xfs_inode_t *ip; |
593 | + ulong version; | |
550 | 594 | |
551 | 595 | ih = XFS_IHASH(mp, ino); |
552 | 596 | read_lock(&ih->ih_lock); |
553 | 597 | |
554 | 598 | |
... | ... | @@ -554,11 +598,15 @@ |
554 | 598 | if (ip->i_ino == ino) { |
555 | 599 | /* |
556 | 600 | * If we find it and tp matches, return it. |
601 | + * Also move it to the front of the hash list | |
602 | + * if we find it and it is not already there. | |
557 | 603 | * Otherwise break from the loop and return |
558 | 604 | * NULL. |
559 | 605 | */ |
560 | 606 | if (ip->i_transp == tp) { |
607 | + version = ih->ih_version; | |
561 | 608 | read_unlock(&ih->ih_lock); |
609 | + xfs_ihash_promote(ih, ip, version); | |
562 | 610 | return (ip); |
563 | 611 | } |
564 | 612 | break; |
... | ... | @@ -685,6 +733,7 @@ |
685 | 733 | iq->i_prevp = ip->i_prevp; |
686 | 734 | } |
687 | 735 | *ip->i_prevp = iq; |
736 | + ih->ih_version++; | |
688 | 737 | write_unlock(&ih->ih_lock); |
689 | 738 | |
690 | 739 | /* |