Commit 5ea42986694a96542644f9cae8b122d3a00c508f
1 parent
97e36834f5
Exists in
master
and in
6 other branches
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], ©[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*/ |