rbd: header read/refresh improvements
Subsystems (3)
cover rbd: header read/refresh improvements
Support multiple class op calls in one ceph_msg and consolidate rbd header read and refresh processes to use this feature to reduce the number of ceph_msgs sent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.
Douglas Fuller (3):
ceph: support multiple class method calls in one ceph_msg
rbd: combine object method calls in header refresh using fewer
ceph_msgs
rbd: re-read features during header refresh and detect changes.
drivers/block/rbd.c | 518 +++++++++++++++++++++++++++++----------- include/linux/ceph/osd_client.h | 3 +- net/ceph/messenger.c | 4 + net/ceph/osd_client.c | 92 ++++++- 4 files changed, 470 insertions(+), 147 deletions(-)
Signature · 1 line
1.9.3
PATCH 1/3 ceph: support multiple class method calls in one ceph_msg
Messages are received from the wire directly into destination buffers. A short read could result in corruption of the following destination buffers. Allocate a single message buffer for all class method calls and split them at the osd_client level. This only applies to ceph_msgs containing multiple op call and may break support for ceph_msgs containing a mix of class method calls that return data and other ops.
--- include/linux/ceph/osd_client.h | 1 + net/ceph/messenger.c | 4 ++ net/ceph/osd_client.c | 92 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 2 deletions(-)
include/linux/ceph/osd_client.h +1 -0
@@ -99,6 +99,7 @@ struct ceph_osd_req_op {struct ceph_osd_data request_info;struct ceph_osd_data request_data;struct ceph_osd_data response_data; +struct ceph_osd_data chain_data;__u8 class_len;__u8 method_len;__u8 argc;
net/ceph/messenger.c +4 -0
@@ -907,6 +907,10 @@ static void ceph_msg_data_pages_cursor_init(struct ceph_msg_data_cursor *cursor,BUG_ON (!data->pages);BUG_ON (!data->length); +/* +* bug here if a short read occurs and length < data->length; see +* http://tracker.ceph.com/issues/11424 +*/ cursor->resid =min (length, data->length); page_count =calc_pages_for (data->alignment, (u64 )data->length); cursor->page_offset = data->alignment & ~PAGE_MASK ;
net/ceph/osd_client.c +90 -2
110 lines not on this page · raw message
Signature · 1 line
1.9.3
PATCH 2/3 rbd: combine object method calls in header refresh using fewer ceph_msgs
In reply to Douglas Fuller--- drivers/block/rbd.c | 337 ++++++++++++++++++++++++++++++++++++---- include/linux/ceph/osd_client.h | 2 +- 2 files changed, 312 insertions(+), 27 deletions(-)
drivers/block/rbd.c +311 -26
@@ -4577,6 +4577,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)"rbd" ,"get_snapcontext" ,NULL ,0 , reply_buf, size);dout ("%s: rbd_obj_method_sync returned %d\n" , __func__, ret); +printk (KERN_INFO "%s: rbd_obj_method_sync returned %d\n" , __func__, ret);if (ret <0 ) goto out;
@@ -4667,20 +4668,23 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)bool first_time = rbd_dev->header.object_prefix ==NULL ;int ret; - ret =rbd_dev_v2_image_size (rbd_dev); -if (ret) -return ret; +if (!first_time) + { + ret =rbd_dev_v2_image_size (rbd_dev); +if (ret) +return ret; -if (first_time) { + ret =rbd_dev_v2_snap_context (rbd_dev); +dout ("rbd_dev_v2_snap_context returned %d\n" , ret); +return ret; + } +else + { ret =rbd_dev_v2_header_onetime (rbd_dev);if (ret)return ret; } - - ret =rbd_dev_v2_snap_context (rbd_dev); -dout ("rbd_dev_v2_snap_context returned %d\n" , ret); - -return ret; +return ret;/* XXX change logic? */ }static int rbd_dev_header_info (struct rbd_device *rbd_dev)
@@ -5091,36 +5095,317 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)memset (header,0 ,sizeof (*header)); } -static int rbd_dev_v2_header_onetime (struct rbd_device *rbd_dev) +static struct ceph_osd_request *rbd_obj_header_req_alloc ( +struct rbd_device *rbd_dev, +int num_ops) +{ +struct ceph_osd_request *osd_req; +struct page ***replies; + + replies =kmalloc (CEPH_OSD_MAX_OP *sizeof (*replies),GFP_KERNEL ); +if (!replies) +return NULL ; + + osd_req =ceph_osdc_alloc_request (&rbd_dev->rbd_client->client->osdc, +NULL , num_ops, false,GFP_ATOMIC ); +if (!osd_req) + { +kfree (replies); +return NULL ; + } + + osd_req->r_flags =CEPH_OSD_FLAG_READ ; + osd_req->r_base_oloc.pool =ceph_file_layout_pg_pool (rbd_dev->layout); + osd_req->r_priv = (void *)replies; +ceph_oid_set_name (&osd_req->r_base_oid, rbd_dev->header_name); + +return osd_req; +} + +static int rbd_obj_header_method_add (struct ceph_osd_request *osd_req, +int which, +const char *class_name, +const char *method_name, +const void *outbound, +size_t outbound_size, +size_t inbound_size) +{ +u32 page_count; +struct page ***replies = (struct page ***)osd_req->r_priv; + +BUG_ON (which >= osd_req->r_num_ops); + +osd_req_op_cls_init (osd_req, which,CEPH_OSD_OP_CALL , + class_name, method_name); + +if (outbound_size) + { +struct ceph_pagelist *pagelist; + pagelist =kmalloc (sizeof (*pagelist),GFP_NOFS ); +/* XXX is this ever freed? */ +if (!pagelist) +return -ENOMEM ; + +ceph_pagelist_init (pagelist); +ceph_pagelist_append (pagelist, outbound, outbound_size); +osd_req_op_cls_request_data_pagelist (osd_req, which, pagelist); + } + + page_count = (u32 )calc_pages_for (0 , inbound_size); + replies[which] =ceph_alloc_page_vector (page_count,GFP_KERNEL ); +if (IS_ERR (replies[which])) +return PTR_ERR (replies[which]); +osd_req_op_cls_response_data_pages (osd_req, which, replies[which], + inbound_size,0 , false, false); + +return 0 ; +} + +static int rbd_obj_header_req_exec (struct rbd_device * rbd_dev, +struct ceph_osd_request *osd_req) {int ret; - ret =rbd_dev_v2_object_prefix (rbd_dev); +ceph_osdc_build_request (osd_req,0 ,NULL ,cpu_to_le64 (CEPH_NOSNAP ),NULL ); + ret =ceph_osdc_start_request (&rbd_dev->rbd_client->client->osdc, + osd_req, false);if (ret) + { +ceph_osdc_put_request (osd_req); +return ret; + } + + ret =ceph_osdc_wait_request (&rbd_dev->rbd_client->client->osdc, osd_req); +if (ret <0 ) + { +ceph_osdc_cancel_request (osd_req); +return ret; + } + +return 0 ; +} + +static int rbd_obj_header_method_retrieve (struct ceph_osd_request *osd_req, +int which,void *buf,size_t length) +{ +struct page ***replies = (struct page ***)osd_req->r_priv; +size_t reply_length = osd_req->r_reply_op_len[which]; + +BUG_ON (reply_length > length); + +ceph_copy_from_page_vector (replies[which], buf,0 , reply_length); +ceph_release_page_vector (replies[which],calc_pages_for (0 , reply_length)); + +return reply_length; +} + +static void rbd_obj_header_req_destroy (struct ceph_osd_request *osd_req) +{ +if (osd_req) + { +kfree (osd_req->r_priv); +ceph_osdc_put_request (osd_req); + } +} + +static int __extract_prefix (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +void *prefix_buf; +void * p; +size_t prefix_buflen; +int ret; + + prefix_buf =kzalloc (RBD_OBJ_PREFIX_LEN_MAX ,GFP_KERNEL ); +if (!prefix_buf) +return -ENOMEM ; + + prefix_buflen =rbd_obj_header_method_retrieve (osd_req, which, + prefix_buf,RBD_OBJ_PREFIX_LEN_MAX ); + p = prefix_buf; + rbd_dev->header.object_prefix =ceph_extract_encoded_string (&p, + p + prefix_buflen,NULL ,GFP_NOIO ); + +if (IS_ERR (rbd_dev->header.object_prefix)) + { + ret =PTR_ERR (rbd_dev->header.object_prefix); + rbd_dev->header.object_prefix =NULL ; goto out_err; + } -/* -* Get the and check features for the image. Currently the -* features are assumed to never change. -*/ - ret =rbd_dev_v2_features (rbd_dev); -if (ret) + ret =0 ; + +out_err: +kfree (prefix_buf); +return ret; +} + +static int __extract_features (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +int ret; +struct + { +__le64 features; +__le64 incompat; + } __attribute__((packed)) features_buf = {0 }; +u64 incompat; + +rbd_obj_header_method_retrieve (osd_req, which, + &features_buf,sizeof (features_buf)); + incompat =le64_to_cpu (features_buf.incompat); +if (incompat & ~RBD_FEATURES_SUPPORTED ) + { + ret = -ENXIO ; goto out_err; + } + rbd_dev->header.features =le64_to_cpu (features_buf.features); -/* If the image supports fancy striping, get its parameters */ + ret =0 ; -if (rbd_dev->header.features &RBD_FEATURE_STRIPINGV2 ) { - ret =rbd_dev_v2_striping_info (rbd_dev); -if (ret <0 ) - goto out_err; +out_err: +return ret; +} + +static int __extract_snapcontext (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +void *snapc_buf; +size_t snapc_max; +size_t snapc_buflen; + +void *p; +void *q; + +struct ceph_snap_context * snapc; + +u32 seq; +u32 snap_count; + +int i; +int ret; + + snapc_max =sizeof (__le64) +sizeof (__le32) + +RBD_MAX_SNAP_COUNT *sizeof (__le64); + + snapc_buf =kzalloc (snapc_max,GFP_KERNEL ); +BUG_ON (!snapc_buf); + + snapc_buflen =rbd_obj_header_method_retrieve (osd_req, which, + snapc_buf, snapc_max); + + p = snapc_buf; + q = snapc_buf + snapc_buflen; + ret = -ERANGE ; +ceph_decode_64_safe (&p, q, seq, out_err); +ceph_decode_32_safe (&p, q, snap_count, out_err); + +if (snap_count > (SIZE_MAX -sizeof (struct ceph_snap_context )) / +sizeof (u64)) + { + ret = -EINVAL ; + goto out_err; } -/* No support for crypto and compression type format 2 images */ +if (!ceph_has_room (&p, q, snap_count *sizeof (__le64))) + goto out_err; + + snapc =ceph_create_snap_context (snap_count,GFP_KERNEL ); +BUG_ON (!snapc); + snapc->seq = seq; +for (i=0 ; i < snap_count; i++) + snapc->snaps[i] =ceph_decode_64 (&p); +ceph_put_snap_context (rbd_dev->header.snapc); + rbd_dev->header.snapc = snapc; + + ret =0 ; +out_err: +kfree (snapc_buf); +return ret; +} + +static int __extract_size (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +struct + { +u8 order; +__le64 size; + } __attribute((packed)) size_buf = {0 }; + +rbd_obj_header_method_retrieve (osd_req, which, &size_buf,sizeof (size_buf)); + + rbd_dev->header.obj_order = size_buf.order; + rbd_dev->header.image_size =le64_to_cpu (size_buf.size);return 0 ; +} + +static int rbd_dev_v2_header_onetime (struct rbd_device *rbd_dev) +{ +int ret; + +size_t snapc_max; +__le64 snapid =cpu_to_le64 (CEPH_NOSNAP ); +struct ceph_osd_request *osd_req; + + snapc_max =sizeof (__le64) +sizeof (__le32) + +RBD_MAX_SNAP_COUNT *sizeof (__le64); + + osd_req =rbd_obj_header_req_alloc (rbd_dev,4 ); + +if (!osd_req) + { + ret = -ENOMEM ; + goto out_err; + } + + ret =rbd_obj_header_method_add (osd_req,0 , +"rbd" ,"get_object_prefix" , +NULL ,0 ,RBD_OBJ_PREFIX_LEN_MAX ); +if (ret) + goto out_err; + + ret =rbd_obj_header_method_add (osd_req,1 , +"rbd" ,"get_features" , + &snapid,sizeof (snapid), +sizeof (struct {__le64 features;__le64 incompat;} __attribute__((packed)))); +if (ret) + goto out_err; + + ret =rbd_obj_header_method_add (osd_req,2 , +"rbd" ,"get_snapcontext" , +NULL ,0 , snapc_max); +if (ret) + goto out_err; + + ret =rbd_obj_header_method_add (osd_req,3 , +"rbd" ,"get_size" , + &snapid,sizeof (snapid), +sizeof (struct {u8 order;__le64 size;}__attribute((packed)))); +if (ret) + goto out_err; + + ret =rbd_obj_header_req_exec (rbd_dev, osd_req); +if (ret) + goto out_err; + +if ((ret =__extract_prefix (rbd_dev, osd_req,0 ))) + goto out_err; +if ((ret =__extract_features (rbd_dev, osd_req,1 ))) + goto out_err; +if ((ret =__extract_snapcontext (rbd_dev, osd_req,2 ))) + goto out_err; +if ((ret =__extract_size (rbd_dev, osd_req,3 ))) + goto out_err; + + ret =0 ; + out_err: - rbd_dev->header.features =0 ; -kfree (rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix =NULL ; +rbd_obj_header_req_destroy (osd_req);return ret; }
include/linux/ceph/osd_client.h +1 -1
@@ -43,7 +43,7 @@ struct ceph_osd { }; -#define CEPH_OSD_MAX_OP 3 +#define CEPH_OSD_MAX_OP 4enum ceph_osd_data_type {CEPH_OSD_DATA_TYPE_NONE =0 ,
Signature · 1 line
1.9.3
Re: [PATCH 2/3] rbd: combine object method calls in header refresh using fewer ceph_msgs
Quoted 11 lines · Douglas Fuller
Signed-off-by Douglas Fuller <[email protected]>--- drivers/block/rbd.c | 337 ++++++++++++++++++++++++++++++++++++---- include/linux/ceph/osd_client.h | 2 +- 2 files changed, 312 insertions(+), 27 deletions(-)drivers/block/rbd.c +0
-0
drivers/block/rbd.c static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev) · line 4580
Quoted 4 lines
drivers/block/rbd.c +1
-0@@ -4577,6 +4577,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)"rbd" ,"get_snapcontext" ,NULL ,0 , reply_buf, size);dout ("%s: rbd_obj_method_sync returned %d\n" , __func__, ret); +printk (KERN_INFO "%s: rbd_obj_method_sync returned %d\n" , __func__, ret);
You probably forgot to remove that debug printk.
drivers/block/rbd.c static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) · line 4672
Quoted 12 lines
drivers/block/rbd.c +2
-3if (ret <0 ) goto out;@@ -4667,20 +4668,23 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)bool first_time = rbd_dev->header.object_prefix ==NULL ;int ret; - ret =rbd_dev_v2_image_size (rbd_dev); -if (ret) -return ret; +if (!first_time) + {
You want to follow the coding style in the existing code or follow the style in Documentation/CodingStyle. The {} use in your if/elses do not follow either one.
Quoted 32 lines
drivers/block/rbd.c +13
-7+ ret =rbd_dev_v2_image_size (rbd_dev); +if (ret) +return ret; -if (first_time) { + ret =rbd_dev_v2_snap_context (rbd_dev); +dout ("rbd_dev_v2_snap_context returned %d\n" , ret); +return ret; + } +else + { ret =rbd_dev_v2_header_onetime (rbd_dev);if (ret)return ret; } - - ret =rbd_dev_v2_snap_context (rbd_dev); -dout ("rbd_dev_v2_snap_context returned %d\n" , ret); - -return ret; +return ret;/* XXX change logic? */ }static int rbd_dev_header_info (struct rbd_device *rbd_dev)@@ -5091,36 +5095,317 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)memset (header,0 ,sizeof (*header)); } -static int rbd_dev_v2_header_onetime (struct rbd_device *rbd_dev) +static struct ceph_osd_request *rbd_obj_header_req_alloc ( +struct rbd_device *rbd_dev, +int num_ops)
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5110
Quoted 10 lines
drivers/block/rbd.c +10
-0+{ +struct ceph_osd_request *osd_req; +struct page ***replies; + + replies =kmalloc (CEPH_OSD_MAX_OP *sizeof (*replies),GFP_KERNEL ); +if (!replies) +return NULL ; + + osd_req =ceph_osdc_alloc_request (&rbd_dev->rbd_client->client->osdc, +NULL , num_ops, false,GFP_ATOMIC );
I think you can just use GFP_KERNEL here. You used it above and it looks like we have process context and are not under any locks.
You might have to use GFP_NOIO if we think that these functions are called from the watch_cb for something like a resize and we need to update the rbd_dev's size before we can execute IO. I do not think that is the case though, so I think GFP_KERNEL is ok.
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5119
Quoted 9 lines
drivers/block/rbd.c +9
-0+if (!osd_req) + { +kfree (replies); +return NULL ; + } + + osd_req->r_flags =CEPH_OSD_FLAG_READ ; + osd_req->r_base_oloc.pool =ceph_file_layout_pg_pool (rbd_dev->layout); + osd_req->r_priv = (void *)replies;
No need to cast to a void pointer.
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5131
Quoted 12 lines
drivers/block/rbd.c +12
-0+ceph_oid_set_name (&osd_req->r_base_oid, rbd_dev->header_name); + +return osd_req; +} + +static int rbd_obj_header_method_add (struct ceph_osd_request *osd_req, +int which, +const char *class_name, +const char *method_name, +const void *outbound, +size_t outbound_size, +size_t inbound_size)
I think you want to follow the existing code's tab style for function arguments.
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5134
Quoted 3 lines
drivers/block/rbd.c +3
-0+{ +u32 page_count; +struct page ***replies = (struct page ***)osd_req->r_priv;
Don't need to cast from a void pointer.
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5144
Quoted 10 lines
drivers/block/rbd.c +10
-0+ +BUG_ON (which >= osd_req->r_num_ops); + +osd_req_op_cls_init (osd_req, which,CEPH_OSD_OP_CALL , + class_name, method_name); + +if (outbound_size) + { +struct ceph_pagelist *pagelist; + pagelist =kmalloc (sizeof (*pagelist),GFP_NOFS );
I think you can use GFP_KERNEL here. You used it below.
If you cannot use GFP_KERNEL, then you really want to be using GFP_NOIO instead of GFP_NOFS.
Quoted 75 lines
drivers/block/rbd.c +70
-1+/* XXX is this ever freed? */ +if (!pagelist) +return -ENOMEM ; + +ceph_pagelist_init (pagelist); +ceph_pagelist_append (pagelist, outbound, outbound_size); +osd_req_op_cls_request_data_pagelist (osd_req, which, pagelist); + } + + page_count = (u32 )calc_pages_for (0 , inbound_size); + replies[which] =ceph_alloc_page_vector (page_count,GFP_KERNEL ); +if (IS_ERR (replies[which])) +return PTR_ERR (replies[which]); +osd_req_op_cls_response_data_pages (osd_req, which, replies[which], + inbound_size,0 , false, false); + +return 0 ; +} + +static int rbd_obj_header_req_exec (struct rbd_device * rbd_dev, +struct ceph_osd_request *osd_req) {int ret; - ret =rbd_dev_v2_object_prefix (rbd_dev); +ceph_osdc_build_request (osd_req,0 ,NULL ,cpu_to_le64 (CEPH_NOSNAP ),NULL ); + ret =ceph_osdc_start_request (&rbd_dev->rbd_client->client->osdc, + osd_req, false);if (ret) + { +ceph_osdc_put_request (osd_req); +return ret; + } + + ret =ceph_osdc_wait_request (&rbd_dev->rbd_client->client->osdc, osd_req); +if (ret <0 ) + { +ceph_osdc_cancel_request (osd_req); +return ret; + } + +return 0 ; +} + +static int rbd_obj_header_method_retrieve (struct ceph_osd_request *osd_req, +int which,void *buf,size_t length) +{ +struct page ***replies = (struct page ***)osd_req->r_priv; +size_t reply_length = osd_req->r_reply_op_len[which]; + +BUG_ON (reply_length > length); + +ceph_copy_from_page_vector (replies[which], buf,0 , reply_length); +ceph_release_page_vector (replies[which],calc_pages_for (0 , reply_length)); + +return reply_length; +} + +static void rbd_obj_header_req_destroy (struct ceph_osd_request *osd_req) +{ +if (osd_req) + { +kfree (osd_req->r_priv); +ceph_osdc_put_request (osd_req); + } +} + +static int __extract_prefix (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +void *prefix_buf; +void * p; +size_t prefix_buflen; +int ret;
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5228
Quoted 10 lines
drivers/block/rbd.c +10
-0+ + prefix_buf =kzalloc (RBD_OBJ_PREFIX_LEN_MAX ,GFP_KERNEL ); +if (!prefix_buf) +return -ENOMEM ; + + prefix_buflen =rbd_obj_header_method_retrieve (osd_req, which, + prefix_buf,RBD_OBJ_PREFIX_LEN_MAX ); + p = prefix_buf; + rbd_dev->header.object_prefix =ceph_extract_encoded_string (&p, + p + prefix_buflen,NULL ,GFP_NOIO );
I think this can be GFP_KERNEL like above.
Quoted 68 lines
drivers/block/rbd.c +52
-11+ +if (IS_ERR (rbd_dev->header.object_prefix)) + { + ret =PTR_ERR (rbd_dev->header.object_prefix); + rbd_dev->header.object_prefix =NULL ; goto out_err; + } -/* -* Get the and check features for the image. Currently the -* features are assumed to never change. -*/ - ret =rbd_dev_v2_features (rbd_dev); -if (ret) + ret =0 ; + +out_err: +kfree (prefix_buf); +return ret; +} + +static int __extract_features (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +int ret; +struct + { +__le64 features; +__le64 incompat; + } __attribute__((packed)) features_buf = {0 }; +u64 incompat; + +rbd_obj_header_method_retrieve (osd_req, which, + &features_buf,sizeof (features_buf)); + incompat =le64_to_cpu (features_buf.incompat); +if (incompat & ~RBD_FEATURES_SUPPORTED ) + { + ret = -ENXIO ; goto out_err; + } + rbd_dev->header.features =le64_to_cpu (features_buf.features); -/* If the image supports fancy striping, get its parameters */ + ret =0 ; -if (rbd_dev->header.features &RBD_FEATURE_STRIPINGV2 ) { - ret =rbd_dev_v2_striping_info (rbd_dev); -if (ret <0 ) - goto out_err; +out_err: +return ret; +} + +static int __extract_snapcontext (struct rbd_device *rbd_dev, +struct ceph_osd_request *osd_req, +int which) +{ +void *snapc_buf; +size_t snapc_max; +size_t snapc_buflen; + +void *p; +void *q; + +struct ceph_snap_context * snapc; + +u32 seq;
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5295
Quoted 10 lines
drivers/block/rbd.c +10
-0+u32 snap_count; + +int i; +int ret; + + snapc_max =sizeof (__le64) +sizeof (__le32) + +RBD_MAX_SNAP_COUNT *sizeof (__le64); + + snapc_buf =kzalloc (snapc_max,GFP_KERNEL ); +BUG_ON (!snapc_buf);
Why a BUG_ON for a allocation failure?
Quoted 12 lines
drivers/block/rbd.c +12
-0+ + snapc_buflen =rbd_obj_header_method_retrieve (osd_req, which, + snapc_buf, snapc_max); + + p = snapc_buf; + q = snapc_buf + snapc_buflen; + ret = -ERANGE ; +ceph_decode_64_safe (&p, q, seq, out_err); +ceph_decode_32_safe (&p, q, snap_count, out_err); + +if (snap_count > (SIZE_MAX -sizeof (struct ceph_snap_context )) / +sizeof (u64))
drivers/block/rbd.c static void rbd_dev_unprobe(struct rbd_device *rbd_dev) · line 5316
Quoted 10 lines
drivers/block/rbd.c +8
-1+ { + ret = -EINVAL ; + goto out_err; } -/* No support for crypto and compression type format 2 images */ +if (!ceph_has_room (&p, q, snap_count *sizeof (__le64))) + goto out_err; + + snapc =ceph_create_snap_context (snap_count,GFP_KERNEL ); +BUG_ON (!snapc);
Again why a BUG_ON?
I think it is best to handle it gracefully. There is no need to kill the box for a allocation failure.
PATCH 3/3 rbd: re-read features during header refresh and detect changes.
In reply to Douglas FullerFrom: Douglas Fuller <[email protected]>
Add a new header item to track when features have changed since mapping and return EIO on I/O operations. Clean up and consolidate code path for header read and update. Remove unused code.
--- drivers/block/rbd.c | 209 +++++++++++++++++++--------------------------------- 1 file changed, 77 insertions(+), 132 deletions(-)
drivers/block/rbd.c +77 -132
@@ -320,9 +320,17 @@ struct rbd_img_request {#define for_each_obj_request_safe (ireq, oreq, n) \ list_for_each_entry_safe_reverse(oreq, n, &(ireq)->obj_requests, links) +enum rbd_mapping_state +{ +MAP_STATE_MAPPED , +MAP_STATE_DETACHED , +}; + +struct rbd_mapping {u64 size;u64 features; +enum rbd_mapping_state state;bool read_only; };
@@ -527,7 +535,7 @@ static void rbd_img_parent_read(struct rbd_obj_request *obj_request);static void rbd_dev_remove_parent (struct rbd_device *rbd_dev);static int rbd_dev_refresh (struct rbd_device *rbd_dev); -static int rbd_dev_v2_header_onetime (struct rbd_device *rbd_dev); +static int rbd_dev_v2_header_data (struct rbd_device *rbd_dev);static int rbd_dev_header_info (struct rbd_device *rbd_dev);static int rbd_dev_v2_parent_info (struct rbd_device *rbd_dev); static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
@@ -3336,6 +3344,14 @@ static void rbd_queue_workfn(struct work_struct *work)else op_type =OBJ_OP_READ ; +/* If a configuration change was detected, issue EIO. */ + +if (rbd_dev->mapping.state ==MAP_STATE_DETACHED ) + { + result = -EIO ; + goto err_rq; + } +/* Ignore/skip any zero-length requests */ if (!length) {
@@ -3670,12 +3686,23 @@ static void rbd_dev_update_size(struct rbd_device *rbd_dev)static int rbd_dev_refresh (struct rbd_device *rbd_dev) {u64 mapping_size; +u64 features;int ret;down_write (&rbd_dev->header_rwsem); mapping_size = rbd_dev->mapping.size; + features = rbd_dev->mapping.features; ret =rbd_dev_header_info (rbd_dev); + +if (ret == -ENXIO || (ret && features != rbd_dev->mapping.features)) + { + rbd_dev->mapping.read_only =1 ; + rbd_dev->mapping.state =MAP_STATE_DETACHED ; +rbd_warn (rbd_dev, +"detected feature change in mapped device, setting read-only" ); + } +if (ret) goto out;
@@ -3698,6 +3725,9 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev) out:up_write (&rbd_dev->header_rwsem); + +if (rbd_dev->mapping.read_only) +set_disk_ro (rbd_dev->disk,1 );if (!ret && mapping_size != rbd_dev->mapping.size)rbd_dev_update_size (rbd_dev);
@@ -4111,47 +4141,6 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,return 0 ; } -static int rbd_dev_v2_image_size (struct rbd_device *rbd_dev) -{ -return _rbd_dev_v2_snap_size (rbd_dev,CEPH_NOSNAP , - &rbd_dev->header.obj_order, - &rbd_dev->header.image_size); -} - -static int rbd_dev_v2_object_prefix (struct rbd_device *rbd_dev) -{ -void *reply_buf; -int ret; -void *p; - - reply_buf =kzalloc (RBD_OBJ_PREFIX_LEN_MAX ,GFP_KERNEL ); -if (!reply_buf) -return -ENOMEM ; - - ret =rbd_obj_method_sync (rbd_dev, rbd_dev->header_name, -"rbd" ,"get_object_prefix" ,NULL ,0 , - reply_buf,RBD_OBJ_PREFIX_LEN_MAX ); -dout ("%s: rbd_obj_method_sync returned %d\n" , __func__, ret); -if (ret <0 ) - goto out; - - p = reply_buf; - rbd_dev->header.object_prefix =ceph_extract_encoded_string (&p, - p + ret,NULL ,GFP_NOIO ); - ret =0 ; - -if (IS_ERR (rbd_dev->header.object_prefix)) { - ret =PTR_ERR (rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix =NULL ; - }else { -dout (" object_prefix = %s\n" , rbd_dev->header.object_prefix); - } -out: -kfree (reply_buf); - -return ret; -} -static int _rbd_dev_v2_snap_features (struct rbd_device *rbd_dev,u64 snap_id,u64 *snap_features) {
@@ -4187,12 +4176,6 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,return 0 ; } -static int rbd_dev_v2_features (struct rbd_device *rbd_dev) -{ -return _rbd_dev_v2_snap_features (rbd_dev,CEPH_NOSNAP , - &rbd_dev->header.features); -} -static int rbd_dev_v2_parent_info (struct rbd_device *rbd_dev) {struct rbd_spec *parent_spec;
@@ -4549,79 +4532,6 @@ out_err:return ret; } -static int rbd_dev_v2_snap_context (struct rbd_device *rbd_dev) -{ -size_t size; -int ret; -void *reply_buf; -void *p; -void *end; -u64 seq; -u32 snap_count; -struct ceph_snap_context *snapc; -u32 i; - -/* -* We'll need room for the seq value (maximum snapshot id), -* snapshot count, and array of that many snapshot ids. -* For now we have a fixed upper limit on the number we're -* prepared to receive. -*/ - size =sizeof (__le64) +sizeof (__le32) + -RBD_MAX_SNAP_COUNT *sizeof (__le64); - reply_buf =kzalloc (size,GFP_KERNEL ); -if (!reply_buf) -return -ENOMEM ; - - ret =rbd_obj_method_sync (rbd_dev, rbd_dev->header_name, -"rbd" ,"get_snapcontext" ,NULL ,0 , - reply_buf, size); -dout ("%s: rbd_obj_method_sync returned %d\n" , __func__, ret); -printk (KERN_INFO "%s: rbd_obj_method_sync returned %d\n" , __func__, ret); -if (ret <0 ) - goto out; - - p = reply_buf; - end = reply_buf + ret; - ret = -ERANGE ; -ceph_decode_64_safe (&p, end, seq, out); -ceph_decode_32_safe (&p, end, snap_count, out); - -/* -* Make sure the reported number of snapshot ids wouldn't go -* beyond the end of our buffer. But before checking that, -* make sure the computed size of the snapshot context we -* allocate is representable in a size_t. -*/ -if (snap_count > (SIZE_MAX -sizeof (struct ceph_snap_context )) - /sizeof (u64)) { - ret = -EINVAL ; - goto out; - } -if (!ceph_has_room (&p, end, snap_count *sizeof (__le64))) - goto out; - ret =0 ; - - snapc =ceph_create_snap_context (snap_count,GFP_KERNEL ); -if (!snapc) { - ret = -ENOMEM ; - goto out; - } - snapc->seq = seq; -for (i =0 ; i < snap_count; i++) - snapc->snaps[i] =ceph_decode_64 (&p); - -ceph_put_snap_context (rbd_dev->header.snapc); - rbd_dev->header.snapc = snapc; - -dout (" snap context seq = %llu, snap_count = %u\n" , - (unsigned long long )seq, (unsigned int )snap_count); -out: -kfree (reply_buf); - -return ret; -} -static const char *rbd_dev_v2_snap_name (struct rbd_device *rbd_dev,u64 snap_id) {
@@ -4663,6 +4573,16 @@ out:return snap_name; } +static int rbd_dev_v2_mutable_metadata (struct rbd_device *rbd_dev) +{ +return rbd_dev_v2_header_data (rbd_dev); +} + +static int rbd_dev_v2_immutable_metadata (struct rbd_device *rbd_dev) +{ +return rbd_dev_v2_header_data (rbd_dev); +} +static int rbd_dev_v2_header_info (struct rbd_device *rbd_dev) {bool first_time = rbd_dev->header.object_prefix ==NULL ;
@@ -4670,27 +4590,39 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)if (!first_time) { - ret =rbd_dev_v2_image_size (rbd_dev); + ret =rbd_dev_v2_mutable_metadata (rbd_dev);if (ret) -return ret; - - ret =rbd_dev_v2_snap_context (rbd_dev); -dout ("rbd_dev_v2_snap_context returned %d\n" , ret); -return ret; + goto out_err; }else { - ret =rbd_dev_v2_header_onetime (rbd_dev); + ret =rbd_dev_v2_immutable_metadata (rbd_dev);if (ret) -return ret; + goto out_err; } -return ret;/* XXX change logic? */ + +if (rbd_dev->header.features &RBD_FEATURE_STRIPINGV2 ) + { + ret =rbd_dev_v2_striping_info (rbd_dev); +if (ret) + goto out_err; + } + + ret =0 ; +out_err: + rbd_dev->header.features =0 ; +kfree (rbd_dev->header.object_prefix); + rbd_dev->header.object_prefix =NULL ; + +return ret; }static int rbd_dev_header_info (struct rbd_device *rbd_dev) {rbd_assert (rbd_image_format_valid (rbd_dev->image_format)); +/* XXX need to fix 11418 here too? */ +if (rbd_dev->image_format ==1 )return rbd_dev_v1_header_info (rbd_dev);
@@ -5142,7 +5074,6 @@ static int rbd_obj_header_method_add(struct ceph_osd_request *osd_req, {struct ceph_pagelist *pagelist; pagelist =kmalloc (sizeof (*pagelist),GFP_NOFS ); -/* XXX is this ever freed? */ if (!pagelist)return -ENOMEM ;
@@ -5288,6 +5219,12 @@ static int __extract_snapcontext(struct rbd_device *rbd_dev,int i;int ret; +/* +* We'll need room for the seq value (maximum snapshot id), +* snapshot count, and array of that many snapshot ids. +* For now we have a fixed upper limit on the number we're +* prepared to receive. +*/ snapc_max =sizeof (__le64) +sizeof (__le32) +RBD_MAX_SNAP_COUNT *sizeof (__le64);
@@ -5303,6 +5240,12 @@ static int __extract_snapcontext(struct rbd_device *rbd_dev,ceph_decode_64_safe (&p, q, seq, out_err);ceph_decode_32_safe (&p, q, snap_count, out_err); +/* +* Make sure the reported number of snapshot ids wouldn't go +* beyond the end of our buffer. But before checking that, +* make sure the computed size of the snapshot context we +* allocate is representable in a size_t. +*/ if (snap_count > (SIZE_MAX -sizeof (struct ceph_snap_context )) /sizeof (u64)) {
@@ -5344,7 +5287,7 @@ static int __extract_size(struct rbd_device *rbd_dev,return 0 ; } -static int rbd_dev_v2_header_onetime (struct rbd_device *rbd_dev) +static int rbd_dev_v2_header_data (struct rbd_device *rbd_dev) {int ret;
@@ -5718,6 +5661,8 @@ static ssize_t do_rbd_add(struct bus_type *bus, read_only = true; rbd_dev->mapping.read_only = read_only; + rbd_dev->mapping.state =MAP_STATE_MAPPED ; + rc =rbd_dev_device_setup (rbd_dev);if (rc) {/*
Signature · 1 line
1.9.3
Quoted 11 lines · Douglas Fuller
Support multiple class op calls in one
ceph_msgand consolidate rbd header read and refresh processes to use this feature to reduce the number ofceph_msgssent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.Douglas Fuller (3):
ceph: support multiple class method calls in oneceph_msg
rbd: combine object method calls in header refresh using fewer
ceph_msgs
rbd: re-read features during header refresh and detect changes.
Quoted 6 lines
drivers/block/rbd.c | 518 +++++++++++++++++++++++++++++----------- include/linux/ceph/osd_client.h | 3 +- net/ceph/messenger.c | 4 + net/ceph/osd_client.c | 92 ++++++- 4 files changed, 470 insertions(+), 147 deletions(-)
In case Ilya or others don't get to it soon, I plan to review this series tomorrow.
-Alex
Quoted 22 lines · Alex Elder
Quoted 11 lines · Douglas Fuller
Support multiple class op calls in one
ceph_msgand consolidate rbd header read and refresh processes to use this feature to reduce the number ofceph_msgssent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.Douglas Fuller (3):
ceph: support multiple class method calls in oneceph_msg
rbd: combine object method calls in header refresh using fewer
ceph_msgs
rbd: re-read features during header refresh and detect changes.Quoted 6 lines
drivers/block/rbd.c | 518 +++++++++++++++++++++++++++++----------- include/linux/ceph/osd_client.h | 3 +- net/ceph/messenger.c | 4 + net/ceph/osd_client.c | 92 ++++++- 4 files changed, 470 insertions(+), 147 deletions(-)
Quoted 4 lines
In case Ilya or others don't get to it soon, I plan to review this series tomorrow.
-Alex
Much appreciated. I sent an update this morning, as well.
—Doug--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Ilya Dryomov
maintainerQuoted 21 lines · Alex Elder
Quoted 12 lines · Douglas Fuller
Support multiple class op calls in one
ceph_msgand consolidate rbd header read and refresh processes to use this feature to reduce the number ofceph_msgssent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.Douglas Fuller (3):
ceph: support multiple class method calls in oneceph_msg
rbd: combine object method calls in header refresh using fewer
ceph_msgs
rbd: re-read features during header refresh and detect changes.Quoted 7 lines
drivers/block/rbd.c | 518 +++++++++++++++++++++++++++++----------- include/linux/ceph/osd_client.h | 3 +- net/ceph/messenger.c | 4 + net/ceph/osd_client.c | 92 ++++++- 4 files changed, 470 insertions(+), 147 deletions(-)
Quoted 2 lines
In case Ilya or others don't get to it soon, I plan to review this series tomorrow.
I was planning take a look while I'm the road during the weekend.
Doug, from a quick look this revision still has a bunch of style issues, most notably the alignment of function parameters and braces around if / else. See Documentation/CodingStyle in the kernel tree for examples.
You might also want to run your patches through scripts/checkpatch.pl, but take it with a grain of salt - it can be a bit too extreme at times. No need to post v3 with just style fixes, wait for more feedback.
Thanks,
Ilya
Quoted 28 lines · Ilya Dryomov
Quoted 21 lines · Alex Elder
Quoted 12 lines · Douglas Fuller
Support multiple class op calls in one
ceph_msgand consolidate rbd header read and refresh processes to use this feature to reduce the number ofceph_msgssent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.Douglas Fuller (3):
ceph: support multiple class method calls in oneceph_msg
rbd: combine object method calls in header refresh using fewer
ceph_msgs
rbd: re-read features during header refresh and detect changes.Quoted 7 lines
drivers/block/rbd.c | 518 +++++++++++++++++++++++++++++----------- include/linux/ceph/osd_client.h | 3 +- net/ceph/messenger.c | 4 + net/ceph/osd_client.c | 92 ++++++- 4 files changed, 470 insertions(+), 147 deletions(-)Quoted 2 lines
In case Ilya or others don't get to it soon, I plan to review this series tomorrow.
Quoted 6 lines
I was planning take a look while I'm the road during the weekend.
Doug, from a quick look this revision still has a bunch of style issues, most notably the alignment of function parameters and braces around if / else. See
Documentation/CodingStylein the kernel tree for examples.
I needed to put out v2 in part because I squashed a couple fixup commits in the wrong place, leaving some things behind in #2 that were corrected in #3.
I changed the braces in that version, but the function parameter indents are inconsistent throughout the code. I’ll try to come up with a compromise.
Quoted 4 lines
You might also want to run your patches through
scripts/checkpatch.pl, but take it with a grain of salt - it can be a bit too extreme at times. No need to post v3 with just style fixes, wait for more feedback.
Thanks again for all feedback.
Quoted 4 lines
Thanks,
Ilya
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 36 lines · Douglas Fuller
Quoted 29 lines
On Apr 24, 2015, at 10:17 AM, Ilya Dryomov <[email protected]> wrote:
Quoted 20 lines · Alex Elder
Quoted 12 lines · Douglas Fuller
Support multiple class op calls in one
ceph_msgand consolidate rbd header read and refresh processes to use this feature to reduce the number ofceph_msgssent for that process. Refresh features on header refresh and begin returning EIO if features have changed since mapping.Douglas Fuller (3): ceph: support multiple class method calls in one
ceph_msgrbd: combine object method calls in header refresh using fewerceph_msgsrbd: re-read features during header refresh and detect changes.Quoted 6 lines
drivers/block/rbd.c| 518
+++++++++++++++++++++++++++++-----------include/linux/ceph/osd_client.h| 3 +-net/ceph/messenger.c
| 4 +net/ceph/osd_client.c| 92 ++++++- 4 files
changed, 470 insertions(+), 147 deletions(-)Quoted 2 lines
In case Ilya or others don't get to it soon, I plan to review this series tomorrow.
Quoted 6 lines
I was planning take a look while I'm the road during the weekend.
Doug, from a quick look this revision still has a bunch of style issues, most notably the alignment of function parameters and braces around if / else. See
Documentation/CodingStylein the kernel tree for examples.
Quoted 7 lines
I needed to put out v2 in part because I squashed a couple fixup commits in the wrong place, leaving some things behind in #2 that were corrected in #3.
I changed the braces in that version, but the function parameter indents are inconsistent throughout the code. I’ll try to come up with a compromise.
When in doubt, lean toward the style used in the rest of the kernel. I used a few conventions that are not consistent with that in a lot of places, and those can be gradually phased toward what's recommended for the kernel. Some examples are:
sizeof x or sizeof (x) --> sizeof(x)
(cast) foo --> (cast)foo
White space under comment blocks
static int\nfunction(...) -> static int function(...)
-AlexQuoted 13 lines
Quoted 5 lines
You might also want to run your patches through
scripts/checkpatch.pl, but take it with a grain of salt - it can be a bit too extreme at times. No need to post v3 with just style fixes, wait for more feedback.Thanks again for all feedback.
Quoted 4 lines
Thanks,
Ilya
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html