From: "Yan, Zheng" <zyan@redhat.com>
Date: Fri, 27 Apr 2018 11:11:31 +0800
Subject: ceph: handle the new nfiles/nsubdirs fields in cap message
Git-commit: 4985d6f9e50fa48e35a9dbe1726434f987305cae
Patch-mainline: v4.18-rc1
References: FATE#324714
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>
Acked-by: Luis Henriques <lhenriques@suse.com>
---
fs/ceph/caps.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -3029,6 +3029,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;
};
@@ -3153,6 +3157,11 @@ static void handle_cap_grant(struct inod
&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;
@@ -3740,6 +3749,7 @@ void ceph_handle_caps(struct ceph_mds_se
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;
@@ -3764,7 +3774,7 @@ void ceph_handle_caps(struct ceph_mds_se
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)
@@ -3772,7 +3782,7 @@ void ceph_handle_caps(struct ceph_mds_se
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;
@@ -3784,7 +3794,7 @@ void ceph_handle_caps(struct ceph_mds_se
}
}
- 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)
@@ -3793,7 +3803,7 @@ void ceph_handle_caps(struct ceph_mds_se
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;
@@ -3801,7 +3811,7 @@ void ceph_handle_caps(struct ceph_mds_se
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;
@@ -3821,6 +3831,25 @@ void ceph_handle_caps(struct ceph_mds_se
}
}
+ 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);