On Tue, 2020-11-10 at 07:03 -0500, Jeff Layton wrote: > The link count for a directory is defined as inode->i_subdirs + 2, > (for "." and ".."). i_subdirs is only populated when Fs caps are held. > Ensure we grab Fs caps when fetching the link count for a directory. > > URL: https://tracker.ceph.com/issues/48125 > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > --- > fs/ceph/inode.c | 13 ++++++++++--- > 1 file changed, 10 insertions(+), 3 deletions(-) > > diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c > index 7c22bc2ea076..9ba15ca6b010 100644 > --- a/fs/ceph/inode.c > +++ b/fs/ceph/inode.c > @@ -2343,15 +2343,22 @@ int ceph_permission(struct inode *inode, int mask) > } > > > > > /* Craft a mask of needed caps given a set of requested statx attrs. */ > -static int statx_to_caps(u32 want) > +static int statx_to_caps(u32 want, umode_t mode) > { > int mask = 0; > > > > > if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME|STATX_BTIME)) > mask |= CEPH_CAP_AUTH_SHARED; > > > > > - if (want & (STATX_NLINK|STATX_CTIME)) > + if (want & (STATX_NLINK|STATX_CTIME)) { > mask |= CEPH_CAP_LINK_SHARED; > + /* > + * The link count for directories depends on inode->i_subdirs, > + * and that is only updated when Fs caps are held. > + */ > + if (S_ISDIR(mode)) > + mask |= CEPH_CAP_FILE_SHARED; > + } I think I'm going to make a small change here and make this not set the Ls bit on directories. There really is no need for it since only care about i_subdirs, and that might prevent having to do a synchronous call to the MDS. > > > > > if (want & (STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_SIZE| > STATX_BLOCKS)) > @@ -2377,7 +2384,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat, > > > > > /* Skip the getattr altogether if we're asked not to sync */ > if (!(flags & AT_STATX_DONT_SYNC)) { > - err = ceph_do_getattr(inode, statx_to_caps(request_mask), > + err = ceph_do_getattr(inode, statx_to_caps(request_mask, inode->i_mode), > flags & AT_STATX_FORCE_SYNC); > if (err) > return err; -- Jeff Layton <jlayton@xxxxxxxxxx>