From 4985d6f9e50fa48e35a9dbe1726434f987305cae Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 27 Apr 2018 11:11:31 +0800 Subject: [PATCH] ceph: handle the new nfiles/nsubdirs fields in cap message Without these new fields, stale st_size is returned in following case. 1. MDS modifies a directory 2. MDS issues CEPH_CAP_ANY_SHARED to client 3. The client satifies stat(2) by its cached metadata. set st_size to "i_files + i_subdirs". Link: http://tracker.ceph.com/issues/23855 Signed-off-by: "Yan, Zheng" Signed-off-by: Ilya Dryomov --- fs/ceph/caps.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index de7b7a34195e..477b822e6333 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3030,6 +3030,10 @@ struct cap_extra_info { u64 inline_version; void *inline_data; u32 inline_len; + /* dirstat */ + bool dirstat_valid; + u64 nfiles; + u64 nsubdirs; /* currently issued */ int issued; }; @@ -3154,6 +3158,11 @@ static void handle_cap_grant(struct inode *inode, &ctime, &mtime, &atime); } + if ((newcaps & CEPH_CAP_FILE_SHARED) && extra_info->dirstat_valid) { + ci->i_files = extra_info->nfiles; + ci->i_subdirs = extra_info->nsubdirs; + } + if (newcaps & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)) { /* file layout may have changed */ s64 old_pool = ci->i_layout.pool_id; @@ -3741,6 +3750,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, struct ceph_mds_cap_peer *peer = NULL; struct ceph_snap_realm *realm = NULL; int op; + int msg_version = le16_to_cpu(msg->hdr.version); u32 seq, mseq; struct ceph_vino vino; void *snaptrace; @@ -3765,7 +3775,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, snaptrace_len = le32_to_cpu(h->snap_trace_len); p = snaptrace + snaptrace_len; - if (le16_to_cpu(msg->hdr.version) >= 2) { + if (msg_version >= 2) { u32 flock_len; ceph_decode_32_safe(&p, end, flock_len, bad); if (p + flock_len > end) @@ -3773,7 +3783,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, p += flock_len; } - if (le16_to_cpu(msg->hdr.version) >= 3) { + if (msg_version >= 3) { if (op == CEPH_CAP_OP_IMPORT) { if (p + sizeof(*peer) > end) goto bad; @@ -3785,7 +3795,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, } } - if (le16_to_cpu(msg->hdr.version) >= 4) { + if (msg_version >= 4) { ceph_decode_64_safe(&p, end, extra_info.inline_version, bad); ceph_decode_32_safe(&p, end, extra_info.inline_len, bad); if (p + extra_info.inline_len > end) @@ -3794,7 +3804,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, p += extra_info.inline_len; } - if (le16_to_cpu(msg->hdr.version) >= 5) { + if (msg_version >= 5) { struct ceph_osd_client *osdc = &mdsc->fsc->client->osdc; u32 epoch_barrier; @@ -3802,7 +3812,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, ceph_osdc_update_epoch_barrier(osdc, epoch_barrier); } - if (le16_to_cpu(msg->hdr.version) >= 8) { + if (msg_version >= 8) { u64 flush_tid; u32 caller_uid, caller_gid; u32 pool_ns_len; @@ -3822,6 +3832,25 @@ void ceph_handle_caps(struct ceph_mds_session *session, } } + if (msg_version >= 11) { + struct ceph_timespec *btime; + u64 change_attr; + u32 flags; + + /* version >= 9 */ + if (p + sizeof(*btime) > end) + goto bad; + btime = p; + p += sizeof(*btime); + ceph_decode_64_safe(&p, end, change_attr, bad); + /* version >= 10 */ + ceph_decode_32_safe(&p, end, flags, bad); + /* version >= 11 */ + extra_info.dirstat_valid = true; + ceph_decode_64_safe(&p, end, extra_info.nfiles, bad); + ceph_decode_64_safe(&p, end, extra_info.nsubdirs, bad); + } + /* lookup ino */ inode = ceph_find_inode(mdsc->fsc->sb, vino); ci = ceph_inode(inode);