351 lines
13 KiB
Plaintext
351 lines
13 KiB
Plaintext
$NetBSD: patch-9084,v 1.1 2014/11/18 14:38:15 manu Exp $
|
|
From 23b7ead5de0f21abdcf5440a4a43dcf3a42c3822 Mon Sep 17 00:00:00 2001
|
|
From: Emmanuel Dreyfus <manu@netbsd.org>
|
|
Date: Mon, 10 Nov 2014 10:01:00 +0100
|
|
Subject: [PATCH] telldir()/seekdir() portability fixes
|
|
|
|
POSIX says that an offset obtained from telldir() can only be used
|
|
on the same DIR *. Linux is abls to reuse the offset accross
|
|
closedir()/opendir() for a given directory, but this is not portable
|
|
and such a behavior should be fixed.
|
|
|
|
An incomplete fix for the posix xlator was merged in
|
|
http://review.gluster.org/8933
|
|
This change set completes it.
|
|
|
|
- Perform the same fix index xlator.
|
|
- Use appropriate casts and variable types so that 32 bit signed
|
|
offsets obtained by telldir() do not get clobbered when copied into
|
|
64 bit signed types.
|
|
- modify afr-self-heald.c so that it does not use anonymous fd,
|
|
since this will cause closedir()/opendir() between each
|
|
syncop_readdir(). On failure we fallback to anonymous fs
|
|
only for Linux so that we can cope with updated client vs not
|
|
updated brick.
|
|
- Avoid sending an EINVAL when the client request for the EOF offset.
|
|
Here we fix an error in previous fix for posix xlator: since we
|
|
fill each directory entry with the offset of the next entry, we
|
|
must consider as EOF the offset of the last entry, and not the
|
|
value of telldir() after we read it.
|
|
|
|
This is a backport of I59fb7f06a872c4f98987105792d648141c258c6a
|
|
|
|
BUG: 1138897
|
|
Change-Id: I1e9f3e4a7d780b98adf6d9f197ee2198d43ef94d
|
|
Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org>
|
|
---
|
|
xlators/cluster/afr/src/afr-self-heald.c | 46 +++++++++++++++++++++++++++-----
|
|
xlators/features/index/src/index.c | 42 ++++++++++++++++++++---------
|
|
xlators/features/index/src/index.h | 1 +
|
|
xlators/storage/posix/src/posix.c | 26 +++++++++++-------
|
|
4 files changed, 87 insertions(+), 28 deletions(-)
|
|
|
|
diff --git xlators/cluster/afr/src/afr-self-heald.c xlators/cluster/afr/src/afr-self-heald.c
|
|
index 10e1996..6ce52aa 100644
|
|
--- xlators/cluster/afr/src/afr-self-heald.c
|
|
+++ xlators/cluster/afr/src/afr-self-heald.c
|
|
@@ -276,6 +276,8 @@ afr_shd_index_opendir (xlator_t *this, int child)
|
|
#ifdef GF_LINUX_HOST_OS
|
|
fd_unref (fd);
|
|
fd = fd_anonymous (inode);
|
|
+ if (!fd)
|
|
+ goto out;
|
|
#else /* GF_LINUX_HOST_OS */
|
|
gf_log(this->name, GF_LOG_ERROR,
|
|
"opendir of %s for %s failed: %s",
|
|
@@ -429,7 +431,7 @@ afr_shd_index_sweep (struct subvol_healer *healer)
|
|
fd_t *fd = NULL;
|
|
xlator_t *subvol = NULL;
|
|
afr_private_t *priv = NULL;
|
|
- off_t offset = 0;
|
|
+ uint64_t offset = 0;
|
|
gf_dirent_t entries;
|
|
gf_dirent_t *entry = NULL;
|
|
uuid_t gfid;
|
|
@@ -503,11 +505,12 @@ afr_shd_index_sweep (struct subvol_healer *healer)
|
|
int
|
|
afr_shd_full_sweep (struct subvol_healer *healer, inode_t *inode)
|
|
{
|
|
+ loc_t loc = {0, };
|
|
fd_t *fd = NULL;
|
|
xlator_t *this = NULL;
|
|
xlator_t *subvol = NULL;
|
|
afr_private_t *priv = NULL;
|
|
- off_t offset = 0;
|
|
+ uint64_t offset = 0;
|
|
gf_dirent_t entries;
|
|
gf_dirent_t *entry = NULL;
|
|
int ret = 0;
|
|
@@ -516,9 +519,38 @@ afr_shd_full_sweep (struct subvol_healer *healer, inode_t *inode)
|
|
priv = this->private;
|
|
subvol = priv->children[healer->subvol];
|
|
|
|
- fd = fd_anonymous (inode);
|
|
- if (!fd)
|
|
- return -errno;
|
|
+ uuid_copy (loc.gfid, inode->gfid);
|
|
+ loc.inode = inode_ref(inode);
|
|
+
|
|
+ fd = fd_create (inode, GF_CLIENT_PID_AFR_SELF_HEALD);
|
|
+ if (!fd) {
|
|
+ gf_log(this->name, GF_LOG_ERROR,
|
|
+ "fd_create of %s failed: %s",
|
|
+ uuid_utoa (loc.gfid), strerror(errno));
|
|
+ ret = -errno;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = syncop_opendir (subvol, &loc, fd);
|
|
+ if (ret) {
|
|
+#ifdef GF_LINUX_HOST_OS /* See comment in afr_shd_index_opendir() */
|
|
+ fd_unref(fd);
|
|
+ fd = fd_anonymous (inode);
|
|
+ if (!fd) {
|
|
+ gf_log(this->name, GF_LOG_ERROR,
|
|
+ "fd_anonymous of %s failed: %s",
|
|
+ uuid_utoa (loc.gfid), strerror(errno));
|
|
+ ret = -errno;
|
|
+ goto out;
|
|
+ }
|
|
+#else /* GF_LINUX_HOST_OS */
|
|
+ gf_log(this->name, GF_LOG_ERROR,
|
|
+ "opendir of %s failed: %s",
|
|
+ uuid_utoa (loc.gfid), strerror(errno));
|
|
+ ret = -errno;
|
|
+ goto out;
|
|
+#endif /* GF_LINUX_HOST_OS */
|
|
+ }
|
|
|
|
INIT_LIST_HEAD (&entries.list);
|
|
|
|
@@ -560,6 +592,8 @@ afr_shd_full_sweep (struct subvol_healer *healer, inode_t *inode)
|
|
break;
|
|
}
|
|
|
|
+out:
|
|
+ loc_wipe (&loc);
|
|
if (fd)
|
|
fd_unref (fd);
|
|
return ret;
|
|
@@ -949,7 +983,7 @@ afr_shd_gather_index_entries (xlator_t *this, int child, dict_t *output)
|
|
fd_t *fd = NULL;
|
|
xlator_t *subvol = NULL;
|
|
afr_private_t *priv = NULL;
|
|
- off_t offset = 0;
|
|
+ uint64_t offset = 0;
|
|
gf_dirent_t entries;
|
|
gf_dirent_t *entry = NULL;
|
|
uuid_t gfid;
|
|
diff --git xlators/features/index/src/index.c xlators/features/index/src/index.c
|
|
index c342da8..50e2e0a 100644
|
|
--- xlators/features/index/src/index.c
|
|
+++ xlators/features/index/src/index.c
|
|
@@ -268,10 +268,11 @@ check_delete_stale_index_file (xlator_t *this, char *filename)
|
|
}
|
|
|
|
static int
|
|
-index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
+index_fill_readdir (fd_t *fd, index_fd_ctx_t *fctx, DIR *dir, off_t off,
|
|
size_t size, gf_dirent_t *entries)
|
|
{
|
|
off_t in_case = -1;
|
|
+ off_t last_off = 0;
|
|
size_t filled = 0;
|
|
int count = 0;
|
|
char entrybuf[sizeof(struct dirent) + 256 + 8];
|
|
@@ -286,11 +287,11 @@ index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
} else {
|
|
seekdir (dir, off);
|
|
#ifndef GF_LINUX_HOST_OS
|
|
- if (telldir(dir) != off) {
|
|
+ if ((u_long)telldir(dir) != off && off != fctx->dir_eof) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
- "seekdir(%ld) failed on dir=%p: "
|
|
+ "seekdir(0x%llx) failed on dir=%p: "
|
|
"Invalid argument (offset reused from "
|
|
- "another DIR * structure?)", (long)off, dir);
|
|
+ "another DIR * structure?)", off, dir);
|
|
errno = EINVAL;
|
|
count = -1;
|
|
goto out;
|
|
@@ -299,7 +300,7 @@ index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
}
|
|
|
|
while (filled <= size) {
|
|
- in_case = telldir (dir);
|
|
+ in_case = (u_long)telldir (dir);
|
|
|
|
if (in_case == -1) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
@@ -335,12 +336,13 @@ index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
if (this_size + filled > size) {
|
|
seekdir (dir, in_case);
|
|
#ifndef GF_LINUX_HOST_OS
|
|
- if (telldir(dir) != in_case) {
|
|
+ if ((u_long)telldir(dir) != in_case &&
|
|
+ in_case != fctx->dir_eof) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
- "seekdir(%ld) failed on dir=%p: "
|
|
+ "seekdir(0x%llx) failed on dir=%p: "
|
|
"Invalid argument (offset reused from "
|
|
"another DIR * structure?)",
|
|
- (long)in_case, dir);
|
|
+ in_case, dir);
|
|
errno = EINVAL;
|
|
count = -1;
|
|
goto out;
|
|
@@ -357,7 +359,14 @@ index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
entry->d_name, strerror (errno));
|
|
goto out;
|
|
}
|
|
- this_entry->d_off = telldir (dir);
|
|
+ /*
|
|
+ * we store the offset of next entry here, which is
|
|
+ * probably not intended, but code using syncop_readdir()
|
|
+ * (glfs-heal.c, afr-self-heald.c, pump.c) rely on it
|
|
+ * for directory read resumption.
|
|
+ */
|
|
+ last_off = (u_long)telldir(dir);
|
|
+ this_entry->d_off = last_off;
|
|
this_entry->d_ino = entry->d_ino;
|
|
|
|
list_add_tail (&this_entry->list, &entries->list);
|
|
@@ -366,9 +375,12 @@ index_fill_readdir (fd_t *fd, DIR *dir, off_t off,
|
|
count ++;
|
|
}
|
|
|
|
- if ((!readdir (dir) && (errno == 0)))
|
|
+ if ((!readdir (dir) && (errno == 0))) {
|
|
/* Indicate EOF */
|
|
errno = ENOENT;
|
|
+ /* Remember EOF offset for later detection */
|
|
+ fctx->dir_eof = last_off;
|
|
+ }
|
|
out:
|
|
return count;
|
|
}
|
|
@@ -581,6 +593,7 @@ __index_fd_ctx_get (fd_t *fd, xlator_t *this, index_fd_ctx_t **ctx)
|
|
fctx = NULL;
|
|
goto out;
|
|
}
|
|
+ fctx->dir_eof = -1;
|
|
|
|
ret = __fd_ctx_set (fd, this, (uint64_t)(long)fctx);
|
|
if (ret) {
|
|
@@ -949,7 +962,7 @@ index_readdir_wrapper (call_frame_t *frame, xlator_t *this,
|
|
goto done;
|
|
}
|
|
|
|
- count = index_fill_readdir (fd, dir, off, size, &entries);
|
|
+ count = index_fill_readdir (fd, fctx, dir, off, size, &entries);
|
|
|
|
/* pick ENOENT to indicate EOF */
|
|
op_errno = errno;
|
|
@@ -1270,8 +1283,11 @@ index_releasedir (xlator_t *this, fd_t *fd)
|
|
goto out;
|
|
|
|
fctx = (index_fd_ctx_t*) (long) ctx;
|
|
- if (fctx->dir)
|
|
- closedir (fctx->dir);
|
|
+ if (fctx->dir) {
|
|
+ ret = closedir (fctx->dir);
|
|
+ if (ret)
|
|
+ gf_log (this->name, GF_LOG_ERROR, "closedir error: %s", strerror (errno));
|
|
+ }
|
|
|
|
GF_FREE (fctx);
|
|
out:
|
|
diff --git xlators/features/index/src/index.h xlators/features/index/src/index.h
|
|
index 661dcdb..206d280 100644
|
|
--- xlators/features/index/src/index.h
|
|
+++ xlators/features/index/src/index.h
|
|
@@ -34,6 +34,7 @@ typedef struct index_inode_ctx {
|
|
|
|
typedef struct index_fd_ctx {
|
|
DIR *dir;
|
|
+ off_t dir_eof;
|
|
} index_fd_ctx_t;
|
|
|
|
typedef struct index_priv {
|
|
diff --git xlators/storage/posix/src/posix.c xlators/storage/posix/src/posix.c
|
|
index 3e3d14f..5d37c9f 100644
|
|
--- xlators/storage/posix/src/posix.c
|
|
+++ xlators/storage/posix/src/posix.c
|
|
@@ -4839,6 +4839,7 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
gf_dirent_t *entries, xlator_t *this, int32_t skip_dirs)
|
|
{
|
|
off_t in_case = -1;
|
|
+ off_t last_off = 0;
|
|
size_t filled = 0;
|
|
int count = 0;
|
|
char entrybuf[sizeof(struct dirent) + 256 + 8];
|
|
@@ -4874,11 +4875,11 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
} else {
|
|
seekdir (dir, off);
|
|
#ifndef GF_LINUX_HOST_OS
|
|
- if (telldir(dir) != (long)off && off != pfd->dir_eof) {
|
|
+ if ((u_long)telldir(dir) != off && off != pfd->dir_eof) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
- "seekdir(%ld) failed on dir=%p: "
|
|
+ "seekdir(0x%llx) failed on dir=%p: "
|
|
"Invalid argument (offset reused from "
|
|
- "another DIR * structure?)", (long)off, dir);
|
|
+ "another DIR * structure?)", off, dir);
|
|
errno = EINVAL;
|
|
count = -1;
|
|
goto out;
|
|
@@ -4887,7 +4888,7 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
}
|
|
|
|
while (filled <= size) {
|
|
- in_case = telldir (dir);
|
|
+ in_case = (u_long)telldir (dir);
|
|
|
|
if (in_case == -1) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
@@ -4947,13 +4948,13 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
if (this_size + filled > size) {
|
|
seekdir (dir, in_case);
|
|
#ifndef GF_LINUX_HOST_OS
|
|
- if (telldir(dir) != (long)in_case &&
|
|
+ if ((u_long)telldir(dir) != in_case &&
|
|
in_case != pfd->dir_eof) {
|
|
gf_log (THIS->name, GF_LOG_ERROR,
|
|
- "seekdir(%ld) failed on dir=%p: "
|
|
+ "seekdir(0x%llx) failed on dir=%p: "
|
|
"Invalid argument (offset reused from "
|
|
"another DIR * structure?)",
|
|
- (long)in_case, dir);
|
|
+ in_case, dir);
|
|
errno = EINVAL;
|
|
count = -1;
|
|
goto out;
|
|
@@ -4970,7 +4971,14 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
entry->d_name, strerror (errno));
|
|
goto out;
|
|
}
|
|
- this_entry->d_off = telldir (dir);
|
|
+ /*
|
|
+ * we store the offset of next entry here, which is
|
|
+ * probably not intended, but code using syncop_readdir()
|
|
+ * (glfs-heal.c, afr-self-heald.c, pump.c) rely on it
|
|
+ * for directory read resumption.
|
|
+ */
|
|
+ last_off = (u_long)telldir(dir);
|
|
+ this_entry->d_off = last_off;
|
|
this_entry->d_ino = entry->d_ino;
|
|
this_entry->d_type = entry->d_type;
|
|
|
|
@@ -4984,7 +4992,7 @@ posix_fill_readdir (fd_t *fd, DIR *dir, off_t off, size_t size,
|
|
/* Indicate EOF */
|
|
errno = ENOENT;
|
|
/* Remember EOF offset for later detection */
|
|
- pfd->dir_eof = telldir (dir);
|
|
+ pfd->dir_eof = (u_long)last_off;
|
|
}
|
|
out:
|
|
return count;
|
|
--
|
|
1.8.2.3
|
|
|