| From hch@lst.de Mon Sep 18 10:09:48 2017 |
| From: Christoph Hellwig <hch@lst.de> |
| Date: Sun, 17 Sep 2017 14:06:42 -0700 |
| Subject: xfs: fix inobt inode allocation search optimization |
| To: stable@vger.kernel.org |
| Cc: linux-xfs@vger.kernel.org, Omar Sandoval <osandov@fb.com>, "Darrick J . Wong" <darrick.wong@oracle.com> |
| Message-ID: <20170917210712.10804-18-hch@lst.de> |
| |
| |
| From: Omar Sandoval <osandov@fb.com> |
| |
| commit c44245b3d5435f533ca8346ece65918f84c057f9 upstream. |
| |
| When we try to allocate a free inode by searching the inobt, we try to |
| find the inode nearest the parent inode by searching chunks both left |
| and right of the chunk containing the parent. As an optimization, we |
| cache the leftmost and rightmost records that we previously searched; if |
| we do another allocation with the same parent inode, we'll pick up the |
| search where it last left off. |
| |
| There's a bug in the case where we found a free inode to the left of the |
| parent's chunk: we need to update the cached left and right records, but |
| because we already reassigned the right record to point to the left, we |
| end up assigning the left record to both the cached left and right |
| records. |
| |
| This isn't a correctness problem strictly, but it can result in the next |
| allocation rechecking chunks unnecessarily or allocating inodes further |
| away from the parent than it needs to. Fix it by swapping the record |
| pointer after we update the cached left and right records. |
| |
| Fixes: bd169565993b ("xfs: speed up free inode search") |
| Signed-off-by: Omar Sandoval <osandov@fb.com> |
| Reviewed-by: Christoph Hellwig <hch@lst.de> |
| Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/xfs/libxfs/xfs_ialloc.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/fs/xfs/libxfs/xfs_ialloc.c |
| +++ b/fs/xfs/libxfs/xfs_ialloc.c |
| @@ -1236,13 +1236,13 @@ xfs_dialloc_ag_inobt( |
| |
| /* free inodes to the left? */ |
| if (useleft && trec.ir_freecount) { |
| - rec = trec; |
| xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| cur = tcur; |
| |
| pag->pagl_leftrec = trec.ir_startino; |
| pag->pagl_rightrec = rec.ir_startino; |
| pag->pagl_pagino = pagino; |
| + rec = trec; |
| goto alloc_inode; |
| } |
| |