summaryrefslogtreecommitdiffstats
path: root/arch/um/drivers
diff options
context:
space:
mode:
authorAnton Ivanov <anton.ivanov@cambridgegreys.com>2018-11-14 13:41:09 -0500
committerRichard Weinberger <richard@nod.at>2018-12-27 16:48:20 -0500
commit50109b5a03b4024eb6b8df3ab8f427625f54fe92 (patch)
tree763dffe32e8a11bf9c6ac69bbf4a45cbc8e1ebff /arch/um/drivers
parenta41421edb926fcc8f212742b2e7a1f21c9047853 (diff)
um: Add support for DISCARD in the UBD Driver
Support for DISCARD and WRITE_ZEROES in the ubd driver using fallocate. DISCARD is enabled by default and can be disabled using a new UBD command line flag. If the underlying fs on which the UBD image is stored does not support DISCARD the support for both DISCARD and WRITE_ZEROES is turned off. Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/drivers')
-rw-r--r--arch/um/drivers/ubd_kern.c65
1 files changed, 54 insertions, 11 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 1672e3c49bfb..7aaa473909be 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -154,6 +154,7 @@ struct ubd {
154 struct openflags openflags; 154 struct openflags openflags;
155 unsigned shared:1; 155 unsigned shared:1;
156 unsigned no_cow:1; 156 unsigned no_cow:1;
157 unsigned no_trim:1;
157 struct cow cow; 158 struct cow cow;
158 struct platform_device pdev; 159 struct platform_device pdev;
159 struct request_queue *queue; 160 struct request_queue *queue;
@@ -177,6 +178,7 @@ struct ubd {
177 .boot_openflags = OPEN_FLAGS, \ 178 .boot_openflags = OPEN_FLAGS, \
178 .openflags = OPEN_FLAGS, \ 179 .openflags = OPEN_FLAGS, \
179 .no_cow = 0, \ 180 .no_cow = 0, \
181 .no_trim = 0, \
180 .shared = 0, \ 182 .shared = 0, \
181 .cow = DEFAULT_COW, \ 183 .cow = DEFAULT_COW, \
182 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \ 184 .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
@@ -323,7 +325,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
323 *index_out = n; 325 *index_out = n;
324 326
325 err = -EINVAL; 327 err = -EINVAL;
326 for (i = 0; i < sizeof("rscd="); i++) { 328 for (i = 0; i < sizeof("rscdt="); i++) {
327 switch (*str) { 329 switch (*str) {
328 case 'r': 330 case 'r':
329 flags.w = 0; 331 flags.w = 0;
@@ -337,12 +339,15 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
337 case 'c': 339 case 'c':
338 ubd_dev->shared = 1; 340 ubd_dev->shared = 1;
339 break; 341 break;
342 case 't':
343 ubd_dev->no_trim = 1;
344 break;
340 case '=': 345 case '=':
341 str++; 346 str++;
342 goto break_loop; 347 goto break_loop;
343 default: 348 default:
344 *error_out = "Expected '=' or flag letter " 349 *error_out = "Expected '=' or flag letter "
345 "(r, s, c, or d)"; 350 "(r, s, c, t or d)";
346 goto out; 351 goto out;
347 } 352 }
348 str++; 353 str++;
@@ -415,6 +420,7 @@ __uml_help(ubd_setup,
415" 'c' will cause the device to be treated as being shared between multiple\n" 420" 'c' will cause the device to be treated as being shared between multiple\n"
416" UMLs and file locking will be turned off - this is appropriate for a\n" 421" UMLs and file locking will be turned off - this is appropriate for a\n"
417" cluster filesystem and inappropriate at almost all other times.\n\n" 422" cluster filesystem and inappropriate at almost all other times.\n\n"
423" 't' will disable trim/discard support on the device (enabled by default).\n\n"
418); 424);
419 425
420static int udb_setup(char *str) 426static int udb_setup(char *str)
@@ -513,9 +519,17 @@ static void ubd_handler(void)
513 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { 519 for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
514 struct io_thread_req *io_req = (*irq_req_buffer)[count]; 520 struct io_thread_req *io_req = (*irq_req_buffer)[count];
515 521
516 if (!blk_update_request(io_req->req, io_req->error, io_req->length)) 522 if ((io_req->error == BLK_STS_NOTSUPP) && (req_op(io_req->req) == REQ_OP_DISCARD)) {
517 __blk_mq_end_request(io_req->req, io_req->error); 523 blk_queue_max_discard_sectors(io_req->req->q, 0);
518 524 blk_queue_max_write_zeroes_sectors(io_req->req->q, 0);
525 blk_queue_flag_clear(QUEUE_FLAG_DISCARD, io_req->req->q);
526 }
527 if ((io_req->error) || (io_req->buffer == NULL))
528 blk_mq_end_request(io_req->req, io_req->error);
529 else {
530 if (!blk_update_request(io_req->req, io_req->error, io_req->length))
531 __blk_mq_end_request(io_req->req, io_req->error);
532 }
519 kfree(io_req); 533 kfree(io_req);
520 } 534 }
521 } 535 }
@@ -829,6 +843,13 @@ static int ubd_open_dev(struct ubd *ubd_dev)
829 if(err < 0) goto error; 843 if(err < 0) goto error;
830 ubd_dev->cow.fd = err; 844 ubd_dev->cow.fd = err;
831 } 845 }
846 if (ubd_dev->no_trim == 0) {
847 ubd_dev->queue->limits.discard_granularity = SECTOR_SIZE;
848 ubd_dev->queue->limits.discard_alignment = SECTOR_SIZE;
849 blk_queue_max_discard_sectors(ubd_dev->queue, UBD_MAX_REQUEST);
850 blk_queue_max_write_zeroes_sectors(ubd_dev->queue, UBD_MAX_REQUEST);
851 blk_queue_flag_set(QUEUE_FLAG_DISCARD, ubd_dev->queue);
852 }
832 blk_queue_flag_set(QUEUE_FLAG_NONROT, ubd_dev->queue); 853 blk_queue_flag_set(QUEUE_FLAG_NONROT, ubd_dev->queue);
833 return 0; 854 return 0;
834 error: 855 error:
@@ -1372,6 +1393,10 @@ static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx,
1372 case REQ_OP_WRITE: 1393 case REQ_OP_WRITE:
1373 ret = queue_rw_req(hctx, req); 1394 ret = queue_rw_req(hctx, req);
1374 break; 1395 break;
1396 case REQ_OP_DISCARD:
1397 case REQ_OP_WRITE_ZEROES:
1398 ret = ubd_queue_one_vec(hctx, req, (u64)blk_rq_pos(req) << 9, NULL);
1399 break;
1375 default: 1400 default:
1376 WARN_ON_ONCE(1); 1401 WARN_ON_ONCE(1);
1377 res = BLK_STS_NOTSUPP; 1402 res = BLK_STS_NOTSUPP;
@@ -1463,7 +1488,7 @@ static int update_bitmap(struct io_thread_req *req)
1463 1488
1464 n = os_pwrite_file(req->fds[1], &req->bitmap_words, 1489 n = os_pwrite_file(req->fds[1], &req->bitmap_words,
1465 sizeof(req->bitmap_words), req->cow_offset); 1490 sizeof(req->bitmap_words), req->cow_offset);
1466 if(n != sizeof(req->bitmap_words)) 1491 if (n != sizeof(req->bitmap_words))
1467 return map_error(-n); 1492 return map_error(-n);
1468 1493
1469 return map_error(0); 1494 return map_error(0);
@@ -1471,11 +1496,13 @@ static int update_bitmap(struct io_thread_req *req)
1471 1496
1472static void do_io(struct io_thread_req *req) 1497static void do_io(struct io_thread_req *req)
1473{ 1498{
1474 char *buf; 1499 char *buf = NULL;
1475 unsigned long len; 1500 unsigned long len;
1476 int n, nsectors, start, end, bit; 1501 int n, nsectors, start, end, bit;
1477 __u64 off; 1502 __u64 off;
1478 1503
1504 /* FLUSH is really a special case, we cannot "case" it with others */
1505
1479 if (req_op(req->req) == REQ_OP_FLUSH) { 1506 if (req_op(req->req) == REQ_OP_FLUSH) {
1480 /* fds[0] is always either the rw image or our cow file */ 1507 /* fds[0] is always either the rw image or our cow file */
1481 req->error = map_error(-os_sync_file(req->fds[0])); 1508 req->error = map_error(-os_sync_file(req->fds[0]));
@@ -1495,26 +1522,42 @@ static void do_io(struct io_thread_req *req)
1495 off = req->offset + req->offsets[bit] + 1522 off = req->offset + req->offsets[bit] +
1496 start * req->sectorsize; 1523 start * req->sectorsize;
1497 len = (end - start) * req->sectorsize; 1524 len = (end - start) * req->sectorsize;
1498 buf = &req->buffer[start * req->sectorsize]; 1525 if (req->buffer != NULL)
1526 buf = &req->buffer[start * req->sectorsize];
1499 1527
1500 if (req_op(req->req) == REQ_OP_READ) { 1528 switch (req_op(req->req)) {
1529 case REQ_OP_READ:
1501 n = 0; 1530 n = 0;
1502 do { 1531 do {
1503 buf = &buf[n]; 1532 buf = &buf[n];
1504 len -= n; 1533 len -= n;
1505 n = os_pread_file(req->fds[bit], buf, len, off); 1534 n = os_pread_file(req->fds[bit], buf, len, off);
1506 if(n < 0){ 1535 if (n < 0) {
1507 req->error = map_error(-n); 1536 req->error = map_error(-n);
1508 return; 1537 return;
1509 } 1538 }
1510 } while((n < len) && (n != 0)); 1539 } while((n < len) && (n != 0));
1511 if (n < len) memset(&buf[n], 0, len - n); 1540 if (n < len) memset(&buf[n], 0, len - n);
1512 } else { 1541 break;
1542 case REQ_OP_WRITE:
1513 n = os_pwrite_file(req->fds[bit], buf, len, off); 1543 n = os_pwrite_file(req->fds[bit], buf, len, off);
1514 if(n != len){ 1544 if(n != len){
1515 req->error = map_error(-n); 1545 req->error = map_error(-n);
1516 return; 1546 return;
1517 } 1547 }
1548 break;
1549 case REQ_OP_DISCARD:
1550 case REQ_OP_WRITE_ZEROES:
1551 n = os_falloc_punch(req->fds[bit], off, len);
1552 if (n) {
1553 req->error = map_error(-n);
1554 return;
1555 }
1556 break;
1557 default:
1558 WARN_ON_ONCE(1);
1559 req->error = BLK_STS_NOTSUPP;
1560 return;
1518 } 1561 }
1519 1562
1520 start = end; 1563 start = end;