rbd: return errors for mapped but deleted snapshot
When a snapshot is deleted, the OSD will return ENOENT when reading from it. This is normally interpreted as a hole by rbd, which will return zeroes. To minimize the time in which this can happen, stop requests early when we are notified that our snapshot no longer exists. [elder@inktank.com: updated __rbd_init_snaps_header() logic] Signed-off-by: Josh Durgin <josh.durgin@inktank.com> Reviewed-by: Alex Elder <elder@inktank.com>
This commit is contained in:
parent
048a9d2d06
commit
e88a36ec96
|
@ -172,9 +172,13 @@ struct rbd_device {
|
||||||
|
|
||||||
/* protects updating the header */
|
/* protects updating the header */
|
||||||
struct rw_semaphore header_rwsem;
|
struct rw_semaphore header_rwsem;
|
||||||
|
/* name of the snapshot this device reads from */
|
||||||
char *snap_name;
|
char *snap_name;
|
||||||
|
/* id of the snapshot this device reads from */
|
||||||
u64 snap_id; /* current snapshot id */
|
u64 snap_id; /* current snapshot id */
|
||||||
int read_only;
|
/* whether the snap_id this device reads from still exists */
|
||||||
|
bool snap_exists;
|
||||||
|
int read_only;
|
||||||
|
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
|
||||||
|
@ -597,6 +601,7 @@ static int rbd_header_set_snap(struct rbd_device *rbd_dev, u64 *size)
|
||||||
else
|
else
|
||||||
snapc->seq = 0;
|
snapc->seq = 0;
|
||||||
rbd_dev->snap_id = CEPH_NOSNAP;
|
rbd_dev->snap_id = CEPH_NOSNAP;
|
||||||
|
rbd_dev->snap_exists = false;
|
||||||
rbd_dev->read_only = 0;
|
rbd_dev->read_only = 0;
|
||||||
if (size)
|
if (size)
|
||||||
*size = header->image_size;
|
*size = header->image_size;
|
||||||
|
@ -606,6 +611,7 @@ static int rbd_header_set_snap(struct rbd_device *rbd_dev, u64 *size)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
rbd_dev->snap_id = snapc->seq;
|
rbd_dev->snap_id = snapc->seq;
|
||||||
|
rbd_dev->snap_exists = true;
|
||||||
rbd_dev->read_only = 1;
|
rbd_dev->read_only = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,6 +1474,21 @@ static void rbd_rq_fn(struct request_queue *q)
|
||||||
|
|
||||||
spin_unlock_irq(q->queue_lock);
|
spin_unlock_irq(q->queue_lock);
|
||||||
|
|
||||||
|
if (rbd_dev->snap_id != CEPH_NOSNAP) {
|
||||||
|
bool snap_exists;
|
||||||
|
|
||||||
|
down_read(&rbd_dev->header_rwsem);
|
||||||
|
snap_exists = rbd_dev->snap_exists;
|
||||||
|
up_read(&rbd_dev->header_rwsem);
|
||||||
|
|
||||||
|
if (!snap_exists) {
|
||||||
|
dout("request for non-existent snapshot");
|
||||||
|
spin_lock_irq(q->queue_lock);
|
||||||
|
__blk_end_request_all(rq, -ENXIO);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dout("%s 0x%x bytes at 0x%llx\n",
|
dout("%s 0x%x bytes at 0x%llx\n",
|
||||||
do_write ? "write" : "read",
|
do_write ? "write" : "read",
|
||||||
size, blk_rq_pos(rq) * SECTOR_SIZE);
|
size, blk_rq_pos(rq) * SECTOR_SIZE);
|
||||||
|
@ -2088,7 +2109,14 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
|
||||||
cur_id = rbd_dev->header.snapc->snaps[i - 1];
|
cur_id = rbd_dev->header.snapc->snaps[i - 1];
|
||||||
|
|
||||||
if (!i || old_snap->id < cur_id) {
|
if (!i || old_snap->id < cur_id) {
|
||||||
/* old_snap->id was skipped, thus was removed */
|
/*
|
||||||
|
* old_snap->id was skipped, thus was
|
||||||
|
* removed. If this rbd_dev is mapped to
|
||||||
|
* the removed snapshot, record that it no
|
||||||
|
* longer exists, to prevent further I/O.
|
||||||
|
*/
|
||||||
|
if (rbd_dev->snap_id == old_snap->id)
|
||||||
|
rbd_dev->snap_exists = false;
|
||||||
__rbd_remove_snap_dev(rbd_dev, old_snap);
|
__rbd_remove_snap_dev(rbd_dev, old_snap);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue