aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/rbd.c89
1 files changed, 79 insertions, 10 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index aa95227fdee2..4befd8f6ac9c 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -221,22 +221,32 @@ enum obj_operation_type {
221 * Writes go through the following state machine to deal with 221 * Writes go through the following state machine to deal with
222 * layering: 222 * layering:
223 * 223 *
224 * need copyup 224 * . . . . . RBD_OBJ_WRITE_GUARD. . . . . . . . . . . . . .
225 * RBD_OBJ_WRITE_GUARD ---------------> RBD_OBJ_WRITE_COPYUP 225 * . | .
226 * | ^ | 226 * . v .
227 * v \------------------------------/ 227 * . RBD_OBJ_WRITE_READ_FROM_PARENT. . . .
228 * done 228 * . | . .
229 * ^ 229 * . v v (deep-copyup .
230 * | 230 * (image . RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC . not needed) .
231 * RBD_OBJ_WRITE_FLAT 231 * flattened) v | . .
232 * . v . .
233 * . . . .RBD_OBJ_WRITE_COPYUP_OPS. . . . . (copyup .
234 * | not needed) v
235 * v .
236 * done . . . . . . . . . . . . . . . . . .
237 * ^
238 * |
239 * RBD_OBJ_WRITE_FLAT
232 * 240 *
233 * Writes start in RBD_OBJ_WRITE_GUARD or _FLAT, depending on whether 241 * Writes start in RBD_OBJ_WRITE_GUARD or _FLAT, depending on whether
234 * there is a parent or not. 242 * assert_exists guard is needed or not (in some cases it's not needed
243 * even if there is a parent).
235 */ 244 */
236enum rbd_obj_write_state { 245enum rbd_obj_write_state {
237 RBD_OBJ_WRITE_FLAT = 1, 246 RBD_OBJ_WRITE_FLAT = 1,
238 RBD_OBJ_WRITE_GUARD, 247 RBD_OBJ_WRITE_GUARD,
239 RBD_OBJ_WRITE_READ_FROM_PARENT, 248 RBD_OBJ_WRITE_READ_FROM_PARENT,
249 RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC,
240 RBD_OBJ_WRITE_COPYUP_OPS, 250 RBD_OBJ_WRITE_COPYUP_OPS,
241}; 251};
242 252
@@ -422,6 +432,10 @@ static DEFINE_IDA(rbd_dev_id_ida);
422 432
423static struct workqueue_struct *rbd_wq; 433static struct workqueue_struct *rbd_wq;
424 434
435static struct ceph_snap_context rbd_empty_snapc = {
436 .nref = REFCOUNT_INIT(1),
437};
438
425/* 439/*
426 * single-major requires >= 0.75 version of userspace rbd utility. 440 * single-major requires >= 0.75 version of userspace rbd utility.
427 */ 441 */
@@ -2461,6 +2475,38 @@ static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes)
2461 2475
2462#define MODS_ONLY U32_MAX 2476#define MODS_ONLY U32_MAX
2463 2477
2478static int rbd_obj_issue_copyup_empty_snapc(struct rbd_obj_request *obj_req,
2479 u32 bytes)
2480{
2481 int ret;
2482
2483 dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
2484 rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT);
2485 rbd_assert(bytes > 0 && bytes != MODS_ONLY);
2486 rbd_osd_req_destroy(obj_req->osd_req);
2487
2488 obj_req->osd_req = __rbd_osd_req_create(obj_req, &rbd_empty_snapc, 1);
2489 if (!obj_req->osd_req)
2490 return -ENOMEM;
2491
2492 ret = osd_req_op_cls_init(obj_req->osd_req, 0, "rbd", "copyup");
2493 if (ret)
2494 return ret;
2495
2496 osd_req_op_cls_request_data_bvecs(obj_req->osd_req, 0,
2497 obj_req->copyup_bvecs,
2498 obj_req->copyup_bvec_count,
2499 bytes);
2500 rbd_osd_req_format_write(obj_req);
2501
2502 ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
2503 if (ret)
2504 return ret;
2505
2506 rbd_obj_request_submit(obj_req);
2507 return 0;
2508}
2509
2464static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes) 2510static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
2465{ 2511{
2466 struct rbd_img_request *img_req = obj_req->img_request; 2512 struct rbd_img_request *img_req = obj_req->img_request;
@@ -2469,7 +2515,8 @@ static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
2469 int ret; 2515 int ret;
2470 2516
2471 dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes); 2517 dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
2472 rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT); 2518 rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT ||
2519 obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_CALL);
2473 rbd_osd_req_destroy(obj_req->osd_req); 2520 rbd_osd_req_destroy(obj_req->osd_req);
2474 2521
2475 switch (img_req->op_type) { 2522 switch (img_req->op_type) {
@@ -2531,6 +2578,17 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
2531 bytes = 0; 2578 bytes = 0;
2532 } 2579 }
2533 2580
2581 if (obj_req->img_request->snapc->num_snaps && bytes > 0) {
2582 /*
2583 * Send a copyup request with an empty snapshot context to
2584 * deep-copyup the object through all existing snapshots.
2585 * A second request with the current snapshot context will be
2586 * sent for the actual modification.
2587 */
2588 obj_req->write_state = RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC;
2589 return rbd_obj_issue_copyup_empty_snapc(obj_req, bytes);
2590 }
2591
2534 obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS; 2592 obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
2535 return rbd_obj_issue_copyup_ops(obj_req, bytes); 2593 return rbd_obj_issue_copyup_ops(obj_req, bytes);
2536} 2594}
@@ -2632,6 +2690,17 @@ static bool rbd_obj_handle_write(struct rbd_obj_request *obj_req)
2632 return true; 2690 return true;
2633 } 2691 }
2634 return false; 2692 return false;
2693 case RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC:
2694 if (obj_req->result)
2695 return true;
2696
2697 obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
2698 ret = rbd_obj_issue_copyup_ops(obj_req, MODS_ONLY);
2699 if (ret) {
2700 obj_req->result = ret;
2701 return true;
2702 }
2703 return false;
2635 default: 2704 default:
2636 BUG(); 2705 BUG();
2637 } 2706 }