Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e88a36ec authored by Josh Durgin's avatar Josh Durgin Committed by Sage Weil
Browse files

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: default avatarJosh Durgin <josh.durgin@inktank.com>
Reviewed-by: default avatarAlex Elder <elder@inktank.com>
parent 048a9d2d
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -172,8 +172,12 @@ struct rbd_device {

	/* protects updating the header */
	struct rw_semaphore     header_rwsem;
	/* name of the snapshot this device reads from */
	char                    *snap_name;
	/* id of the snapshot this device reads from */
	u64                     snap_id;	/* current snapshot id */
	/* whether the snap_id this device reads from still exists */
	bool                    snap_exists;
	int                     read_only;

	struct list_head	node;
@@ -597,6 +601,7 @@ static int rbd_header_set_snap(struct rbd_device *rbd_dev, u64 *size)
		else
			snapc->seq = 0;
		rbd_dev->snap_id = CEPH_NOSNAP;
		rbd_dev->snap_exists = false;
		rbd_dev->read_only = 0;
		if (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)
			goto done;
		rbd_dev->snap_id = snapc->seq;
		rbd_dev->snap_exists = true;
		rbd_dev->read_only = 1;
	}

@@ -1468,6 +1474,21 @@ static void rbd_rq_fn(struct request_queue *q)

		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",
		     do_write ? "write" : "read",
		     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];

		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);
			continue;
		}