Skip to content

Commit 442ee66

Browse files
author
Robert Breker
committed
Add discard support to the block_aio driver
This commit enables discard for images accessed using block_aio: - For discard support, the image must be stored on a filesystem that supports hole punching. To determine this, there is a whitelist in util.c:is_hole_punching_supported_for_fd(), that filters based on the kernel version and filesystem. - Discard request are handled as synchronous hole punches into the image. This commit has been dev-tested using: * v8 Windows PV drivers that include XenDisk and thereby implement discard * Linux xen-blkfront that implements discard Signed-off-by: Robert Breker <robert.breker@citrix.com>
1 parent 1a51656 commit 442ee66

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

drivers/block-aio.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <sys/stat.h>
2929
#include <sys/ioctl.h>
3030
#include <linux/fs.h>
31+
#include <linux/falloc.h>
3132

3233
#include "tapdisk.h"
3334
#include "tapdisk-driver.h"
@@ -82,6 +83,11 @@ static int tdaio_get_image_info(int fd, td_disk_info_t *info)
8283
/*Local file? try fstat instead*/
8384
info->size = (stat.st_size >> SECTOR_SHIFT);
8485
info->sector_size = DEFAULT_SECTOR_SIZE;
86+
87+
if(is_hole_punching_supported_for_fd(fd)) {
88+
info->discard_supported = true;
89+
}
90+
8591
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
8692
"sector_shift [%llu]\n",
8793
(long long unsigned)(info->size << SECTOR_SHIFT),
@@ -212,6 +218,33 @@ void tdaio_queue_write(td_driver_t *driver, td_request_t treq)
212218
td_complete_request(treq, -EBUSY);
213219
}
214220

221+
void tdaio_discard(td_driver_t *driver, td_request_t treq)
222+
{
223+
int rc;
224+
off64_t size;
225+
off64_t offset;
226+
struct tdaio_state *prv;
227+
228+
if (driver->info.discard_supported != true) {
229+
td_complete_request(treq, -EOPNOTSUPP);
230+
return;
231+
}
232+
233+
prv = (struct tdaio_state *)driver->data;
234+
size = treq.vreq->discard_nr_sectors * driver->info.sector_size;
235+
offset = treq.vreq->sec * driver->info.sector_size;
236+
237+
rc = fallocate64(prv->fd, (FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE), offset, size);
238+
// Upper layers will retry on EINTR
239+
240+
// ToDo: Remove the following debug statement after feeling confident
241+
DPRINTF("fallocate64(%d, %d, %" PRIu64 ", %" PRIu64 ") returned %d", prv->fd,
242+
(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE), offset, size, rc);
243+
244+
td_complete_request(treq, rc);
245+
return;
246+
}
247+
215248
int tdaio_close(td_driver_t *driver)
216249
{
217250
struct tdaio_state *prv = (struct tdaio_state *)driver->data;
@@ -253,6 +286,7 @@ struct tap_disk tapdisk_aio = {
253286
.td_close = tdaio_close,
254287
.td_queue_read = tdaio_queue_read,
255288
.td_queue_write = tdaio_queue_write,
289+
.td_queue_discard = tdaio_discard,
256290
.td_get_parent_id = tdaio_get_parent_id,
257291
.td_validate_parent = tdaio_validate_parent,
258292
.td_debug = NULL,

drivers/tapdisk-utils.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
#include <string.h>
2626
#include <unistd.h>
2727
#include <linux/fs.h>
28+
#include <linux/magic.h>
2829
#include <sys/stat.h>
2930
#include <sys/mman.h>
3031
#include <sys/ioctl.h>
3132
#include <sys/resource.h>
3233
#include <sys/utsname.h>
34+
#include <sys/vfs.h>
3335
#include <arpa/inet.h>
3436

3537
#ifdef __linux__
@@ -431,3 +433,39 @@ inline long long timeval_to_us(struct timeval *tv)
431433
{
432434
return ((long long)tv->tv_sec * USEC_PER_SEC) + tv->tv_usec;
433435
}
436+
437+
bool is_hole_punching_supported_for_fd(int fd) {
438+
int rc;
439+
int kernel_version;
440+
struct statfs statfs_buf;
441+
442+
rc = fstatfs(fd, &statfs_buf);
443+
if (rc)
444+
return false;
445+
kernel_version = tapdisk_linux_version();
446+
if (-ENOSYS == kernel_version)
447+
return false;
448+
449+
// Support matrix according to man fallocate(2)
450+
switch (statfs_buf.f_type) {
451+
#ifdef BTRFS_SUPER_MAGIC
452+
case BTRFS_SUPER_MAGIC:
453+
return (kernel_version >= KERNEL_VERSION(3, 7, 0));
454+
#endif
455+
#ifdef EXT4_SUPER_MAGIC
456+
case EXT4_SUPER_MAGIC:
457+
return (kernel_version >= KERNEL_VERSION(3, 0, 0));
458+
#endif
459+
#ifdef TMPFS_SUPER_MAGIC
460+
case TMPFS_SUPER_MAGIC:
461+
return (kernel_version >= KERNEL_VERSION(3, 5, 0));
462+
#endif
463+
#ifdef XFS_SUPER_MAGIC
464+
case XFS_SUPER_MAGIC:
465+
return (kernel_version >= KERNEL_VERSION(2, 6, 38));
466+
#endif
467+
default:
468+
break;
469+
}
470+
return false;
471+
}

drivers/tapdisk-utils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define _TAPDISK_UTILS_H_
2020

2121
#include <inttypes.h>
22+
#include <stdbool.h>
2223
#include <sys/time.h>
2324
#include <sys/types.h>
2425
#include <sys/stat.h>
@@ -89,4 +90,10 @@ shm_destroy(struct shm *shm);
8990

9091
inline long long timeval_to_us(struct timeval *tv);
9192

93+
/**
94+
* Returns true if the filesystem that hosts the specified path is known to
95+
* allow hole punching and thereby discard.
96+
*/
97+
bool is_hole_punching_supported_for_fd(int fd);
98+
9299
#endif

0 commit comments

Comments
 (0)