fs/ceph/inode.c | 1 +
fs/ceph/mds_client.c | 11 +++++++++++
fs/ceph/mds_client.h | 6 +++++-
fs/ceph/xattr.c | 6 +-----
4 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 79ff197c7cc5..cfa0b550eef2 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -2607,6 +2607,7 @@ int ceph_do_getvxattr(struct inode *inode, const char *name, void *value,
goto out;
}
+ req->r_feature_needed = CEPHFS_FEATURE_OP_GETVXATTR;
req->r_path2 = kstrdup(name, GFP_NOFS);
if (!req->r_path2) {
err = -ENOMEM;
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 598012ddc401..e3683305445c 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2501,6 +2501,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
INIT_LIST_HEAD(&req->r_unsafe_dir_item);
INIT_LIST_HEAD(&req->r_unsafe_target_item);
req->r_fmode = -1;
+ req->r_feature_needed = -1;
kref_init(&req->r_kref);
RB_CLEAR_NODE(&req->r_node);
INIT_LIST_HEAD(&req->r_wait);
@@ -3255,6 +3256,16 @@ static void __do_request(struct ceph_mds_client *mdsc,
dout("do_request mds%d session %p state %s\n", mds, session,
ceph_session_state_name(session->s_state));
+
+ /*
+ * The old ceph will crash the MDSs when see unknown OPs
+ */
+ if (req->r_feature_needed > 0 &&
+ !test_bit(req->r_feature_needed, &session->s_features)) {
+ err = -EOPNOTSUPP;
+ goto out_session;
+ }
+
if (session->s_state != CEPH_MDS_SESSION_OPEN &&
session->s_state != CEPH_MDS_SESSION_HUNG) {
/*
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index e15ee2858fef..728b7d72bf76 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -31,8 +31,9 @@ enum ceph_feature_type {
CEPHFS_FEATURE_METRIC_COLLECT,
CEPHFS_FEATURE_ALTERNATE_NAME,
CEPHFS_FEATURE_NOTIFY_SESSION_STATE,
+ CEPHFS_FEATURE_OP_GETVXATTR,
- CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_NOTIFY_SESSION_STATE,
+ CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_OP_GETVXATTR,
};
#define CEPHFS_FEATURES_CLIENT_SUPPORTED { \
@@ -45,6 +46,7 @@ enum ceph_feature_type {
CEPHFS_FEATURE_METRIC_COLLECT, \
CEPHFS_FEATURE_ALTERNATE_NAME, \
CEPHFS_FEATURE_NOTIFY_SESSION_STATE, \
+ CEPHFS_FEATURE_OP_GETVXATTR, \
}
/*
@@ -352,6 +354,8 @@ struct ceph_mds_request {
long long r_dir_ordered_cnt;
int r_readdir_cache_idx;
+ int r_feature_needed;
+
struct ceph_cap_reservation r_caps_reservation;
};
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index b10d459c2326..5f29c1f08de1 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -983,11 +983,7 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
}
return err;
} else {
- err = ceph_do_getvxattr(inode, name, value, size);
- /* this would happen with a new client and old server combo */
- if (err == -EOPNOTSUPP)
- err = -ENODATA;
- return err;
+ return ceph_do_getvxattr(inode, name, value, size);
}
handle_non_vxattrs:
req_mask = __get_request_mask(inode);