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

Commit ed30bf31 authored by Li Dongyang's avatar Li Dongyang Committed by Konrad Rzeszutek Wilk
Browse files

xen-blkfront: Handle discard requests.



If the backend advertises 'feature-discard', then interrogate
the backend for alignment and granularity. Setup the request
queue with the appropiate values and send the discard operation
as required.

Signed-off-by: default avatarLi Dongyang <lidongyang@novell.com>
[v1: Amended commit description]
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
parent b3cb0d6a
Loading
Loading
Loading
Loading
+88 −23
Original line number Diff line number Diff line
@@ -98,6 +98,9 @@ struct blkfront_info
	unsigned long shadow_free;
	unsigned int feature_flush;
	unsigned int flush_op;
	unsigned int feature_discard;
	unsigned int discard_granularity;
	unsigned int discard_alignment;
	int is_ready;
};

@@ -302,6 +305,12 @@ static int blkif_queue_request(struct request *req)
		ring_req->operation = info->flush_op;
	}

	if (unlikely(req->cmd_flags & REQ_DISCARD)) {
		/* id, sector_number and handle are set above. */
		ring_req->operation = BLKIF_OP_DISCARD;
		ring_req->nr_segments = 0;
		ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
	} else {
		ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
		BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);

@@ -326,6 +335,7 @@ static int blkif_queue_request(struct request *req)
						.first_sect = fsect,
						.last_sect  = lsect };
		}
	}

	info->ring.req_prod_pvt++;

@@ -399,6 +409,7 @@ static void do_blkif_request(struct request_queue *rq)
static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
{
	struct request_queue *rq;
	struct blkfront_info *info = gd->private_data;

	rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
	if (rq == NULL)
@@ -406,6 +417,13 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)

	queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);

	if (info->feature_discard) {
		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, rq);
		blk_queue_max_discard_sectors(rq, get_capacity(gd));
		rq->limits.discard_granularity = info->discard_granularity;
		rq->limits.discard_alignment = info->discard_alignment;
	}

	/* Hard sector size and max sectors impersonate the equiv. hardware. */
	blk_queue_logical_block_size(rq, sector_size);
	blk_queue_max_hw_sectors(rq, 512);
@@ -722,6 +740,19 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)

		error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
		switch (bret->operation) {
		case BLKIF_OP_DISCARD:
			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
				struct request_queue *rq = info->rq;
				printk(KERN_WARNING "blkfront: %s: discard op failed\n",
					   info->gd->disk_name);
				error = -EOPNOTSUPP;
				info->feature_discard = 0;
				spin_lock(rq->queue_lock);
				queue_flag_clear(QUEUE_FLAG_DISCARD, rq);
				spin_unlock(rq->queue_lock);
			}
			__blk_end_request_all(req, error);
			break;
		case BLKIF_OP_FLUSH_DISKCACHE:
		case BLKIF_OP_WRITE_BARRIER:
			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
@@ -1098,6 +1129,33 @@ blkfront_closing(struct blkfront_info *info)
	bdput(bdev);
}

static void blkfront_setup_discard(struct blkfront_info *info)
{
	int err;
	char *type;
	unsigned int discard_granularity;
	unsigned int discard_alignment;

	type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL);
	if (IS_ERR(type))
		return;

	if (strncmp(type, "phy", 3) == 0) {
		err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
			"discard-granularity", "%u", &discard_granularity,
			"discard-alignment", "%u", &discard_alignment,
			NULL);
		if (!err) {
			info->feature_discard = 1;
			info->discard_granularity = discard_granularity;
			info->discard_alignment = discard_alignment;
		}
	} else if (strncmp(type, "file", 4) == 0)
		info->feature_discard = 1;

	kfree(type);
}

/*
 * Invoked when the backend is finally 'ready' (and has told produced
 * the details about the physical device - #sectors, size, etc).
@@ -1108,7 +1166,7 @@ static void blkfront_connect(struct blkfront_info *info)
	unsigned long sector_size;
	unsigned int binfo;
	int err;
	int barrier, flush;
	int barrier, flush, discard;

	switch (info->connected) {
	case BLKIF_STATE_CONNECTED:
@@ -1179,6 +1237,13 @@ static void blkfront_connect(struct blkfront_info *info)
		info->flush_op = BLKIF_OP_FLUSH_DISKCACHE;
	}

	err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
			    "feature-discard", "%d", &discard,
			    NULL);

	if (!err && discard)
		blkfront_setup_discard(info);

	err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
	if (err) {
		xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",