Commit 428bb68a authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov

ceph: properly handle granular statx requests

cephfs can benefit from statx. We can have the client just request caps
sufficient for the needed attributes and leave off the rest.

Also, recognize when AT_STATX_DONT_SYNC is set, and just scrape the
inode without doing any call in that case. Force a call to the MDS in
the event that AT_STATX_FORCE_SYNC is set.

Link: http://tracker.ceph.com/issues/39258Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Reviewed-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarSage Weil <sage@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent ffb61c55
...@@ -2269,43 +2269,72 @@ int ceph_permission(struct inode *inode, int mask) ...@@ -2269,43 +2269,72 @@ int ceph_permission(struct inode *inode, int mask)
return err; return err;
} }
/* Craft a mask of needed caps given a set of requested statx attrs. */
static int statx_to_caps(u32 want)
{
int mask = 0;
if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME))
mask |= CEPH_CAP_AUTH_SHARED;
if (want & (STATX_NLINK|STATX_CTIME))
mask |= CEPH_CAP_LINK_SHARED;
if (want & (STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_SIZE|
STATX_BLOCKS))
mask |= CEPH_CAP_FILE_SHARED;
if (want & (STATX_CTIME))
mask |= CEPH_CAP_XATTR_SHARED;
return mask;
}
/* /*
* Get all attributes. Hopefully somedata we'll have a statlite() * Get all the attributes. If we have sufficient caps for the requested attrs,
* and can limit the fields we require to be accurate. * then we can avoid talking to the MDS at all.
*/ */
int ceph_getattr(const struct path *path, struct kstat *stat, int ceph_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags) u32 request_mask, unsigned int flags)
{ {
struct inode *inode = d_inode(path->dentry); struct inode *inode = d_inode(path->dentry);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
int err; int err = 0;
err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL, false); /* Skip the getattr altogether if we're asked not to sync */
if (!err) { if (!(flags & AT_STATX_DONT_SYNC)) {
generic_fillattr(inode, stat); err = ceph_do_getattr(inode, statx_to_caps(request_mask),
stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino); flags & AT_STATX_FORCE_SYNC);
if (ceph_snap(inode) == CEPH_NOSNAP) if (err)
stat->dev = inode->i_sb->s_dev; return err;
}
generic_fillattr(inode, stat);
stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
if (ceph_snap(inode) == CEPH_NOSNAP)
stat->dev = inode->i_sb->s_dev;
else
stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0;
if (S_ISDIR(inode->i_mode)) {
if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
RBYTES))
stat->size = ci->i_rbytes;
else else
stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0; stat->size = ci->i_files + ci->i_subdirs;
stat->blocks = 0;
if (S_ISDIR(inode->i_mode)) { stat->blksize = 65536;
if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), /*
RBYTES)) * Some applications rely on the number of st_nlink
stat->size = ci->i_rbytes; * value on directories to be either 0 (if unlinked)
else * or 2 + number of subdirectories.
stat->size = ci->i_files + ci->i_subdirs; */
stat->blocks = 0; if (stat->nlink == 1)
stat->blksize = 65536; /* '.' + '..' + subdirs */
/* stat->nlink = 1 + 1 + ci->i_subdirs;
* Some applications rely on the number of st_nlink
* value on directories to be either 0 (if unlinked)
* or 2 + number of subdirectories.
*/
if (stat->nlink == 1)
/* '.' + '..' + subdirs */
stat->nlink = 1 + 1 + ci->i_subdirs;
}
} }
/* Mask off any higher bits (e.g. btime) until we have support */
stat->result_mask = request_mask & STATX_BASIC_STATS;
return err; return err;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment