Commit 5ea42986694a96542644f9cae8b122d3a00c508f

Authored by Konrad Rzeszutek Wilk
1 parent 97e36834f5

xen/blk[front|back]: Enhance discard support with secure erasing support.

Part of the blkdev_issue_discard(xx) operation is that it can also
issue a secure discard operation that will permanantly remove the
sectors in question. We advertise that we can support that via the
'discard-secure' attribute and on the request, if the 'secure' bit
is set, we will attempt to pass in REQ_DISCARD | REQ_SECURE.

CC: Li Dongyang <lidongyang@novell.com>
[v1: Used 'flag' instead of 'secure:1' bit]
[v2: Use 'reserved' uint8_t instead of adding a new value]
[v3: Check for nseg when mapping instead of operation]
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

Showing 5 changed files with 77 additions and 19 deletions Side-by-side Diff

drivers/block/xen-blkback/blkback.c
... ... @@ -422,13 +422,16 @@
422 422 int status = BLKIF_RSP_OKAY;
423 423 struct block_device *bdev = blkif->vbd.bdev;
424 424  
425   - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY)
  425 + if (blkif->blk_backend_type == BLKIF_BACKEND_PHY) {
  426 + unsigned long secure = (blkif->vbd.discard_secure &&
  427 + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ?
  428 + BLKDEV_DISCARD_SECURE : 0;
426 429 /* just forward the discard request */
427 430 err = blkdev_issue_discard(bdev,
428 431 req->u.discard.sector_number,
429 432 req->u.discard.nr_sectors,
430   - GFP_KERNEL, 0);
431   - else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) {
  433 + GFP_KERNEL, secure);
  434 + } else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) {
432 435 /* punch a hole in the backing file */
433 436 struct loop_device *lo = bdev->bd_disk->private_data;
434 437 struct file *file = lo->lo_backing_file;
... ... @@ -643,8 +646,11 @@
643 646 break;
644 647 }
645 648  
646   - /* Check that the number of segments is sane. */
647   - nseg = req->u.rw.nr_segments;
  649 + if (unlikely(operation == REQ_DISCARD))
  650 + nseg = 0;
  651 + else
  652 + /* Check that the number of segments is sane. */
  653 + nseg = req->u.rw.nr_segments;
648 654  
649 655 if (unlikely(nseg == 0 && operation != WRITE_FLUSH &&
650 656 operation != REQ_DISCARD) ||
... ... @@ -708,7 +714,7 @@
708 714 * the hypercall to unmap the grants - that is all done in
709 715 * xen_blkbk_unmap.
710 716 */
711   - if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg))
  717 + if (nseg && xen_blkbk_map(req, pending_req, seg))
712 718 goto fail_flush;
713 719  
714 720 /*
drivers/block/xen-blkback/common.h
... ... @@ -69,7 +69,7 @@
69 69 } __attribute__((__packed__));
70 70  
71 71 struct blkif_x86_32_request_discard {
72   - uint8_t nr_segments; /* number of segments */
  72 + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */
73 73 blkif_vdev_t _pad1; /* was "handle" for read/write requests */
74 74 uint64_t id; /* private guest value, echoed in resp */
75 75 blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
... ... @@ -104,7 +104,7 @@
104 104 } __attribute__((__packed__));
105 105  
106 106 struct blkif_x86_64_request_discard {
107   - uint8_t nr_segments; /* number of segments */
  107 + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */
108 108 blkif_vdev_t _pad1; /* was "handle" for read/write requests */
109 109 uint32_t _pad2; /* offsetof(blkif_..,u.discard.id)==8 */
110 110 uint64_t id;
... ... @@ -164,6 +164,7 @@
164 164 /* Cached size parameter. */
165 165 sector_t size;
166 166 bool flush_support;
  167 + bool discard_secure;
167 168 };
168 169  
169 170 struct backend_info;
... ... @@ -261,6 +262,7 @@
261 262 dst->u.rw.seg[i] = src->u.rw.seg[i];
262 263 break;
263 264 case BLKIF_OP_DISCARD:
  265 + dst->u.discard.flag = src->u.discard.flag;
264 266 dst->u.discard.sector_number = src->u.discard.sector_number;
265 267 dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
266 268 break;
... ... @@ -290,6 +292,7 @@
290 292 dst->u.rw.seg[i] = src->u.rw.seg[i];
291 293 break;
292 294 case BLKIF_OP_DISCARD:
  295 + dst->u.discard.flag = src->u.discard.flag;
293 296 dst->u.discard.sector_number = src->u.discard.sector_number;
294 297 dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
295 298 break;
drivers/block/xen-blkback/xenbus.c
... ... @@ -338,6 +338,9 @@
338 338 if (q && q->flush_flags)
339 339 vbd->flush_support = true;
340 340  
  341 + if (q && blk_queue_secdiscard(q))
  342 + vbd->discard_secure = true;
  343 +
341 344 DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
342 345 handle, blkif->domid);
343 346 return 0;
... ... @@ -419,6 +422,15 @@
419 422 }
420 423 state = 1;
421 424 blkif->blk_backend_type = BLKIF_BACKEND_PHY;
  425 + }
  426 + /* Optional. */
  427 + err = xenbus_printf(xbt, dev->nodename,
  428 + "discard-secure", "%d",
  429 + blkif->vbd.discard_secure);
  430 + if (err) {
  431 + xenbus_dev_fatal(dev, err,
  432 + "writting discard-secure");
  433 + goto kfree;
422 434 }
423 435 }
424 436 } else {
drivers/block/xen-blkfront.c
... ... @@ -98,7 +98,8 @@
98 98 unsigned long shadow_free;
99 99 unsigned int feature_flush;
100 100 unsigned int flush_op;
101   - unsigned int feature_discard;
  101 + unsigned int feature_discard:1;
  102 + unsigned int feature_secdiscard:1;
102 103 unsigned int discard_granularity;
103 104 unsigned int discard_alignment;
104 105 int is_ready;
105 106  
106 107  
... ... @@ -305,11 +306,14 @@
305 306 ring_req->operation = info->flush_op;
306 307 }
307 308  
308   - if (unlikely(req->cmd_flags & REQ_DISCARD)) {
  309 + if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
309 310 /* id, sector_number and handle are set above. */
310 311 ring_req->operation = BLKIF_OP_DISCARD;
311   - ring_req->u.discard.nr_segments = 0;
312 312 ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
  313 + if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
  314 + ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
  315 + else
  316 + ring_req->u.discard.flag = 0;
313 317 } else {
314 318 ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req,
315 319 info->sg);
... ... @@ -426,6 +430,8 @@
426 430 blk_queue_max_discard_sectors(rq, get_capacity(gd));
427 431 rq->limits.discard_granularity = info->discard_granularity;
428 432 rq->limits.discard_alignment = info->discard_alignment;
  433 + if (info->feature_secdiscard)
  434 + queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq);
429 435 }
430 436  
431 437 /* Hard sector size and max sectors impersonate the equiv. hardware. */
... ... @@ -707,6 +713,8 @@
707 713 static void blkif_completion(struct blk_shadow *s)
708 714 {
709 715 int i;
  716 + /* Do not let BLKIF_OP_DISCARD as nr_segment is in the same place
  717 + * flag. */
710 718 for (i = 0; i < s->req.u.rw.nr_segments; i++)
711 719 gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL);
712 720 }
... ... @@ -738,7 +746,8 @@
738 746 id = bret->id;
739 747 req = info->shadow[id].request;
740 748  
741   - blkif_completion(&info->shadow[id]);
  749 + if (bret->operation != BLKIF_OP_DISCARD)
  750 + blkif_completion(&info->shadow[id]);
742 751  
743 752 add_id_to_freelist(info, id);
744 753  
745 754  
... ... @@ -751,7 +760,9 @@
751 760 info->gd->disk_name);
752 761 error = -EOPNOTSUPP;
753 762 info->feature_discard = 0;
  763 + info->feature_secdiscard = 0;
754 764 queue_flag_clear(QUEUE_FLAG_DISCARD, rq);
  765 + queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq);
755 766 }
756 767 __blk_end_request_all(req, error);
757 768 break;
758 769  
... ... @@ -1039,13 +1050,15 @@
1039 1050 req->u.rw.id = get_id_from_freelist(info);
1040 1051 memcpy(&info->shadow[req->u.rw.id], &copy[i], sizeof(copy[i]));
1041 1052  
  1053 + if (req->operation != BLKIF_OP_DISCARD) {
1042 1054 /* Rewrite any grant references invalidated by susp/resume. */
1043   - for (j = 0; j < req->u.rw.nr_segments; j++)
1044   - gnttab_grant_foreign_access_ref(
1045   - req->u.rw.seg[j].gref,
1046   - info->xbdev->otherend_id,
1047   - pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]),
1048   - rq_data_dir(info->shadow[req->u.rw.id].request));
  1055 + for (j = 0; j < req->u.rw.nr_segments; j++)
  1056 + gnttab_grant_foreign_access_ref(
  1057 + req->u.rw.seg[j].gref,
  1058 + info->xbdev->otherend_id,
  1059 + pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]),
  1060 + rq_data_dir(info->shadow[req->u.rw.id].request));
  1061 + }
1049 1062 info->shadow[req->u.rw.id].req = *req;
1050 1063  
1051 1064 info->ring.req_prod_pvt++;
1052 1065  
... ... @@ -1137,11 +1150,13 @@
1137 1150 char *type;
1138 1151 unsigned int discard_granularity;
1139 1152 unsigned int discard_alignment;
  1153 + unsigned int discard_secure;
1140 1154  
1141 1155 type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL);
1142 1156 if (IS_ERR(type))
1143 1157 return;
1144 1158  
  1159 + info->feature_secdiscard = 0;
1145 1160 if (strncmp(type, "phy", 3) == 0) {
1146 1161 err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
1147 1162 "discard-granularity", "%u", &discard_granularity,
... ... @@ -1152,6 +1167,12 @@
1152 1167 info->discard_granularity = discard_granularity;
1153 1168 info->discard_alignment = discard_alignment;
1154 1169 }
  1170 + err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
  1171 + "discard-secure", "%d", &discard_secure,
  1172 + NULL);
  1173 + if (!err)
  1174 + info->feature_secdiscard = discard_secure;
  1175 +
1155 1176 } else if (strncmp(type, "file", 4) == 0)
1156 1177 info->feature_discard = 1;
1157 1178  
include/xen/interface/io/blkif.h
... ... @@ -84,6 +84,21 @@
84 84 * e07154r6-Data_Set_Management_Proposal_for_ATA-ACS2.doc
85 85 * http://www.seagate.com/staticfiles/support/disc/manuals/
86 86 * Interface%20manuals/100293068c.pdf
  87 + * The backend can optionally provide three extra XenBus attributes to
  88 + * further optimize the discard functionality:
  89 + * 'discard-aligment' - Devices that support discard functionality may
  90 + * internally allocate space in units that are bigger than the exported
  91 + * logical block size. The discard-alignment parameter indicates how many bytes
  92 + * the beginning of the partition is offset from the internal allocation unit's
  93 + * natural alignment.
  94 + * 'discard-granularity' - Devices that support discard functionality may
  95 + * internally allocate space using units that are bigger than the logical block
  96 + * size. The discard-granularity parameter indicates the size of the internal
  97 + * allocation unit in bytes if reported by the device. Otherwise the
  98 + * discard-granularity will be set to match the device's physical block size.
  99 + * 'discard-secure' - All copies of the discarded sectors (potentially created
  100 + * by garbage collection) must also be erased. To use this feature, the flag
  101 + * BLKIF_DISCARD_SECURE must be set in the blkif_request_trim.
87 102 */
88 103 #define BLKIF_OP_DISCARD 5
89 104  
... ... @@ -111,7 +126,8 @@
111 126 } __attribute__((__packed__));
112 127  
113 128 struct blkif_request_discard {
114   - uint8_t nr_segments; /* number of segments */
  129 + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero. */
  130 +#define BLKIF_DISCARD_SECURE (1<<0) /* ignored if discard-secure=0 */
115 131 blkif_vdev_t _pad1; /* only for read/write requests */
116 132 #ifdef CONFIG_X86_64
117 133 uint32_t _pad2; /* offsetof(blkif_req..,u.discard.id)==8*/