cluster/ec: correctly handle end of file for seek
When a SEEK_HOLE was issued near to the end of file, sometimes an offset beyond the end of file was returned. Another problem was that using some offsets greater than the end of file returned successfully instead of failing with ENXIO. Change-Id: I238d2884ba02fd19a78116b0f8f8e8d6338fb3f5 BUG: 1449348 Signed-off-by: Xavier Hernandez <xhernandez@datalab.es> Reviewed-on: https://review.gluster.org/17228 Smoke: Gluster Build System <jenkins@build.gluster.org> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> CentOS-regression: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Amar Tumballi <amarts@redhat.com> Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
This commit is contained in:
parent
b25bf64f3a
commit
eb96dd45f8
57
tests/basic/ec/ec-seek.t
Normal file
57
tests/basic/ec/ec-seek.t
Normal file
@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
|
||||
. $(dirname $0)/../../include.rc
|
||||
. $(dirname $0)/../../volume.rc
|
||||
|
||||
cleanup
|
||||
|
||||
SEEK=$(dirname $0)/seek
|
||||
build_tester $(dirname $0)/seek.c -o ${SEEK}
|
||||
|
||||
TEST glusterd
|
||||
TEST pidof glusterd
|
||||
TEST $CLI volume info
|
||||
|
||||
TEST mkdir -p $B0/${V0}{0..2}
|
||||
TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2}
|
||||
|
||||
EXPECT "$V0" volinfo_field $V0 'Volume Name'
|
||||
EXPECT 'Created' volinfo_field $V0 'Status'
|
||||
EXPECT '3' brick_count $V0
|
||||
|
||||
TEST $CLI volume start $V0
|
||||
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status'
|
||||
|
||||
TEST $GFS -s $H0 --volfile-id $V0 $M0
|
||||
EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0
|
||||
|
||||
TEST ${SEEK} create ${M0}/test 0 1 1048576 1
|
||||
# Determine underlying filesystem allocation block size
|
||||
BSIZE="$(($(${SEEK} scan ${M0}/test hole 0) * 2))"
|
||||
|
||||
TEST ${SEEK} create ${M0}/test 0 ${BSIZE} $((${BSIZE} * 4 + 512)) ${BSIZE}
|
||||
|
||||
EXPECT "^0$" ${SEEK} scan ${M0}/test data 0
|
||||
EXPECT "^$((${BSIZE} / 2))$" ${SEEK} scan ${M0}/test data $((${BSIZE} / 2))
|
||||
EXPECT "^$((${BSIZE} - 1))$" ${SEEK} scan ${M0}/test data $((${BSIZE} - 1))
|
||||
EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data ${BSIZE}
|
||||
EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 4))
|
||||
EXPECT "^$((${BSIZE} * 5))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5))
|
||||
EXPECT "^$((${BSIZE} * 5 + 511))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 511))
|
||||
EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 512))
|
||||
EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 6))
|
||||
|
||||
EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole 0
|
||||
EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} / 2))
|
||||
EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} - 1))
|
||||
EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole ${BSIZE}
|
||||
EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 4))
|
||||
EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5))
|
||||
EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 511))
|
||||
EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 512))
|
||||
EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 6))
|
||||
|
||||
cleanup
|
||||
|
||||
# Centos6 regression slaves seem to not support SEEK_DATA/SEEK_HOLE
|
||||
#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000
|
185
tests/basic/ec/seek.c
Normal file
185
tests/basic/ec/seek.c
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
static char buffer[65536];
|
||||
|
||||
static int
|
||||
parse_int(const char *text, size_t *value)
|
||||
{
|
||||
char *ptr;
|
||||
size_t val;
|
||||
|
||||
val = strtoul(text, &ptr, 0);
|
||||
if (*ptr != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
fill_area(int fd, off_t offset, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
ssize_t res;
|
||||
|
||||
while (size > 0) {
|
||||
len = sizeof(buffer);
|
||||
if (len > size) {
|
||||
len = size;
|
||||
}
|
||||
res = pwrite(fd, buffer, len, offset);
|
||||
if (res < 0) {
|
||||
fprintf(stderr,
|
||||
"pwrite(%d, %p, %lu, %lu) failed: %d\n",
|
||||
fd, buffer, size, offset, errno);
|
||||
return 0;
|
||||
}
|
||||
if (res != len) {
|
||||
fprintf(stderr,
|
||||
"pwrite(%d, %p, %lu, %lu) didn't wrote all "
|
||||
"data: %lu/%lu\n",
|
||||
fd, buffer, size, offset, res, len);
|
||||
return 0;
|
||||
}
|
||||
offset += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
syntax(void)
|
||||
{
|
||||
fprintf(stderr, "Syntax: seek create <path> <offset> <size> [...]\n");
|
||||
fprintf(stderr, " seek scan <path> data|hole <offset>\n");
|
||||
}
|
||||
|
||||
static int
|
||||
seek_create(const char *path, int argc, char *argv[])
|
||||
{
|
||||
size_t off, size;
|
||||
int fd;
|
||||
int ret = 1;
|
||||
|
||||
fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Failed to create the file\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (argc > 0) {
|
||||
if (!parse_int(argv[0], &off) ||
|
||||
!parse_int(argv[1], &size)) {
|
||||
syntax();
|
||||
goto out_close;
|
||||
}
|
||||
if (!fill_area(fd, off, size)) {
|
||||
goto out_close;
|
||||
}
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out_close:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
seek_scan(const char *path, const char *type, const char *pos)
|
||||
{
|
||||
size_t off, res;
|
||||
int fd, whence;
|
||||
int ret = 1;
|
||||
|
||||
if (strcmp(type, "data") == 0) {
|
||||
whence = SEEK_DATA;
|
||||
} else if (strcmp(type, "hole") == 0) {
|
||||
whence = SEEK_HOLE;
|
||||
} else {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!parse_int(pos, &off)) {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Failed to open the file\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = lseek(fd, off, whence);
|
||||
if (res == (off_t)-1) {
|
||||
if (errno != ENXIO) {
|
||||
fprintf(stderr, "seek(%d, %lu, %d) failed: %d\n", fd,
|
||||
off, whence, errno);
|
||||
goto out_close;
|
||||
}
|
||||
fprintf(stdout, "ENXIO\n");
|
||||
} else {
|
||||
fprintf(stdout, "%lu\n", res);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out_close:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
memset(buffer, 0x55, sizeof(buffer));
|
||||
|
||||
if (argc < 3) {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "create") == 0) {
|
||||
if (((argc - 3) & 1) != 0) {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
ret = seek_create(argv[2], argc - 3, argv + 3);
|
||||
} else if (strcmp(argv[1], "scan") == 0) {
|
||||
if (argc != 5) {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
ret = seek_scan(argv[2], argv[3], argv[4]);
|
||||
} else {
|
||||
syntax();
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1556,6 +1556,7 @@ void ec_wind_seek(ec_t *ec, ec_fop_data_t *fop, int32_t idx)
|
||||
int32_t ec_manager_seek(ec_fop_data_t *fop, int32_t state)
|
||||
{
|
||||
ec_cbk_data_t *cbk;
|
||||
size_t size;
|
||||
|
||||
switch (state) {
|
||||
case EC_STATE_INIT:
|
||||
@ -1571,6 +1572,16 @@ int32_t ec_manager_seek(ec_fop_data_t *fop, int32_t state)
|
||||
return EC_STATE_DISPATCH;
|
||||
|
||||
case EC_STATE_DISPATCH:
|
||||
/* This shouldn't fail because we have the inode locked. */
|
||||
GF_ASSERT(ec_get_inode_size(fop, fop->locks[0].lock->loc.inode,
|
||||
&size));
|
||||
|
||||
if (fop->user_size >= size) {
|
||||
ec_fop_set_error(fop, ENXIO);
|
||||
|
||||
return EC_STATE_REPORT;
|
||||
}
|
||||
|
||||
ec_dispatch_one(fop);
|
||||
|
||||
return EC_STATE_PREPARE_ANSWER;
|
||||
@ -1582,10 +1593,17 @@ int32_t ec_manager_seek(ec_fop_data_t *fop, int32_t state)
|
||||
if ((cbk != NULL) && (cbk->op_ret >= 0)) {
|
||||
ec_t *ec = fop->xl->private;
|
||||
|
||||
/* This shouldn't fail because we have the inode locked. */
|
||||
GF_ASSERT(ec_get_inode_size(fop, fop->locks[0].lock->loc.inode,
|
||||
&size));
|
||||
|
||||
cbk->offset *= ec->fragments;
|
||||
if (cbk->offset < fop->user_size) {
|
||||
cbk->offset = fop->user_size;
|
||||
}
|
||||
if (cbk->offset > size) {
|
||||
cbk->offset = size;
|
||||
}
|
||||
}
|
||||
|
||||
return EC_STATE_REPORT;
|
||||
|
Loading…
x
Reference in New Issue
Block a user