@@ -1992,6 +1992,35 @@ xfs_iunlink_destroy(
19921992 ASSERT (freed_anything == false || xfs_is_shutdown (pag -> pag_mount ));
19931993}
19941994
1995+ /*
1996+ * Find an inode on the unlinked list. This does not take references to the
1997+ * inode as we have existence guarantees by holding the AGI buffer lock and that
1998+ * only unlinked, referenced inodes can be on the unlinked inode list. If we
1999+ * don't find the inode in cache, then let the caller handle the situation.
2000+ */
2001+ static struct xfs_inode *
2002+ xfs_iunlink_lookup (
2003+ struct xfs_perag * pag ,
2004+ xfs_agino_t agino )
2005+ {
2006+ struct xfs_inode * ip ;
2007+
2008+ rcu_read_lock ();
2009+ ip = radix_tree_lookup (& pag -> pag_ici_root , agino );
2010+
2011+ /*
2012+ * Inode not in memory or in RCU freeing limbo should not happen.
2013+ * Warn about this and let the caller handle the failure.
2014+ */
2015+ if (WARN_ON_ONCE (!ip || !ip -> i_ino )) {
2016+ rcu_read_unlock ();
2017+ return NULL ;
2018+ }
2019+ ASSERT (!xfs_iflags_test (ip , XFS_IRECLAIMABLE | XFS_IRECLAIM ));
2020+ rcu_read_unlock ();
2021+ return ip ;
2022+ }
2023+
19952024/*
19962025 * Point the AGI unlinked bucket at an inode and log the results. The caller
19972026 * is responsible for validating the old value.
@@ -2097,7 +2126,8 @@ xfs_iunlink_update_inode(
20972126 * current pointer is the same as the new value, unless we're
20982127 * terminating the list.
20992128 */
2100- * old_next_agino = old_value ;
2129+ if (old_next_agino )
2130+ * old_next_agino = old_value ;
21012131 if (old_value == next_agino ) {
21022132 if (next_agino != NULLAGINO ) {
21032133 xfs_inode_verifier_error (ip , - EFSCORRUPTED , __func__ ,
@@ -2203,38 +2233,6 @@ xfs_iunlink(
22032233 return error ;
22042234}
22052235
2206- /* Return the imap, dinode pointer, and buffer for an inode. */
2207- STATIC int
2208- xfs_iunlink_map_ino (
2209- struct xfs_trans * tp ,
2210- xfs_agnumber_t agno ,
2211- xfs_agino_t agino ,
2212- struct xfs_imap * imap ,
2213- struct xfs_dinode * * dipp ,
2214- struct xfs_buf * * bpp )
2215- {
2216- struct xfs_mount * mp = tp -> t_mountp ;
2217- int error ;
2218-
2219- imap -> im_blkno = 0 ;
2220- error = xfs_imap (mp , tp , XFS_AGINO_TO_INO (mp , agno , agino ), imap , 0 );
2221- if (error ) {
2222- xfs_warn (mp , "%s: xfs_imap returned error %d." ,
2223- __func__ , error );
2224- return error ;
2225- }
2226-
2227- error = xfs_imap_to_bp (mp , tp , imap , bpp );
2228- if (error ) {
2229- xfs_warn (mp , "%s: xfs_imap_to_bp returned error %d." ,
2230- __func__ , error );
2231- return error ;
2232- }
2233-
2234- * dipp = xfs_buf_offset (* bpp , imap -> im_boffset );
2235- return 0 ;
2236- }
2237-
22382236/*
22392237 * Walk the unlinked chain from @head_agino until we find the inode that
22402238 * points to @target_agino. Return the inode number, map, dinode pointer,
@@ -2245,77 +2243,49 @@ xfs_iunlink_map_ino(
22452243 *
22462244 * Do not call this function if @target_agino is the head of the list.
22472245 */
2248- STATIC int
2249- xfs_iunlink_map_prev (
2250- struct xfs_trans * tp ,
2246+ static int
2247+ xfs_iunlink_lookup_prev (
22512248 struct xfs_perag * pag ,
22522249 xfs_agino_t head_agino ,
22532250 xfs_agino_t target_agino ,
2254- xfs_agino_t * agino ,
2255- struct xfs_imap * imap ,
2256- struct xfs_dinode * * dipp ,
2257- struct xfs_buf * * bpp )
2251+ struct xfs_inode * * ipp )
22582252{
2259- struct xfs_mount * mp = tp -> t_mountp ;
2253+ struct xfs_inode * ip ;
22602254 xfs_agino_t next_agino ;
2261- int error ;
2262-
2263- ASSERT (head_agino != target_agino );
2264- * bpp = NULL ;
22652255
2266- /* See if our backref cache can find it faster. */
2267- * agino = xfs_iunlink_lookup_backref (pag , target_agino );
2268- if (* agino != NULLAGINO ) {
2269- error = xfs_iunlink_map_ino (tp , pag -> pag_agno , * agino , imap ,
2270- dipp , bpp );
2271- if (error )
2272- return error ;
2256+ * ipp = NULL ;
22732257
2274- if (be32_to_cpu ((* dipp )-> di_next_unlinked ) == target_agino )
2258+ next_agino = xfs_iunlink_lookup_backref (pag , target_agino );
2259+ if (next_agino != NULLAGINO ) {
2260+ ip = xfs_iunlink_lookup (pag , next_agino );
2261+ if (ip && ip -> i_next_unlinked == target_agino ) {
2262+ * ipp = ip ;
22752263 return 0 ;
2276-
2277- /*
2278- * If we get here the cache contents were corrupt, so drop the
2279- * buffer and fall back to walking the bucket list.
2280- */
2281- xfs_trans_brelse (tp , * bpp );
2282- * bpp = NULL ;
2283- WARN_ON_ONCE (1 );
2264+ }
22842265 }
22852266
2286- trace_xfs_iunlink_map_prev_fallback (mp , pag -> pag_agno );
2287-
22882267 /* Otherwise, walk the entire bucket until we find it. */
22892268 next_agino = head_agino ;
2290- while (next_agino != target_agino ) {
2291- xfs_agino_t unlinked_agino ;
2292-
2293- if (* bpp )
2294- xfs_trans_brelse (tp , * bpp );
2269+ while (next_agino != NULLAGINO ) {
2270+ ip = xfs_iunlink_lookup (pag , next_agino );
2271+ if (!ip )
2272+ return - EFSCORRUPTED ;
22952273
2296- * agino = next_agino ;
2297- error = xfs_iunlink_map_ino (tp , pag -> pag_agno , next_agino , imap ,
2298- dipp , bpp );
2299- if (error )
2300- return error ;
2301-
2302- unlinked_agino = be32_to_cpu ((* dipp )-> di_next_unlinked );
23032274 /*
23042275 * Make sure this pointer is valid and isn't an obvious
23052276 * infinite loop.
23062277 */
2307- if (!xfs_verify_agino (pag , unlinked_agino ) ||
2308- next_agino == unlinked_agino ) {
2309- XFS_CORRUPTION_ERROR ( __func__ ,
2310- XFS_ERRLEVEL_LOW , mp ,
2311- * dipp , sizeof ( * * dipp ));
2312- error = - EFSCORRUPTED ;
2313- return error ;
2278+ if (!xfs_verify_agino (pag , ip -> i_next_unlinked ) ||
2279+ next_agino == ip -> i_next_unlinked )
2280+ return - EFSCORRUPTED ;
2281+
2282+ if ( ip -> i_next_unlinked == target_agino ) {
2283+ * ipp = ip ;
2284+ return 0 ;
23142285 }
2315- next_agino = unlinked_agino ;
2286+ next_agino = ip -> i_next_unlinked ;
23162287 }
2317-
2318- return 0 ;
2288+ return - EFSCORRUPTED ;
23192289}
23202290
23212291static int
@@ -2327,8 +2297,6 @@ xfs_iunlink_remove_inode(
23272297{
23282298 struct xfs_mount * mp = tp -> t_mountp ;
23292299 struct xfs_agi * agi = agibp -> b_addr ;
2330- struct xfs_buf * last_ibp ;
2331- struct xfs_dinode * last_dip = NULL ;
23322300 xfs_agino_t agino = XFS_INO_TO_AGINO (mp , ip -> i_ino );
23332301 xfs_agino_t next_agino ;
23342302 xfs_agino_t head_agino ;
@@ -2356,7 +2324,6 @@ xfs_iunlink_remove_inode(
23562324 error = xfs_iunlink_update_inode (tp , ip , pag , NULLAGINO , & next_agino );
23572325 if (error )
23582326 return error ;
2359- ip -> i_next_unlinked = NULLAGINO ;
23602327
23612328 /*
23622329 * If there was a backref pointing from the next inode back to this
@@ -2372,18 +2339,21 @@ xfs_iunlink_remove_inode(
23722339 }
23732340
23742341 if (head_agino != agino ) {
2375- struct xfs_imap imap ;
2376- xfs_agino_t prev_agino ;
2342+ struct xfs_inode * prev_ip ;
23772343
2378- /* We need to search the list for the inode being freed. */
2379- error = xfs_iunlink_map_prev (tp , pag , head_agino , agino ,
2380- & prev_agino , & imap , & last_dip , & last_ibp );
2344+ error = xfs_iunlink_lookup_prev (pag , head_agino , agino ,
2345+ & prev_ip );
23812346 if (error )
23822347 return error ;
23832348
23842349 /* Point the previous inode on the list to the next inode. */
2385- xfs_iunlink_update_dinode (tp , pag , prev_agino , last_ibp ,
2386- last_dip , & imap , next_agino );
2350+ error = xfs_iunlink_update_inode (tp , prev_ip , pag , next_agino ,
2351+ NULL );
2352+ if (error )
2353+ return error ;
2354+
2355+ prev_ip -> i_next_unlinked = ip -> i_next_unlinked ;
2356+ ip -> i_next_unlinked = NULLAGINO ;
23872357
23882358 /*
23892359 * Now we deal with the backref for this inode. If this inode
@@ -2398,6 +2368,7 @@ xfs_iunlink_remove_inode(
23982368 }
23992369
24002370 /* Point the head of the list to the next unlinked inode. */
2371+ ip -> i_next_unlinked = NULLAGINO ;
24012372 return xfs_iunlink_update_bucket (tp , pag , agibp , bucket_index ,
24022373 next_agino );
24032374}
0 commit comments