Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/cody/tags/block-pull-request' i…
Browse files Browse the repository at this point in the history
…nto staging

# gpg: Signature made Wed 29 Jun 2016 04:09:26 BST
# gpg:                using RSA key 0xBDBE7B27C0DE3057
# gpg: Good signature from "Jeffrey Cody <jcody@redhat.com>"
# gpg:                 aka "Jeffrey Cody <jeff@codyprime.org>"
# gpg:                 aka "Jeffrey Cody <codyprime@gmail.com>"
# Primary key fingerprint: 9957 4B4D 3474 90E7 9D98  D624 BDBE 7B27 C0DE 3057

* remotes/cody/tags/block-pull-request:
  mirror: fix misleading comments
  blockjob: assert(cb) when create job
  iotests: add small-granularity mirror test
  mirror: limit niov to IOV_MAX elements, again
  mirror: clarify mirror_do_read return code
  block/gluster: add support for selecting debug logging level
  mirror: fix trace_mirror_yield_in_flight usage in mirror_iteration()
  block/nfs: add support for libnfs pagecache
  block/nfs: refuse readahead if cache.direct is on
  block/gluster: add support for SEEK_DATA/SEEK_HOLE

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jun 29, 2016
2 parents 845d1e7 + 15d6729 commit ef8757f
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 18 deletions.
1 change: 0 additions & 1 deletion block/backup.c
Expand Up @@ -489,7 +489,6 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,

assert(bs);
assert(target);
assert(cb);

if (bs == target) {
error_setg(errp, "Source and target cannot be the same");
Expand Down
230 changes: 223 additions & 7 deletions block/gluster.c
Expand Up @@ -24,6 +24,8 @@ typedef struct GlusterAIOCB {
typedef struct BDRVGlusterState {
struct glfs *glfs;
struct glfs_fd *fd;
bool supports_seek_data;
int debug_level;
} BDRVGlusterState;

typedef struct GlusterConf {
Expand All @@ -32,6 +34,7 @@ typedef struct GlusterConf {
char *volname;
char *image;
char *transport;
int debug_level;
} GlusterConf;

static void qemu_gluster_gconf_free(GlusterConf *gconf)
Expand Down Expand Up @@ -194,11 +197,7 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
goto out;
}

/*
* TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
* GlusterFS makes GF_LOG_* macros available to libgfapi users.
*/
ret = glfs_set_logging(glfs, "-", 4);
ret = glfs_set_logging(glfs, "-", gconf->debug_level);
if (ret < 0) {
goto out;
}
Expand Down Expand Up @@ -256,16 +255,26 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
qemu_bh_schedule(acb->bh);
}

#define GLUSTER_OPT_FILENAME "filename"
#define GLUSTER_OPT_DEBUG "debug"
#define GLUSTER_DEBUG_DEFAULT 4
#define GLUSTER_DEBUG_MAX 9

/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
.name = "gluster",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "filename",
.name = GLUSTER_OPT_FILENAME,
.type = QEMU_OPT_STRING,
.help = "URL to the gluster image",
},
{
.name = GLUSTER_OPT_DEBUG,
.type = QEMU_OPT_NUMBER,
.help = "Gluster log level, valid range is 0-9",
},
{ /* end of list */ }
},
};
Expand All @@ -287,6 +296,28 @@ static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
}
}

/*
* Do SEEK_DATA/HOLE to detect if it is functional. Older broken versions of
* gfapi incorrectly return the current offset when SEEK_DATA/HOLE is used.
* - Corrected versions return -1 and set errno to EINVAL.
* - Versions that support SEEK_DATA/HOLE correctly, will return -1 and set
* errno to ENXIO when SEEK_DATA is called with a position of EOF.
*/
static bool qemu_gluster_test_seek(struct glfs_fd *fd)
{
off_t ret, eof;

eof = glfs_lseek(fd, 0, SEEK_END);
if (eof < 0) {
/* this should never occur */
return false;
}

/* this should always fail with ENXIO if SEEK_DATA is supported */
ret = glfs_lseek(fd, eof, SEEK_DATA);
return (ret < 0) && (errno == ENXIO);
}

static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
int bdrv_flags, Error **errp)
{
Expand All @@ -306,8 +337,17 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
goto out;
}

filename = qemu_opt_get(opts, "filename");
filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);

s->debug_level = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
GLUSTER_DEBUG_DEFAULT);
if (s->debug_level < 0) {
s->debug_level = 0;
} else if (s->debug_level > GLUSTER_DEBUG_MAX) {
s->debug_level = GLUSTER_DEBUG_MAX;
}

gconf->debug_level = s->debug_level;
s->glfs = qemu_gluster_init(gconf, filename, errp);
if (!s->glfs) {
ret = -errno;
Expand Down Expand Up @@ -338,6 +378,8 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
ret = -errno;
}

s->supports_seek_data = qemu_gluster_test_seek(s->fd);

out:
qemu_opts_del(opts);
qemu_gluster_gconf_free(gconf);
Expand All @@ -363,20 +405,24 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
int ret = 0;
BDRVGlusterState *s;
BDRVGlusterReopenState *reop_s;
GlusterConf *gconf = NULL;
int open_flags = 0;

assert(state != NULL);
assert(state->bs != NULL);

s = state->bs->opaque;

state->opaque = g_new0(BDRVGlusterReopenState, 1);
reop_s = state->opaque;

qemu_gluster_parse_flags(state->flags, &open_flags);

gconf = g_new0(GlusterConf, 1);

gconf->debug_level = s->debug_level;
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
if (reop_s->glfs == NULL) {
ret = -errno;
Expand Down Expand Up @@ -510,6 +556,14 @@ static int qemu_gluster_create(const char *filename,
char *tmp = NULL;
GlusterConf *gconf = g_new0(GlusterConf, 1);

gconf->debug_level = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
GLUSTER_DEBUG_DEFAULT);
if (gconf->debug_level < 0) {
gconf->debug_level = 0;
} else if (gconf->debug_level > GLUSTER_DEBUG_MAX) {
gconf->debug_level = GLUSTER_DEBUG_MAX;
}

glfs = qemu_gluster_init(gconf, filename, errp);
if (!glfs) {
ret = -errno;
Expand Down Expand Up @@ -727,6 +781,159 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs)
return 0;
}

/*
* Find allocation range in @bs around offset @start.
* May change underlying file descriptor's file offset.
* If @start is not in a hole, store @start in @data, and the
* beginning of the next hole in @hole, and return 0.
* If @start is in a non-trailing hole, store @start in @hole and the
* beginning of the next non-hole in @data, and return 0.
* If @start is in a trailing hole or beyond EOF, return -ENXIO.
* If we can't find out, return a negative errno other than -ENXIO.
*
* (Shamefully copied from raw-posix.c, only miniscule adaptions.)
*/
static int find_allocation(BlockDriverState *bs, off_t start,
off_t *data, off_t *hole)
{
BDRVGlusterState *s = bs->opaque;
off_t offs;

if (!s->supports_seek_data) {
return -ENOTSUP;
}

/*
* SEEK_DATA cases:
* D1. offs == start: start is in data
* D2. offs > start: start is in a hole, next data at offs
* D3. offs < 0, errno = ENXIO: either start is in a trailing hole
* or start is beyond EOF
* If the latter happens, the file has been truncated behind
* our back since we opened it. All bets are off then.
* Treating like a trailing hole is simplest.
* D4. offs < 0, errno != ENXIO: we learned nothing
*/
offs = glfs_lseek(s->fd, start, SEEK_DATA);
if (offs < 0) {
return -errno; /* D3 or D4 */
}
assert(offs >= start);

if (offs > start) {
/* D2: in hole, next data at offs */
*hole = start;
*data = offs;
return 0;
}

/* D1: in data, end not yet known */

/*
* SEEK_HOLE cases:
* H1. offs == start: start is in a hole
* If this happens here, a hole has been dug behind our back
* since the previous lseek().
* H2. offs > start: either start is in data, next hole at offs,
* or start is in trailing hole, EOF at offs
* Linux treats trailing holes like any other hole: offs ==
* start. Solaris seeks to EOF instead: offs > start (blech).
* If that happens here, a hole has been dug behind our back
* since the previous lseek().
* H3. offs < 0, errno = ENXIO: start is beyond EOF
* If this happens, the file has been truncated behind our
* back since we opened it. Treat it like a trailing hole.
* H4. offs < 0, errno != ENXIO: we learned nothing
* Pretend we know nothing at all, i.e. "forget" about D1.
*/
offs = glfs_lseek(s->fd, start, SEEK_HOLE);
if (offs < 0) {
return -errno; /* D1 and (H3 or H4) */
}
assert(offs >= start);

if (offs > start) {
/*
* D1 and H2: either in data, next hole at offs, or it was in
* data but is now in a trailing hole. In the latter case,
* all bets are off. Treating it as if it there was data all
* the way to EOF is safe, so simply do that.
*/
*data = start;
*hole = offs;
return 0;
}

/* D1 and H1 */
return -EBUSY;
}

/*
* Returns the allocation status of the specified sectors.
*
* If 'sector_num' is beyond the end of the disk image the return value is 0
* and 'pnum' is set to 0.
*
* 'pnum' is set to the number of sectors (including and immediately following
* the specified sector) that are known to be in the same
* allocated/unallocated state.
*
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
* beyond the end of the disk image it will be clamped.
*
* (Based on raw_co_get_block_status() from raw-posix.c.)
*/
static int64_t coroutine_fn qemu_gluster_co_get_block_status(
BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
BlockDriverState **file)
{
BDRVGlusterState *s = bs->opaque;
off_t start, data = 0, hole = 0;
int64_t total_size;
int ret = -EINVAL;

if (!s->fd) {
return ret;
}

start = sector_num * BDRV_SECTOR_SIZE;
total_size = bdrv_getlength(bs);
if (total_size < 0) {
return total_size;
} else if (start >= total_size) {
*pnum = 0;
return 0;
} else if (start + nb_sectors * BDRV_SECTOR_SIZE > total_size) {
nb_sectors = DIV_ROUND_UP(total_size - start, BDRV_SECTOR_SIZE);
}

ret = find_allocation(bs, start, &data, &hole);
if (ret == -ENXIO) {
/* Trailing hole */
*pnum = nb_sectors;
ret = BDRV_BLOCK_ZERO;
} else if (ret < 0) {
/* No info available, so pretend there are no holes */
*pnum = nb_sectors;
ret = BDRV_BLOCK_DATA;
} else if (data == start) {
/* On a data extent, compute sectors to the end of the extent,
* possibly including a partial sector at EOF. */
*pnum = MIN(nb_sectors, DIV_ROUND_UP(hole - start, BDRV_SECTOR_SIZE));
ret = BDRV_BLOCK_DATA;
} else {
/* On a hole, compute sectors to the beginning of the next extent. */
assert(hole == start);
*pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
ret = BDRV_BLOCK_ZERO;
}

*file = bs;

return ret | BDRV_BLOCK_OFFSET_VALID | start;
}


static QemuOptsList qemu_gluster_create_opts = {
.name = "qemu-gluster-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
Expand All @@ -741,6 +948,11 @@ static QemuOptsList qemu_gluster_create_opts = {
.type = QEMU_OPT_STRING,
.help = "Preallocation mode (allowed values: off, full)"
},
{
.name = GLUSTER_OPT_DEBUG,
.type = QEMU_OPT_NUMBER,
.help = "Gluster log level, valid range is 0-9",
},
{ /* end of list */ }
}
};
Expand Down Expand Up @@ -769,6 +981,7 @@ static BlockDriver bdrv_gluster = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
.create_opts = &qemu_gluster_create_opts,
};

Expand Down Expand Up @@ -796,6 +1009,7 @@ static BlockDriver bdrv_gluster_tcp = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
.create_opts = &qemu_gluster_create_opts,
};

Expand Down Expand Up @@ -823,6 +1037,7 @@ static BlockDriver bdrv_gluster_unix = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
.create_opts = &qemu_gluster_create_opts,
};

Expand Down Expand Up @@ -850,6 +1065,7 @@ static BlockDriver bdrv_gluster_rdma = {
#ifdef CONFIG_GLUSTERFS_ZEROFILL
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
#endif
.bdrv_co_get_block_status = qemu_gluster_co_get_block_status,
.create_opts = &qemu_gluster_create_opts,
};

Expand Down

0 comments on commit ef8757f

Please sign in to comment.