diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 2a5caee2fb17..dcf1eff06f85 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2798,7 +2798,8 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
 			     void *inline_data, u32 inline_len,
 			     struct ceph_buffer *xattr_buf,
 			     struct ceph_mds_session *session,
-			     struct ceph_cap *cap, int issued)
+			     struct ceph_cap *cap, int issued,
+			     struct timespec *btime, u64 change_attr)
 	__releases(ci->i_ceph_lock)
 	__releases(mdsc->snap_rwsem)
 {
@@ -2864,11 +2865,14 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
 
 	__check_cap_issue(ci, cap, newcaps);
 
+	inode->i_version = max(change_attr, inode->i_version);
+
 	if ((newcaps & CEPH_CAP_AUTH_SHARED) &&
 	    (issued & CEPH_CAP_AUTH_EXCL) == 0) {
 		inode->i_mode = le32_to_cpu(grant->mode);
 		inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid));
 		inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid));
+		ci->i_btime = *btime;
 		dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
 		     from_kuid(&init_user_ns, inode->i_uid),
 		     from_kgid(&init_user_ns, inode->i_gid));
@@ -3480,6 +3484,9 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 	void *snaptrace;
 	size_t snaptrace_len;
 	void *p, *end;
+	u16 hdr_version;
+	struct timespec btime = {};
+	u64 change_attr = 0;
 
 	dout("handle_caps from mds%d\n", mds);
 
@@ -3499,7 +3506,8 @@ 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) {
+	hdr_version = le16_to_cpu(msg->hdr.version);
+	if (hdr_version >= 2) {
 		u32 flock_len;
 		ceph_decode_32_safe(&p, end, flock_len, bad);
 		if (p + flock_len > end)
@@ -3507,7 +3515,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 		p += flock_len;
 	}
 
-	if (le16_to_cpu(msg->hdr.version) >= 3) {
+	if (hdr_version >= 3) {
 		if (op == CEPH_CAP_OP_IMPORT) {
 			if (p + sizeof(*peer) > end)
 				goto bad;
@@ -3519,7 +3527,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 		}
 	}
 
-	if (le16_to_cpu(msg->hdr.version) >= 4) {
+	if (hdr_version >= 4) {
 		ceph_decode_64_safe(&p, end, inline_version, bad);
 		ceph_decode_32_safe(&p, end, inline_len, bad);
 		if (p + inline_len > end)
@@ -3528,7 +3536,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 		p += inline_len;
 	}
 
-	if (le16_to_cpu(msg->hdr.version) >= 8) {
+	if (hdr_version >= 8) {
 		u64 flush_tid;
 		u32 caller_uid, caller_gid;
 		u32 osd_epoch_barrier;
@@ -3549,6 +3557,13 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 		}
 	}
 
+	if (hdr_version >= 9) {
+		ceph_decode_need(&p, end, sizeof(struct ceph_timespec), bad);
+		ceph_decode_timespec(&btime, p);
+		p += sizeof(struct ceph_timespec);
+		ceph_decode_64_safe(&p, end, change_attr, bad);
+	}
+
 	/* lookup ino */
 	inode = ceph_find_inode(sb, vino);
 	ci = ceph_inode(inode);
@@ -3604,7 +3619,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 				  &cap, &issued);
 		handle_cap_grant(mdsc, inode, h, &pool_ns,
 				 inline_version, inline_data, inline_len,
-				 msg->middle, session, cap, issued);
+				 msg->middle, session, cap, issued, &btime,
+				 change_attr);
 		if (realm)
 			ceph_put_snap_realm(mdsc, realm);
 		goto done_unlocked;
@@ -3628,7 +3644,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 		issued |= __ceph_caps_dirty(ci);
 		handle_cap_grant(mdsc, inode, h, &pool_ns,
 				 inline_version, inline_data, inline_len,
-				 msg->middle, session, cap, issued);
+				 msg->middle, session, cap, issued, &btime,
+				 change_attr);
 		goto done_unlocked;
 
 	case CEPH_CAP_OP_FLUSH_ACK:
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 9ff5219d849e..5cfdab5d366b 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -529,6 +529,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
 	capsnap->mode = inode->i_mode;
 	capsnap->uid = inode->i_uid;
 	capsnap->gid = inode->i_gid;
+	capsnap->btime = ci->i_btime;
+
+	capsnap->change_attr = inode->i_version;
 
 	if (dirty & CEPH_CAP_XATTR_EXCL) {
 		__ceph_build_xattrs_blob(ci);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 244fd8dbff31..c264d823bc58 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -173,10 +173,13 @@ struct ceph_cap_snap {
 	umode_t mode;
 	kuid_t uid;
 	kgid_t gid;
+	struct timespec btime;
 
 	struct ceph_buffer *xattr_blob;
 	u64 xattr_version;
 
+	u64 change_attr;
+
 	u64 size;
 	struct timespec mtime, atime, ctime;
 	u64 time_warp_seq;
