Skip to content

Commit f12b966

Browse files
author
Darrick J. Wong
committed
xfs: use i_prev_unlinked to distinguish inodes that are not on the unlinked list
Alter the definition of i_prev_unlinked slightly to make it more obvious when an inode with 0 link count is not part of the iunlink bucket lists rooted in the AGI. This distinction is necessary because it is not sufficient to check inode.i_nlink to decide if an inode is on the unlinked list. Updates to i_nlink can happen while holding only ILOCK_EXCL, but updates to an inode's position in the AGI unlinked list (which happen after the nlink update) requires both ILOCK_EXCL and the AGI buffer lock. The next few patches will make it possible to reload an entire unlinked bucket list when we're walking the inode table or performing handle operations and need more than the ability to iget the last inode in the chain. The upcoming directory repair code also needs to be able to make this distinction to decide if a zero link count directory should be moved to the orphanage or allowed to inactivate. An upcoming enhancement to the online AGI fsck code will need this distinction to check and rebuild the AGI unlinked buckets. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
1 parent 68b957f commit f12b966

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

fs/xfs/xfs_icache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ xfs_inode_alloc(
113113
INIT_LIST_HEAD(&ip->i_ioend_list);
114114
spin_lock_init(&ip->i_ioend_lock);
115115
ip->i_next_unlinked = NULLAGINO;
116-
ip->i_prev_unlinked = NULLAGINO;
116+
ip->i_prev_unlinked = 0;
117117

118118
return ip;
119119
}

fs/xfs/xfs_inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,7 @@ xfs_iunlink_insert_inode(
20142014
}
20152015

20162016
/* Point the head of the list to point to this inode. */
2017+
ip->i_prev_unlinked = NULLAGINO;
20172018
return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
20182019
}
20192020

@@ -2116,7 +2117,7 @@ xfs_iunlink_remove_inode(
21162117
}
21172118

21182119
ip->i_next_unlinked = NULLAGINO;
2119-
ip->i_prev_unlinked = NULLAGINO;
2120+
ip->i_prev_unlinked = 0;
21202121
return error;
21212122
}
21222123

fs/xfs/xfs_inode.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,21 @@ typedef struct xfs_inode {
6868
uint64_t i_diflags2; /* XFS_DIFLAG2_... */
6969
struct timespec64 i_crtime; /* time created */
7070

71-
/* unlinked list pointers */
71+
/*
72+
* Unlinked list pointers. These point to the next and previous inodes
73+
* in the AGI unlinked bucket list, respectively. These fields can
74+
* only be updated with the AGI locked.
75+
*
76+
* i_next_unlinked caches di_next_unlinked.
77+
*/
7278
xfs_agino_t i_next_unlinked;
79+
80+
/*
81+
* If the inode is not on an unlinked list, this field is zero. If the
82+
* inode is the first element in an unlinked list, this field is
83+
* NULLAGINO. Otherwise, i_prev_unlinked points to the previous inode
84+
* in the unlinked list.
85+
*/
7386
xfs_agino_t i_prev_unlinked;
7487

7588
/* VFS inode */
@@ -81,6 +94,11 @@ typedef struct xfs_inode {
8194
struct list_head i_ioend_list;
8295
} xfs_inode_t;
8396

97+
static inline bool xfs_inode_on_unlinked_list(const struct xfs_inode *ip)
98+
{
99+
return ip->i_prev_unlinked != 0;
100+
}
101+
84102
static inline bool xfs_inode_has_attr_fork(struct xfs_inode *ip)
85103
{
86104
return ip->i_forkoff > 0;

0 commit comments

Comments
 (0)