Skip to content

Commit 2fd26cc

Browse files
dgchinnerdchinner
authored andcommitted
xfs: double link the unlinked inode list
Now we have forwards traversal via the incore inode in place, we now need to add back pointers to the incore inode to entirely replace the back reference cache. We use the same lookup semantics and constraints as for the forwards pointer lookups during unlinks, and so we can look up any inode in the unlinked list directly and update the list pointers, forwards or backwards, at any time. The only wrinkle in converting the unlinked list manipulations to use in-core previous pointers is that log recovery doesn't have the incore inode state built up so it can't just read in an inode and release it to finish off the unlink. Hence we need to modify the traversal in recovery to read one inode ahead before we release the inode at the head of the list. This populates the next->prev relationship sufficient to be able to replay the unlinked list and hence greatly simplify the runtime code. This recovery algorithm also requires that we actually remove inodes from the unlinked list one at a time as background inode inactivation will result in unlinked list removal racing with the building of the in-memory unlinked list state. We could serialise this by holding the AGI buffer lock when constructing the in memory state, but all that does is lockstep background processing with list building. It is much simpler to flush the inodegc immediately after releasing the inode so that it is unlinked immediately and there is no races present at all. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent a83d5a8 commit 2fd26cc

6 files changed

Lines changed: 90 additions & 310 deletions

File tree

fs/xfs/libxfs/xfs_ag.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ xfs_free_perag(
194194
XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
195195

196196
cancel_delayed_work_sync(&pag->pag_blockgc_work);
197-
xfs_iunlink_destroy(pag);
198197
xfs_buf_hash_destroy(pag);
199198

200199
call_rcu(&pag->rcu_head, __xfs_free_perag);
@@ -323,10 +322,6 @@ xfs_initialize_perag(
323322
if (error)
324323
goto out_remove_pag;
325324

326-
error = xfs_iunlink_init(pag);
327-
if (error)
328-
goto out_hash_destroy;
329-
330325
/* first new pag is fully initialized */
331326
if (first_initialised == NULLAGNUMBER)
332327
first_initialised = index;
@@ -349,8 +344,6 @@ xfs_initialize_perag(
349344
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
350345
return 0;
351346

352-
out_hash_destroy:
353-
xfs_buf_hash_destroy(pag);
354347
out_remove_pag:
355348
radix_tree_delete(&mp->m_perag_tree, index);
356349
out_free_pag:
@@ -362,7 +355,6 @@ xfs_initialize_perag(
362355
if (!pag)
363356
break;
364357
xfs_buf_hash_destroy(pag);
365-
xfs_iunlink_destroy(pag);
366358
kmem_free(pag);
367359
}
368360
return error;

fs/xfs/libxfs/xfs_ag.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,6 @@ struct xfs_perag {
103103
/* background prealloc block trimming */
104104
struct delayed_work pag_blockgc_work;
105105

106-
/*
107-
* Unlinked inode information. This incore information reflects
108-
* data stored in the AGI, so callers must hold the AGI buffer lock
109-
* or have some other means to control concurrency.
110-
*/
111-
struct rhashtable pagi_unlinked_hash;
112106
#endif /* __KERNEL__ */
113107
};
114108

fs/xfs/xfs_icache.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ xfs_inode_alloc(
111111
INIT_WORK(&ip->i_ioend_work, xfs_end_io);
112112
INIT_LIST_HEAD(&ip->i_ioend_list);
113113
spin_lock_init(&ip->i_ioend_lock);
114+
ip->i_next_unlinked = NULLAGINO;
115+
ip->i_prev_unlinked = NULLAGINO;
114116

115117
return ip;
116118
}

0 commit comments

Comments
 (0)