From: Konrad Rzeszutek Wilk Date: Tue, 13 Dec 2011 16:15:27 +0000 (-0500) Subject: Merge branches 'stable/xen-block.rebase' and 'stable/vmalloc-3.2.rebased' into uek2... X-Git-Tag: v2.6.39-400.9.0~830^2~4 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=307f80d5bf10744e71ea52c977d1c76d700983b4;p=users%2Fjedix%2Flinux-maple.git Merge branches 'stable/xen-block.rebase' and 'stable/vmalloc-3.2.rebased' into uek2-merge * stable/xen-block.rebase: xen-blkback: Don't disconnect backend until state switched to XenbusStateClosed. block: xen-blkback: use API provided by xenbus module to map rings xen-blkback: convert hole punching to discard request on loop devices xen/blkback: Move processing of BLKIF_OP_DISCARD from dispatch_rw_block_io xen/blk[front|back]: Enhance discard support with secure erasing support. xen/blk[front|back]: Squash blkif_request_rw and blkif_request_discard together * stable/vmalloc-3.2.rebased: xen: map foreign pages for shared rings by updating the PTEs directly net: xen-netback: use API provided by xenbus module to map rings block: xen-blkback: use API provided by xenbus module to map rings xen: use generic functions instead of xen_{alloc, free}_vm_area() --- 307f80d5bf10744e71ea52c977d1c76d700983b4 diff --cc drivers/block/xen-blkback/blkback.c index 8d6e35a8e28e,b75d4a9aa08b,5cf2993a8338..4dde715fc445 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@@@ -416,59 -413,56 -410,6 +413,56 @@@@ static int xen_blkbk_map(struct blkif_r return ret; } - static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) + +static int dispatch_discard_io(struct xen_blkif *blkif, + + struct blkif_request *req) +{ + int err = 0; + int status = BLKIF_RSP_OKAY; + struct block_device *bdev = blkif->vbd.bdev; + - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY) - /* just forward the discard request */ + + blkif->st_ds_req++; + + + + xen_blkif_get(blkif); + + if (blkif->blk_backend_type == BLKIF_BACKEND_PHY || + + blkif->blk_backend_type == BLKIF_BACKEND_FILE) { + + unsigned long secure = (blkif->vbd.discard_secure && + + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + + BLKDEV_DISCARD_SECURE : 0; + err = blkdev_issue_discard(bdev, + req->u.discard.sector_number, + req->u.discard.nr_sectors, - GFP_KERNEL, 0); - else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) { - /* punch a hole in the backing file */ - struct loop_device *lo = bdev->bd_disk->private_data; - struct file *file = lo->lo_backing_file; - - if (file->f_op->fallocate) - err = file->f_op->fallocate(file, - FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, - req->u.discard.sector_number << 9, - req->u.discard.nr_sectors << 9); - else - err = -EOPNOTSUPP; + + GFP_KERNEL, secure); + } else + err = -EOPNOTSUPP; + + if (err == -EOPNOTSUPP) { + pr_debug(DRV_PFX "discard op failed, not supported\n"); + status = BLKIF_RSP_EOPNOTSUPP; + } else if (err) + status = BLKIF_RSP_ERROR; + - make_response(blkif, req->id, req->operation, status); + + make_response(blkif, req->u.discard.id, req->operation, status); + + xen_blkif_put(blkif); + + return err; +} + +static void xen_blk_drain_io(struct xen_blkif *blkif) +{ + atomic_set(&blkif->drain, 1); + do { + /* The initial value is one, and one refcnt taken at the + * start of the xen_blkif_schedule thread. */ + if (atomic_read(&blkif->refcnt) <= 2) + break; + wait_for_completion_interruptible_timeout( + &blkif->drain_complete, HZ); + + if (!atomic_read(&blkif->drain)) + break; + } while (!kthread_should_stop()); + atomic_set(&blkif->drain, 0); +} + /* * Completion callback on the bio's. Called as bh->b_end_io() */ @@@@ -584,23 -581,22 -515,6 +581,23 @@@@ __do_block_io_op(struct xen_blkif *blki return more_to_do; } +static int +do_block_io_op(struct xen_blkif *blkif) +{ + union blkif_back_rings *blk_rings = &blkif->blk_rings; + int more_to_do; + + do { + more_to_do = __do_block_io_op(blkif); + if (more_to_do) + break; + + RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do); + } while (more_to_do); + + return more_to_do; +} ++ /* * Transmutation of the 'struct blkif_request' to a proper 'struct bio' * and call the 'submit_bio' to pass it to the underlying storage. @@@@ -634,10 -630,6 -545,7 +631,6 @@@@ static int dispatch_rw_block_io(struct blkif->st_f_req++; operation = WRITE_FLUSH; break; - case BLKIF_OP_DISCARD: - blkif->st_ds_req++; - operation = REQ_DISCARD; - break; - case BLKIF_OP_WRITE_BARRIER: default: operation = 0; /* make gcc happy */ goto fail_response; @@@@ -645,9 -637,9 -553,8 +638,9 @@@@ } /* Check that the number of segments is sane. */ - - nseg = req->nr_segments; - if (unlikely(nseg == 0 && operation != WRITE_FLUSH && - operation != REQ_DISCARD) || + + nseg = req->u.rw.nr_segments; + + + if (unlikely(nseg == 0 && operation != WRITE_FLUSH) || unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { pr_debug(DRV_PFX "Bad number of segments in request (%d)\n", nseg); @@@@ -708,13 -700,13 -609,10 +701,13 @@@@ * the hypercall to unmap the grants - that is all done in * xen_blkbk_unmap. */ - if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg)) + if (xen_blkbk_map(req, pending_req, seg)) goto fail_flush; - /* This corresponding xen_blkif_put is done in __end_block_io_op */ + /* + * This corresponding xen_blkif_put is done in __end_block_io_op, or + * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. + */ xen_blkif_get(blkif); for (i = 0; i < nseg; i++) { @@@@ -738,25 -730,18 -636,18 +731,18 @@@@ preq.sector_number += seg[i].nsec; } - /* This will be hit if the operation was a flush. */ + /* This will be hit if the operation was a flush or discard. */ if (!bio) { - BUG_ON(operation != WRITE_FLUSH && operation != REQ_DISCARD); + BUG_ON(operation != WRITE_FLUSH); - if (operation == WRITE_FLUSH) { - bio = bio_alloc(GFP_KERNEL, 0); - if (unlikely(bio == NULL)) - goto fail_put_bio; + bio = bio_alloc(GFP_KERNEL, 0); + if (unlikely(bio == NULL)) + goto fail_put_bio; - biolist[nbio++] = bio; - bio->bi_bdev = preq.bdev; - bio->bi_private = pending_req; - bio->bi_end_io = end_block_io_op; - } else if (operation == REQ_DISCARD) { - xen_blk_discard(blkif, req); - xen_blkif_put(blkif); - free_req(pending_req); - return 0; - } + biolist[nbio++] = bio; + bio->bi_bdev = preq.bdev; + bio->bi_private = pending_req; + bio->bi_end_io = end_block_io_op; } /* diff --cc drivers/block/xen-blkback/xenbus.c index a6d43030b107,5b62f519cde5,6a381de39e6f..187fd2c1a15d --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@@@ -423,73 -386,82 -379,6 +386,82 @@@@ int xen_blkbk_flush_diskcache(struct xe return err; } +int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) +{ + struct xenbus_device *dev = be->dev; + struct xen_blkif *blkif = be->blkif; + char *type; + int err; + int state = 0; + + type = xenbus_read(XBT_NIL, dev->nodename, "type", NULL); + if (!IS_ERR(type)) { + if (strncmp(type, "file", 4) == 0) { + state = 1; + blkif->blk_backend_type = BLKIF_BACKEND_FILE; + } + if (strncmp(type, "phy", 3) == 0) { + struct block_device *bdev = be->blkif->vbd.bdev; + struct request_queue *q = bdev_get_queue(bdev); + if (blk_queue_discard(q)) { + err = xenbus_printf(xbt, dev->nodename, + "discard-granularity", "%u", + q->limits.discard_granularity); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-granularity"); + goto kfree; + } + err = xenbus_printf(xbt, dev->nodename, + "discard-alignment", "%u", + q->limits.discard_alignment); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-alignment"); + goto kfree; + } + state = 1; + blkif->blk_backend_type = BLKIF_BACKEND_PHY; + } + + /* Optional. */ + + err = xenbus_printf(xbt, dev->nodename, + + "discard-secure", "%d", + + blkif->vbd.discard_secure); + + if (err) { + + xenbus_dev_fatal(dev, err, + + "writting discard-secure"); + + goto kfree; + + } + } + } else { + err = PTR_ERR(type); + xenbus_dev_fatal(dev, err, "reading type"); + goto out; + } + + err = xenbus_printf(xbt, dev->nodename, "feature-discard", + "%d", state); + if (err) + xenbus_dev_fatal(dev, err, "writing feature-discard"); +kfree: + kfree(type); +out: + return err; +} +int xen_blkbk_barrier(struct xenbus_transaction xbt, + struct backend_info *be, int state) +{ + struct xenbus_device *dev = be->dev; + int err; + + err = xenbus_printf(xbt, dev->nodename, "feature-barrier", + "%d", state); + if (err) + xenbus_dev_fatal(dev, err, "writing feature-barrier"); + + return err; +} + /* * Entry point to this code when a new device is created. Allocate the basic * structures, and watch the store waiting for the hotplug scripts to tell us diff --cc drivers/block/xen-blkfront.c index 7b2ec5908413,f3c45ba1304e,b536a9cef917..351ddeffd430 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@@@ -98,9 -98,10 -98,6 +98,10 @@@@ struct blkfront_inf unsigned long shadow_free; unsigned int feature_flush; unsigned int flush_op; - unsigned int feature_discard; + + unsigned int feature_discard:1; + + unsigned int feature_secdiscard:1; + unsigned int discard_granularity; + unsigned int discard_alignment; int is_ready; }; @@@@ -305,36 -306,41 -302,29 +306,41 @@@@ static int blkif_queue_request(struct r ring_req->operation = info->flush_op; } - if (unlikely(req->cmd_flags & REQ_DISCARD)) { - ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); - BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); - - for_each_sg(info->sg, sg, ring_req->nr_segments, i) { - buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); - fsect = sg->offset >> 9; - lsect = fsect + (sg->length >> 9) - 1; - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); - - gnttab_grant_foreign_access_ref( - ref, - info->xbdev->otherend_id, - buffer_mfn, - rq_data_dir(req) ); - - info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); - ring_req->u.rw.seg[i] = - (struct blkif_request_segment) { - .gref = ref, - .first_sect = fsect, - .last_sect = lsect }; + + if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) { + /* 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); + + if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard) + + ring_req->u.discard.flag = BLKIF_DISCARD_SECURE; + + else + + ring_req->u.discard.flag = 0; + } 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); + + ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req, + + info->sg); + + BUG_ON(ring_req->u.rw.nr_segments > + + BLKIF_MAX_SEGMENTS_PER_REQUEST); + - for_each_sg(info->sg, sg, ring_req->nr_segments, i) { + + for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) { + buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); + fsect = sg->offset >> 9; + lsect = fsect + (sg->length >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); + + gnttab_grant_foreign_access_ref( + ref, + info->xbdev->otherend_id, + buffer_mfn, + rq_data_dir(req)); + + info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); + ring_req->u.rw.seg[i] = + (struct blkif_request_segment) { + .gref = ref, + .first_sect = fsect, + .last_sect = lsect }; + } } info->ring.req_prod_pvt++; @@@@ -419,13 -425,15 -406,6 +425,15 @@@@ static int xlvbd_init_blk_queue(struct 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; + + if (info->feature_secdiscard) + + queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq); + } + /* 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); @@@@ -742,17 -753,19 -722,6 +753,19 @@@@ static irqreturn_t blkif_interrupt(int 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; + + info->feature_secdiscard = 0; + queue_flag_clear(QUEUE_FLAG_DISCARD, rq); + + queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); + } + __blk_end_request_all(req, error); + break; case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_WRITE_BARRIER: if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { @@@@ -1129,33 -1144,41 -1098,6 +1144,41 @@@@ blkfront_closing(struct blkfront_info * bdput(bdev); } +static void blkfront_setup_discard(struct blkfront_info *info) +{ + int err; + char *type; + unsigned int discard_granularity; + unsigned int discard_alignment; + + unsigned int discard_secure; + + type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL); + if (IS_ERR(type)) + return; + + + info->feature_secdiscard = 0; + 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; + } + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + + "discard-secure", "%d", &discard_secure, + + NULL); + + if (!err) + + info->feature_secdiscard = discard_secure; + + + } 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).