diff options
author | Yan, Zheng <zyan@redhat.com> | 2018-04-27 11:11:31 +0800 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2018-06-04 20:45:56 +0200 |
commit | 4985d6f9e50fa48e35a9dbe1726434f987305cae (patch) | |
tree | 4b5c7a54f2b9e71564c5b37cf7b23e7fe93c5307 /fs/ceph/caps.c | |
parent | a1c6b8358171c16db0f858a7fbb28aa574b07c09 (diff) |
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" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r-- | fs/ceph/caps.c | 39 |
1 files 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); |