Skip to content

Commit bd3884a

Browse files
committed
rbd: check for EOD after exclusive lock is ensured to be held
Similar to commit 870611e ("rbd: get snapshot context after exclusive lock is ensured to be held"), move the "beyond EOD" check into the image request state machine so that it's performed after exclusive lock is ensured to be held. This avoids various race conditions which can arise when the image is shrunk under I/O (in practice, mostly readahead). In one such scenario rbd_assert(objno < rbd_dev->object_map_size); can be triggered if a close-to-EOD read gets queued right before the shrink is initiated and the EOD check is performed against an outdated mapping_size. After the resize is done on the server side and exclusive lock is (re)acquired bringing along the new (now shrunk) object map, the read starts going through the state machine and rbd_obj_may_exist() gets invoked on an object that is out of bounds of rbd_dev->object_map array. Cc: [email protected] Signed-off-by: Ilya Dryomov <[email protected]> Reviewed-by: Dongsheng Yang <[email protected]>
1 parent 18f7fcd commit bd3884a

1 file changed

Lines changed: 21 additions & 12 deletions

File tree

drivers/block/rbd.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3495,11 +3495,29 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)
34953495
rbd_assert(!need_exclusive_lock(img_req) ||
34963496
__rbd_is_lock_owner(rbd_dev));
34973497

3498-
if (rbd_img_is_write(img_req)) {
3499-
rbd_assert(!img_req->snapc);
3498+
if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
3499+
rbd_assert(!rbd_img_is_write(img_req));
3500+
} else {
3501+
struct request *rq = blk_mq_rq_from_pdu(img_req);
3502+
u64 off = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
3503+
u64 len = blk_rq_bytes(rq);
3504+
u64 mapping_size;
3505+
35003506
down_read(&rbd_dev->header_rwsem);
3501-
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
3507+
mapping_size = rbd_dev->mapping.size;
3508+
if (rbd_img_is_write(img_req)) {
3509+
rbd_assert(!img_req->snapc);
3510+
img_req->snapc =
3511+
ceph_get_snap_context(rbd_dev->header.snapc);
3512+
}
35023513
up_read(&rbd_dev->header_rwsem);
3514+
3515+
if (unlikely(off + len > mapping_size)) {
3516+
rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)",
3517+
off, len, mapping_size);
3518+
img_req->pending.result = -EIO;
3519+
return;
3520+
}
35033521
}
35043522

35053523
for_each_obj_request(img_req, obj_req) {
@@ -4725,7 +4743,6 @@ static void rbd_queue_workfn(struct work_struct *work)
47254743
struct request *rq = blk_mq_rq_from_pdu(img_request);
47264744
u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
47274745
u64 length = blk_rq_bytes(rq);
4728-
u64 mapping_size;
47294746
int result;
47304747

47314748
/* Ignore/skip any zero-length requests */
@@ -4738,17 +4755,9 @@ static void rbd_queue_workfn(struct work_struct *work)
47384755
blk_mq_start_request(rq);
47394756

47404757
down_read(&rbd_dev->header_rwsem);
4741-
mapping_size = rbd_dev->mapping.size;
47424758
rbd_img_capture_header(img_request);
47434759
up_read(&rbd_dev->header_rwsem);
47444760

4745-
if (offset + length > mapping_size) {
4746-
rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)", offset,
4747-
length, mapping_size);
4748-
result = -EIO;
4749-
goto err_img_request;
4750-
}
4751-
47524761
dout("%s rbd_dev %p img_req %p %s %llu~%llu\n", __func__, rbd_dev,
47534762
img_request, obj_op_name(op_type), offset, length);
47544763

0 commit comments

Comments
 (0)