aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_iget.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r--fs/xfs/xfs_iget.c51
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 */
145STATIC void
146xfs_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
266finish_inode: 309finish_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 /*