ceph: add support for getvxattr op
Subsystems (2)
v4 cover ceph: add support for getvxattr op
Adds support for getting ceph virtual xattrs using the new getvxattr op.
fixed in v4:
* fixed dout format specifier for size_t types to %zu in place of %lu
Milind Changire (1):
ceph: add getvxattr op
fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)
base-commit: fd84bfdddd169c219c3a637889a8b87f70a072c2
Signature · 1 line
2.31.1
PATCH v4 1/1 ceph: add getvxattr op
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.
Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.
URL: https://tracker.ceph.com/issues/51062
--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)
fs/ceph/inode.c +51 -0
@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for
fs/ceph/mds_client.c +26 -1
@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */
@@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }
@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;
fs/ceph/mds_client.h +11 -1
@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/*
@@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }
@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry,
@@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {
fs/ceph/strings.c +1 -0
@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;
fs/ceph/super.h +1 -0
@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);
fs/ceph/xattr.c +34 -0
@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false; + +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false; + } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {
@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err; +if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {
include/linux/ceph/ceph_fs.h +1 -0
@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,
Signature · 1 line
2.31.1
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;
fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;
What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +
What is this? Why not always service this locally?
Quoted 15 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 245 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside a mutex_unlock(&mdsc->mutex) ... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.
Quoted 12 lines
Quoted 12 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;
Quoted 12 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr() currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.
Quoted 19 lines
Quoted 9 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in 'ceph_file_vxattrs' and 'ceph_dir_vxattrs'...
And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
Quoted 21 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 17 lines
Quoted 8 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 289 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*
Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_json
Quoted 25 lines
Quoted 24 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 17 lines
Quoted 8 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 292 lines · Milind Changire
Quoted 291 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...
Quoted 9 lines
Quoted 2 lines
And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_json
Yeah, sounds good. Or maybe just adding the '.json' instead of '_json'.
Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 17 lines
Quoted 8 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 295 lines · Xiubo Li
Quoted 294 lines · Milind Changire
Quoted 293 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
Quoted 9 lines
Quoted 7 lines
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_jsonYeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.
+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after ceph_match_vxattr doesn't match an xattr name.
Quoted 25 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 17 lines
Quoted 8 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 302 lines · Jeff Layton
Quoted 301 lines · Xiubo Li
Quoted 300 lines · Milind Changire
Quoted 286 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_json
Quoted 7 lines
Quoted 2 lines
Yeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after
ceph_match_vxattrdoesn't match an xattr name.
Sounds good.
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 17 lines
Quoted 8 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +0
-0include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 7 lines
include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , +CEPH_MDS_OP_GETVXATTR =0x00106 ,CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
In reply to Jeff LaytonQuoted 304 lines · Jeff Layton
Quoted 302 lines · Xiubo Li
Quoted 301 lines · Milind Changire
Quoted 287 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_json
Quoted 8 lines
Quoted 2 lines
Yeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after
ceph_match_vxattrdoesn't match an xattr name.
I'm with you, but this set of changes (and its Client.cc equivalent) is by request from Patrick and Venky (added), so there may be some subtleties we're missing. And we should follow the same pattern for who gets to resolve vxattrs in both clients.
-Greg
Quoted 30 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
If kclient is new and the cluster is old, then layout vxattr will be handled the old
way, i.e. locally. ceph.dir.pin* will remain inaccessible.Quoted 13 lines
Quoted 13 lines
fs/ceph/xattr.c +0
-0/* let's see if a virtual xattr was requested */ vxattr =ceph_match_vxattr (inode, name);if (vxattr) {include/linux/ceph/ceph_fs.h +1
-0@@ -328,6 +328,7 @@ enum {CEPH_MDS_OP_LOOKUPPARENT =0x00103 ,CEPH_MDS_OP_LOOKUPINO =0x00104 ,CEPH_MDS_OP_LOOKUPNAME =0x00105 , + CEPH_MDS_OP_GETVXATTR = 0x00106,Quoted 5 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/linux/ceph/ceph_fs.h enum { · line 334
Quoted 2 lines
include/linux/ceph/ceph_fs.h +0
-0CEPH_MDS_OP_SETXATTR =0x01105 , CEPH_MDS_OP_RMXATTR = 0x01106,--
Jeff Layton <[email protected]>--
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 315 lines · Gregory Farnum
Quoted 304 lines · Jeff Layton
Quoted 302 lines · Xiubo Li
Quoted 301 lines · Milind Changire
Quoted 287 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_jsonQuoted 8 lines
Quoted 2 lines
Yeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after
ceph_match_vxattrdoesn't match an xattr name.
Quoted 5 lines
I'm with you, but this set of changes (and its Client.cc equivalent) is by request from Patrick and Venky (added), so there may be some subtleties we're missing. And we should follow the same pattern for who gets to resolve vxattrs in both clients.
-Greg
I had incorrectly recalled that the client did return json for the layout xattrs. So, yes, we can't just switch to json for these existing vxattrs. I agree adding a "json" extension cleanly avoids the issue. We can continue handling the existing layout vxattrs without the suffix in the client (for now).
Although, I do think ".json" is a little weird. I had privately expressed to Jeff/Milind that "!json" or similar as a suffix could be more appropriate. It emphasizes it's not a derivative xattr.
Signature · 5 lines
Patrick Donnelly, Ph.D. He / Him / His Principal Software Engineer Red Hat, Inc. GPG: 19F28A586F808C2402351B93C3301A3E258DD79D
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 328 lines · Patrick Donnelly
Quoted 315 lines · Gregory Farnum
Quoted 304 lines · Jeff Layton
Quoted 302 lines · Xiubo Li
Quoted 301 lines · Milind Changire
Quoted 287 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_jsonQuoted 8 lines
Quoted 2 lines
Yeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after
ceph_match_vxattrdoesn't match an xattr name.Quoted 5 lines
I'm with you, but this set of changes (and its Client.cc equivalent) is by request from Patrick and Venky (added), so there may be some subtleties we're missing. And we should follow the same pattern for who gets to resolve vxattrs in both clients.
-GregI had incorrectly recalled that the client did return json for the layout xattrs. So, yes, we can't just switch to json for these existing vxattrs. I agree adding a "json" extension cleanly avoids the issue. We can continue handling the existing layout vxattrs without the suffix in the client (for now).
Quoted 4 lines
Although, I do think ".json" is a little weird. I had privately expressed to Jeff/Milind that "!json" or similar as a suffix could be more appropriate. It emphasizes it's not a derivative xattr.
The mixed delimiters are also weird, and I don't think it's really outside the scope of the existing ceph.file.layout.* xattrs.
Also, I have to wonder -- why json? Isn't yaml more en vogue these days?
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v4 1/1] ceph: add getvxattr op
Quoted 330 lines · Jeff Layton
Quoted 328 lines · Patrick Donnelly
Quoted 315 lines · Gregory Farnum
Quoted 304 lines · Jeff Layton
Quoted 302 lines · Xiubo Li
Quoted 301 lines · Milind Changire
Quoted 287 lines · Xiubo Li
Quoted 277 lines · Milind Changire
Quoted 243 lines · Jeff Layton
Quoted 229 lines · Milind Changire
Problem:
Directory vxattrs like ceph.dir.pin* and ceph.dir.layout* may not be propagated to the client as frequently to keep them updated. This creates vxattr availability problems.Solution:
Adds new getvxattr op to fetch ceph.dir.pin*, ceph.dir.layout* and ceph.file.layout* vxattrs.
If the entire layout for a dir or a file is being set, then it is expected that the layout be set in standard JSON format. Individual field value retrieval is not wrapped in JSON. The JSON format also applies while setting the vxattr if the entire layout is being set in one go.
As a temporary measure, setting a vxattr can also be done in the old format. The old format will be deprecated in the future.URL: https://tracker.ceph.com/issues/51062
Signed-off-by Milind Changire <[email protected]>--- fs/ceph/inode.c | 51 ++++++++++++++++++++++++++++++++++++ fs/ceph/mds_client.c | 27 ++++++++++++++++++- fs/ceph/mds_client.h | 12 ++++++++- fs/ceph/strings.c | 1 + fs/ceph/super.h | 1 + fs/ceph/xattr.c | 34 ++++++++++++++++++++++++ include/linux/ceph/ceph_fs.h | 1 + 7 files changed, 125 insertions(+), 2 deletions(-)fs/ceph/inode.c +51
-0@@ -2291,6 +2291,57 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,return err; } +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value, +size_t size) +{ +struct ceph_fs_client *fsc =ceph_sb_to_client (inode->i_sb); +struct ceph_mds_client *mdsc = fsc->mdsc; +struct ceph_mds_request *req; +int mode =USE_AUTH_MDS ; +int err; +char *xattr_value; +size_t xattr_value_len; + + req =ceph_mdsc_create_request (mdsc,CEPH_MDS_OP_GETVXATTR , mode); +if (IS_ERR (req)) { + err = -ENOMEM ; + goto out; + } + + req->r_path2 =kstrdup (name,GFP_NOFS ); +if (!req->r_path2) { + err = -ENOMEM ; + goto put; + } + +ihold (inode); + req->r_inode = inode; + err =ceph_mdsc_do_request (mdsc,NULL , req); +if (err <0 ) + goto put; + + xattr_value = req->r_reply_info.xattr_info.xattr_value; + xattr_value_len = req->r_reply_info.xattr_info.xattr_value_len; + +dout ("do_getvxattr xattr_value_len:%zu, size:%zu\n" , xattr_value_len, size); + + err = (int )xattr_value_len; +if (size ==0 ) + goto put; + +if (xattr_value_len > size) { + err = -ERANGE ; + goto put; + } + +memcpy (value, xattr_value, xattr_value_len); +put: +ceph_mdsc_put_request (req); +out: +dout ("do_getvxattr result=%d\n" , err); +return err; +} +/* * Check inode permissions. We verify we have a valid value for fs/ceph/mds_client.c +26
-1@@ -555,6 +555,29 @@ static int parse_reply_info_create(void **p, void *end,return -EIO ; } +static int parse_reply_info_getvxattr (void **p,void *end, +struct ceph_mds_reply_info_parsed *info, +u64 features) +{ +u8 struct_v, struct_compat; +u32 struct_len; +u32 value_len; + +ceph_decode_8_safe (p, end, struct_v, bad); +ceph_decode_8_safe (p, end, struct_compat, bad); +ceph_decode_32_safe (p, end, struct_len, bad); +ceph_decode_32_safe (p, end, value_len, bad); + +if (value_len == end - *p) { + info->xattr_info.xattr_value = *p; + info->xattr_info.xattr_value_len = end - *p; + *p = end; +return info->xattr_info.xattr_value_len; + } +bad: +return -EIO ; +} +/* * parse extra results */ @@ -570,6 +593,8 @@ static int parse_reply_info_extra(void **p, void *end,return parse_reply_info_readdir (p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); + else if (op == CEPH_MDS_OP_GETVXATTR) + return parse_reply_info_getvxattr(p, end, info, features); else return -EIO; }@@ -615,7 +640,7 @@ static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,if (p != end) goto bad; -return 0 ; +return err; bad: err = -EIO ;fs/ceph/mds_client.h +11
-1@@ -29,8 +29,10 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT ,CEPHFS_FEATURE_DELEG_INO ,CEPHFS_FEATURE_METRIC_COLLECT , +CEPHFS_FEATURE_ALTERNATE_NAME , +CEPHFS_FEATURE_GETVXATTR , - CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, + CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_GETVXATTR, };/* @@ -45,6 +47,8 @@ enum ceph_feature_type {CEPHFS_FEATURE_MULTI_RECONNECT , \CEPHFS_FEATURE_DELEG_INO , \CEPHFS_FEATURE_METRIC_COLLECT , \ +CEPHFS_FEATURE_ALTERNATE_NAME , \ +CEPHFS_FEATURE_GETVXATTR , \ \ CEPHFS_FEATURE_MAX, \ }@@ -100,6 +104,11 @@ struct ceph_mds_reply_dir_entry {loff_t offset; }; +struct ceph_mds_reply_xattr { +char *xattr_value; +size_t xattr_value_len; +}; +/* * parsed info about an mds reply, including information about * either: 1) the target inode and/or its parent directory and dentry, @@ -115,6 +124,7 @@ struct ceph_mds_reply_info_parsed {char *dname;u32 dname_len;struct ceph_mds_reply_lease *dlease; +struct ceph_mds_reply_xattr xattr_info;/* extra */ union {fs/ceph/strings.c +1
-0@@ -60,6 +60,7 @@ const char *ceph_mds_op_name(int op)case CEPH_MDS_OP_LOOKUPINO :return "lookupino" ;case CEPH_MDS_OP_LOOKUPNAME :return "lookupname" ;case CEPH_MDS_OP_GETATTR :return "getattr" ; +case CEPH_MDS_OP_GETVXATTR :return "getvxattr" ;case CEPH_MDS_OP_SETXATTR :return "setxattr" ;case CEPH_MDS_OP_SETATTR :return "setattr" ;case CEPH_MDS_OP_RMXATTR :return "rmxattr" ;fs/ceph/super.h +1
-0@@ -1043,6 +1043,7 @@ static inline bool ceph_inode_is_shutdown(struct inode *inode)/* xattr.c */ int __ceph_setxattr (struct inode *,const char *,const void *,size_t ,int ); +int ceph_do_getvxattr (struct inode *inode,const char *name,void *value,size_t size);ssize_t __ceph_getxattr (struct inode *,const char *,void *,size_t );extern ssize_t ceph_listxattr (struct dentry *,char *,size_t );extern struct ceph_buffer *__ceph_build_xattrs_blob (struct ceph_inode_info *ci);fs/ceph/xattr.c +10
-0@@ -918,6 +918,30 @@ static inline int __get_request_mask(struct inode *in) {return mask; } +/* check if the entire cluster supports the given feature */ +static inline bool ceph_cluster_has_feature (struct inode *inode,int feature_bit) +{ +int64_t i; +struct ceph_fs_client *fsc =ceph_inode_to_client (inode); +struct ceph_mds_session **sessions = fsc->mdsc->sessions; +int64_t num_sessions =atomic_read (&fsc->mdsc->num_sessions); + +if (fsc->mdsc->stopping) +return false;fs/ceph/xattr.c static inline int __get_request_mask(struct inode *in) { · line 940
Quoted 10 lines
fs/ceph/xattr.c +10
-0+ +if (!sessions) +return false; + +for (i =0 ; i < num_sessions; i++) { +struct ceph_mds_session *session = sessions[i]; +if (!session) +return false; +if (!test_bit (feature_bit, &session->s_features)) +return false;What guarantee do you have that "session" will still be a valid pointer by the time you get to dereferencing it here?
Quoted 2 lines
I think this loop needs some locking (as Xiubo pointed out in his earlier review).
yeah, thanks for pointing that out
I'm trying to wrap the entire processing of this function inside amutex_unlock(&mdsc->mutex)... but the mount command fails to mount if done so. If code is not wrapped in mutex lock...unlock then the mount is successful.
It's a surprise that the code doesn't deadlock under the mutex lock...unlock and gracefully fails with a message.
Any hints on what I could be missing.Quoted 11 lines
Quoted 11 lines
fs/ceph/xattr.c +4
-0+ } +return true; +} +ssize_t __ceph_getxattr (struct inode *inode,const char *name,void *value,size_t size) {@@ -927,6 +951,16 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,int req_mask;ssize_t err;Quoted 11 lines
fs/ceph/xattr.c ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, · line 963
Quoted 10 lines
fs/ceph/xattr.c +10
-0+if (!strncmp (name,XATTR_CEPH_PREFIX ,XATTR_CEPH_PREFIX_LEN ) && +ceph_cluster_has_feature (inode,CEPHFS_FEATURE_GETVXATTR )) { + err =ceph_do_getvxattr (inode, name, value, size); +/* if cluster doesn't support xattr, we try to service it +* locally +*/ +if (err >=0 ) +return err; + } +What is this? Why not always service this locally?
Quoted 8 lines
vxattr handling is planned to be moved to the MDS side.
As I've pointed out to Xiubo, there's a few new things that have been done for layout vxattr management. Also, as per your original tracker, ceph.dir.pin* can't be handled locally.getvxattr()currently handles:
1. ceph.dir.layout*
2. ceph.file.layout*
3. ceph.dir.pin*Quoted 6 lines
The above seems will include the 'ceph.dir.layout', 'ceph.file.layout' and 'ceph.dir.pin' ? All these have been handled in '
ceph_file_vxattrs' and 'ceph_dir_vxattrs'...And the code above will always force kclient to get all the 'ceph.XXX' xattrs from MDS ?
yes, the kclient will always get vxattr values from MDS for old cluster, op will be handled locally
Jeff has a proposal to expose the JSON output variety of layout vxattr vlaue via new vxattr altogether
eg. ceph.dir.layout_json and ceph.file.layout_jsonQuoted 8 lines
Quoted 2 lines
Yeah, sounds good. Or maybe just adding the '.json' instead of '
_json'.+1 -- that looks cleaner than mixing up delimiters
To be clear, I think this should wholly be a fallback mechanism for when the client doesn't recognize a vxattr name. IOW, we should only call the MDS after
ceph_match_vxattrdoesn't match an xattr name.Quoted 5 lines
I'm with you, but this set of changes (and its Client.cc equivalent) is by request from Patrick and Venky (added), so there may be some subtleties we're missing. And we should follow the same pattern for who gets to resolve vxattrs in both clients.
-GregI had incorrectly recalled that the client did return json for the layout xattrs. So, yes, we can't just switch to json for these existing vxattrs. I agree adding a "json" extension cleanly avoids the issue. We can continue handling the existing layout vxattrs without the suffix in the client (for now).
Quoted 7 lines
Quoted 4 lines
Although, I do think ".json" is a little weird. I had privately expressed to Jeff/Milind that "!json" or similar as a suffix could be more appropriate. It emphasizes it's not a derivative xattr.
The mixed delimiters are also weird, and I don't think it's really outside the scope of the existing ceph.file.layout.* xattrs.
Both are weird to me. I don't have a strong opinion either way.
Quoted 1 line
Also, I have to wonder -- why json? Isn't yaml more en vogue these days?
json is a common format for all ceph commands / utilities.
Signature · 5 lines
Patrick Donnelly, Ph.D. He / Him / His Principal Software Engineer Red Hat, Inc. GPG: 19F28A586F808C2402351B93C3301A3E258DD79D