Skip to content

Commit

Permalink
rbd: get snapshot context after exclusive lock is ensured to be held
Browse files Browse the repository at this point in the history
commit 870611e upstream.

Move capturing the snapshot context into the image request state
machine, after exclusive lock is ensured to be held for the duration of
dealing with the image request.  This is needed to ensure correctness
of fast-diff states (OBJECT_EXISTS vs OBJECT_EXISTS_CLEAN) and object
deltas computed based off of them.  Otherwise the object map that is
forked for the snapshot isn't guaranteed to accurately reflect the
contents of the snapshot when the snapshot is taken under I/O.  This
breaks differential backup and snapshot-based mirroring use cases with
fast-diff enabled: since some object deltas may be incomplete, the
destination image may get corrupted.

Cc: stable@vger.kernel.org
Link: https://tracker.ceph.com/issues/61472
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
idryomov authored and gregkh committed Jun 14, 2023
1 parent d647ee6 commit 222a6bc
Showing 1 changed file with 23 additions and 7 deletions.
30 changes: 23 additions & 7 deletions drivers/block/rbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,8 @@ static bool rbd_obj_is_tail(struct rbd_obj_request *obj_req)
*/
static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req)
{
rbd_assert(obj_req->img_request->snapc);

if (obj_req->img_request->op_type == OBJ_OP_DISCARD) {
dout("%s %p objno %llu discard\n", __func__, obj_req,
obj_req->ex.oe_objno);
Expand Down Expand Up @@ -1456,6 +1458,7 @@ __rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
static struct ceph_osd_request *
rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
{
rbd_assert(obj_req->img_request->snapc);
return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
num_ops);
}
Expand Down Expand Up @@ -1592,15 +1595,18 @@ static void rbd_img_request_init(struct rbd_img_request *img_request,
mutex_init(&img_request->state_mutex);
}

/*
* Only snap_id is captured here, for reads. For writes, snapshot
* context is captured in rbd_img_object_requests() after exclusive
* lock is ensured to be held.
*/
static void rbd_img_capture_header(struct rbd_img_request *img_req)
{
struct rbd_device *rbd_dev = img_req->rbd_dev;

lockdep_assert_held(&rbd_dev->header_rwsem);

if (rbd_img_is_write(img_req))
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
else
if (!rbd_img_is_write(img_req))
img_req->snap_id = rbd_dev->spec->snap_id;

if (rbd_dev_parent_get(rbd_dev))
Expand Down Expand Up @@ -3483,9 +3489,19 @@ static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)

static void rbd_img_object_requests(struct rbd_img_request *img_req)
{
struct rbd_device *rbd_dev = img_req->rbd_dev;
struct rbd_obj_request *obj_req;

rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
rbd_assert(!need_exclusive_lock(img_req) ||
__rbd_is_lock_owner(rbd_dev));

if (rbd_img_is_write(img_req)) {
rbd_assert(!img_req->snapc);
down_read(&rbd_dev->header_rwsem);
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
up_read(&rbd_dev->header_rwsem);
}

for_each_obj_request(img_req, obj_req) {
int result = 0;
Expand All @@ -3503,7 +3519,6 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)

static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
{
struct rbd_device *rbd_dev = img_req->rbd_dev;
int ret;

again:
Expand All @@ -3524,9 +3539,6 @@ static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
if (*result)
return true;

rbd_assert(!need_exclusive_lock(img_req) ||
__rbd_is_lock_owner(rbd_dev));

rbd_img_object_requests(img_req);
if (!img_req->pending.num_pending) {
*result = img_req->pending.result;
Expand Down Expand Up @@ -3988,6 +4000,10 @@ static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
{
int ret;

ret = rbd_dev_refresh(rbd_dev);
if (ret)
return ret;

if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
ret = rbd_object_map_open(rbd_dev);
if (ret)
Expand Down

0 comments on commit 222a6bc

Please sign in to comment.