On Fri, Sep 12, 2025 at 09:28:55AM -0600, Thomas Bertschinger wrote: > This is to support using open_by_handle_at(2) via io_uring. It is useful > for io_uring to request that opening a file via handle be completed > using only cached data, or fail with -EAGAIN if that is not possible. > > The signature of xfs_nfs_get_inode() is extended with a new flags > argument that allows callers to specify XFS_IGET_INCORE. > > That flag is set when the VFS passes the FILEID_CACHED flag via the > fileid_type argument. > > Signed-off-by: Thomas Bertschinger <tahbertschinger@xxxxxxxxx> > Acked-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > fs/xfs/xfs_export.c | 34 ++++++++++++++++++++++++++-------- > fs/xfs/xfs_export.h | 3 ++- > fs/xfs/xfs_handle.c | 2 +- > 3 files changed, 29 insertions(+), 10 deletions(-) > > diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c > index 201489d3de08..6a57ed8fd9b7 100644 > --- a/fs/xfs/xfs_export.c > +++ b/fs/xfs/xfs_export.c > @@ -106,7 +106,8 @@ struct inode * > xfs_nfs_get_inode( > struct super_block *sb, > u64 ino, > - u32 generation) > + u32 generation, > + uint flags) > { > xfs_mount_t *mp = XFS_M(sb); > xfs_inode_t *ip; > @@ -123,7 +124,9 @@ xfs_nfs_get_inode( > * fine and not an indication of a corrupted filesystem as clients can > * send invalid file handles and we have to handle it gracefully.. > */ > - error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip); > + flags |= XFS_IGET_UNTRUSTED; > + > + error = xfs_iget(mp, NULL, ino, flags, 0, &ip); > if (error) { > > /* > @@ -140,6 +143,10 @@ xfs_nfs_get_inode( > case -EFSCORRUPTED: > error = -ESTALE; > break; > + case -ENODATA: > + if (flags & XFS_IGET_INCORE) > + error = -EAGAIN; > + break; > default: > break; > } > @@ -170,10 +177,15 @@ xfs_nfs_get_inode( > > STATIC struct dentry * > xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid, > - int fh_len, int fileid_type) > + int fh_len, int fileid_type_flags) > { > + int fileid_type = FILEID_TYPE(fileid_type_flags); > struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; > struct inode *inode = NULL; > + uint flags = 0; > + > + if (fileid_type_flags & FILEID_CACHED) > + flags = XFS_IGET_INCORE; XFS_IGET_INCORE doesn't guarantee non-blocking lookup behaviour. It never has and it never will. It simply means we return inodes that are already full instantiated or it fails with either EAGAIN or ENODATA. IOWs, XFS_IGET_INCORE exploits the internal XFS inode cache architecture (cache lookups are done under RCU locks, so cannot block). The resultant cleanup that needs to be done once a ilookup fails before another attempt can be made is done outside RCU, and the lookup is most definitely allowed to block in those paths before it returns -EAGAIN to the outer lookup loop. It is mostly pure luck that we don't have any sleeping locks in various internal "need to retry the lookup" paths right now. Exposing XFS_IGET_INCORE functionality to the outside world does not fill me with joy, especially to a userspace ABI. i.e. this takes a rarely used, niche internal filesystem behaviour, redefines how it is supposed to behave and what it guarantees to callers without actually defining those semantics, and then requires the filesystem to support it forever more (because io_uring is kernel/userspace ABI). IOWs, this is a NACK on using XFS_IGET_INCORE for FILEID_CACHED. The semantics that are required bu io_uring are non-blocking lookups, and that should be defined by a new flag (say XFS_IGET_NONBLOCK) with clearly defined and agreed upon semantics. Indeed, this shows the semantic problem with defining the generic filehandle behaviour as FILEID_CACHED. io_ uring does not want -cached- inode lookups, it wants *non-blocking* inode lookups. These are *not* equivalent lookup semantics. e.g. find_inode_fast() has FILEID_CACHED compatible semantics - it will return either a referenced, fully instantiated cached inode or null. However, find_inode_fast() does *not have non-blocking behaviour*. If it finds an inode being freed, it will block until that inode has been removed from the cache, then it will retry the lookup and return NULL because the inode is no longer found in the cache. IOWs, "only return in-cache inodes" is fundamentally the wrong semantic to implement for non-blocking filehandle decoding. The API needs to ask for non-blocking lookup semantics, not "in-cache" lookup semantics. -Dave. -- Dave Chinner david@xxxxxxxxxxxxx