diff options
-rw-r--r-- | fs/xfs/xfs_iget.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 3a0ba1dfd0e8..d3da00045f26 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -136,6 +136,40 @@ xfs_chash_free(xfs_mount_t *mp) | |||
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 | * Look up an inode by number in the given file system. | 173 | * Look up an inode by number in the given file system. |
140 | * The inode is looked up in the hash table for the file system | 174 | * The inode is looked up in the hash table for the file system |
141 | * represented by the mount point parameter mp. Each bucket of | 175 | * represented by the mount point parameter mp. Each bucket of |
@@ -229,7 +263,9 @@ again: | |||
229 | XFS_STATS_INC(xs_ig_found); | 263 | XFS_STATS_INC(xs_ig_found); |
230 | 264 | ||
231 | ip->i_flags &= ~XFS_IRECLAIMABLE; | 265 | ip->i_flags &= ~XFS_IRECLAIMABLE; |
266 | version = ih->ih_version; | ||
232 | read_unlock(&ih->ih_lock); | 267 | read_unlock(&ih->ih_lock); |
268 | xfs_ihash_promote(ih, ip, version); | ||
233 | 269 | ||
234 | XFS_MOUNT_ILOCK(mp); | 270 | XFS_MOUNT_ILOCK(mp); |
235 | list_del_init(&ip->i_reclaim); | 271 | list_del_init(&ip->i_reclaim); |
@@ -259,8 +295,15 @@ again: | |||
259 | inode_vp, vp); | 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 | read_unlock(&ih->ih_lock); | 305 | read_unlock(&ih->ih_lock); |
263 | 306 | xfs_ihash_promote(ih, ip, version); | |
264 | XFS_STATS_INC(xs_ig_found); | 307 | XFS_STATS_INC(xs_ig_found); |
265 | 308 | ||
266 | finish_inode: | 309 | finish_inode: |
@@ -547,6 +590,7 @@ xfs_inode_incore(xfs_mount_t *mp, | |||
547 | { | 590 | { |
548 | xfs_ihash_t *ih; | 591 | xfs_ihash_t *ih; |
549 | xfs_inode_t *ip; | 592 | xfs_inode_t *ip; |
593 | ulong version; | ||
550 | 594 | ||
551 | ih = XFS_IHASH(mp, ino); | 595 | ih = XFS_IHASH(mp, ino); |
552 | read_lock(&ih->ih_lock); | 596 | read_lock(&ih->ih_lock); |
@@ -554,11 +598,15 @@ xfs_inode_incore(xfs_mount_t *mp, | |||
554 | if (ip->i_ino == ino) { | 598 | if (ip->i_ino == ino) { |
555 | /* | 599 | /* |
556 | * If we find it and tp matches, return it. | 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 | * Otherwise break from the loop and return | 603 | * Otherwise break from the loop and return |
558 | * NULL. | 604 | * NULL. |
559 | */ | 605 | */ |
560 | if (ip->i_transp == tp) { | 606 | if (ip->i_transp == tp) { |
607 | version = ih->ih_version; | ||
561 | read_unlock(&ih->ih_lock); | 608 | read_unlock(&ih->ih_lock); |
609 | xfs_ihash_promote(ih, ip, version); | ||
562 | return (ip); | 610 | return (ip); |
563 | } | 611 | } |
564 | break; | 612 | break; |
@@ -685,6 +733,7 @@ xfs_iextract( | |||
685 | iq->i_prevp = ip->i_prevp; | 733 | iq->i_prevp = ip->i_prevp; |
686 | } | 734 | } |
687 | *ip->i_prevp = iq; | 735 | *ip->i_prevp = iq; |
736 | ih->ih_version++; | ||
688 | write_unlock(&ih->ih_lock); | 737 | write_unlock(&ih->ih_lock); |
689 | 738 | ||
690 | /* | 739 | /* |