summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/basic/ec/ec-seek.t57
-rw-r--r--tests/basic/ec/seek.c185
-rw-r--r--xlators/cluster/ec/src/ec-inode-read.c18
3 files changed, 260 insertions, 0 deletions
diff --git a/tests/basic/ec/ec-seek.t b/tests/basic/ec/ec-seek.t
new file mode 100644
index 00000000000..6a0060870c8
--- /dev/null
+++ b/tests/basic/ec/ec-seek.t
@@ -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
diff --git a/tests/basic/ec/seek.c b/tests/basic/ec/seek.c
new file mode 100644
index 00000000000..67036ad4e75
--- /dev/null
+++ b/tests/basic/ec/seek.c
@@ -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;
+}
+
diff --git a/xlators/cluster/ec/src/ec-inode-read.c b/xlators/cluster/ec/src/ec-inode-read.c
index d03b4483a67..d925e82ba36 100644
--- a/xlators/cluster/ec/src/ec-inode-read.c
+++ b/xlators/cluster/ec/src/ec-inode-read.c
@@ -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;