Skip to content

Commit 50109b5

Browse files
kot-begemot-ukrichardweinberger
authored andcommitted
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>
1 parent a41421e commit 50109b5

File tree

3 files changed

+65
-11
lines changed

3 files changed

+65
-11
lines changed

arch/um/drivers/ubd_kern.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ struct ubd {
154154
struct openflags openflags;
155155
unsigned shared:1;
156156
unsigned no_cow:1;
157+
unsigned no_trim:1;
157158
struct cow cow;
158159
struct platform_device pdev;
159160
struct request_queue *queue;
@@ -177,6 +178,7 @@ struct ubd {
177178
.boot_openflags = OPEN_FLAGS, \
178179
.openflags = OPEN_FLAGS, \
179180
.no_cow = 0, \
181+
.no_trim = 0, \
180182
.shared = 0, \
181183
.cow = DEFAULT_COW, \
182184
.lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
@@ -323,7 +325,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
323325
*index_out = n;
324326

325327
err = -EINVAL;
326-
for (i = 0; i < sizeof("rscd="); i++) {
328+
for (i = 0; i < sizeof("rscdt="); i++) {
327329
switch (*str) {
328330
case 'r':
329331
flags.w = 0;
@@ -337,12 +339,15 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out)
337339
case 'c':
338340
ubd_dev->shared = 1;
339341
break;
342+
case 't':
343+
ubd_dev->no_trim = 1;
344+
break;
340345
case '=':
341346
str++;
342347
goto break_loop;
343348
default:
344349
*error_out = "Expected '=' or flag letter "
345-
"(r, s, c, or d)";
350+
"(r, s, c, t or d)";
346351
goto out;
347352
}
348353
str++;
@@ -415,6 +420,7 @@ __uml_help(ubd_setup,
415420
" 'c' will cause the device to be treated as being shared between multiple\n"
416421
" UMLs and file locking will be turned off - this is appropriate for a\n"
417422
" 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"
418424
);
419425

420426
static int udb_setup(char *str)
@@ -513,9 +519,17 @@ static void ubd_handler(void)
513519
for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
514520
struct io_thread_req *io_req = (*irq_req_buffer)[count];
515521

516-
if (!blk_update_request(io_req->req, io_req->error, io_req->length))
517-
__blk_mq_end_request(io_req->req, io_req->error);
518-
522+
if ((io_req->error == BLK_STS_NOTSUPP) && (req_op(io_req->req) == REQ_OP_DISCARD)) {
523+
blk_queue_max_discard_sectors(io_req->req->q, 0);
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+
}
519533
kfree(io_req);
520534
}
521535
}
@@ -829,6 +843,13 @@ static int ubd_open_dev(struct ubd *ubd_dev)
829843
if(err < 0) goto error;
830844
ubd_dev->cow.fd = err;
831845
}
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+
}
832853
blk_queue_flag_set(QUEUE_FLAG_NONROT, ubd_dev->queue);
833854
return 0;
834855
error:
@@ -1372,6 +1393,10 @@ static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx,
13721393
case REQ_OP_WRITE:
13731394
ret = queue_rw_req(hctx, req);
13741395
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;
13751400
default:
13761401
WARN_ON_ONCE(1);
13771402
res = BLK_STS_NOTSUPP;
@@ -1463,19 +1488,21 @@ static int update_bitmap(struct io_thread_req *req)
14631488

14641489
n = os_pwrite_file(req->fds[1], &req->bitmap_words,
14651490
sizeof(req->bitmap_words), req->cow_offset);
1466-
if(n != sizeof(req->bitmap_words))
1491+
if (n != sizeof(req->bitmap_words))
14671492
return map_error(-n);
14681493

14691494
return map_error(0);
14701495
}
14711496

14721497
static void do_io(struct io_thread_req *req)
14731498
{
1474-
char *buf;
1499+
char *buf = NULL;
14751500
unsigned long len;
14761501
int n, nsectors, start, end, bit;
14771502
__u64 off;
14781503

1504+
/* FLUSH is really a special case, we cannot "case" it with others */
1505+
14791506
if (req_op(req->req) == REQ_OP_FLUSH) {
14801507
/* fds[0] is always either the rw image or our cow file */
14811508
req->error = map_error(-os_sync_file(req->fds[0]));
@@ -1495,26 +1522,42 @@ static void do_io(struct io_thread_req *req)
14951522
off = req->offset + req->offsets[bit] +
14961523
start * req->sectorsize;
14971524
len = (end - start) * req->sectorsize;
1498-
buf = &req->buffer[start * req->sectorsize];
1525+
if (req->buffer != NULL)
1526+
buf = &req->buffer[start * req->sectorsize];
14991527

1500-
if (req_op(req->req) == REQ_OP_READ) {
1528+
switch (req_op(req->req)) {
1529+
case REQ_OP_READ:
15011530
n = 0;
15021531
do {
15031532
buf = &buf[n];
15041533
len -= n;
15051534
n = os_pread_file(req->fds[bit], buf, len, off);
1506-
if(n < 0){
1535+
if (n < 0) {
15071536
req->error = map_error(-n);
15081537
return;
15091538
}
15101539
} while((n < len) && (n != 0));
15111540
if (n < len) memset(&buf[n], 0, len - n);
1512-
} else {
1541+
break;
1542+
case REQ_OP_WRITE:
15131543
n = os_pwrite_file(req->fds[bit], buf, len, off);
15141544
if(n != len){
15151545
req->error = map_error(-n);
15161546
return;
15171547
}
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;
15181561
}
15191562

15201563
start = end;

arch/um/include/shared/os.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ extern int os_fchange_dir(int fd);
175175
extern unsigned os_major(unsigned long long dev);
176176
extern unsigned os_minor(unsigned long long dev);
177177
extern unsigned long long os_makedev(unsigned major, unsigned minor);
178+
extern int os_falloc_punch(int fd, unsigned long long offset, int count);
178179

179180
/* start_up.c */
180181
extern void os_early_checks(void);

arch/um/os-Linux/file.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,13 @@ unsigned long long os_makedev(unsigned major, unsigned minor)
610610
{
611611
return makedev(major, minor);
612612
}
613+
614+
int os_falloc_punch(int fd, unsigned long long offset, int len)
615+
{
616+
int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len);
617+
618+
if (n < 0)
619+
return -errno;
620+
return n;
621+
}
622+

0 commit comments

Comments
 (0)