summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Dreyfus <manu@netbsd.org>2014-10-02 02:58:50 +0200
committerVijay Bellur <vbellur@redhat.com>2014-10-03 07:58:10 -0700
commit5ee6a5384ee298314e1ef50c293ad5cbc281c609 (patch)
tree13f903485093cbad80ce2de7e9f7af0da611c214
parent58aba738ef73fae01748ddf49c3f7ad03ecf733c (diff)
POSIX filesystem compliance: PATH_MAX
POSIX mandates the filesystem to support paths of lengths up to _XOPEN_PATH_MAX (1024). This is the PATH_MAX limit here: http://pubs.opengroup.org/onlinepubs/009604499/basedefs/limits.h.html When using a path of 1023 bytes, the posix xlator attempts to create an absolute path by prefixing the 1023 bytes path by the brick base path. The result is an absolute path of more than _XOPEN_PATH_MAX bytes which may be rejected by the backend filesystem. Linux's ext3fs PATH_MAX seems to defaut to 4096, which means it will work (except if brick base path is longer than 2072 bytes but it is unlikely to happen. NetBSD's FFS PATH_MAX defaults to 1024, which means the bug can happen regardless of brick base path length. If this condition is detected for a brick, the proposed fix is to chdir() the brick glusterfsd daemon to its brick base directory. Then when encountering a path that will exceed _XOPEN_PATH_MAX once prefixed by the brick base path, a relative path is used instead of an absolute one. We do not always use relative path because some operations require an absolute path on the brick base path itself (e.g.: statvfs). At least on NetBSD, this chdir() uncovers a race condition which causes file lookup to fail with ENODATA for a few seconds. The volume quickly reaches a sane state, but regression tests are fast enough to choke on it. The reason is obscure (as often with race conditions), but sleeping one second after the chdir() seems to change scheduling enough that the problem disapear. Note that since the chdir() is done if brick backend filesystem does not support path long enough, it will not occur with Linux ext3fs (except if brick base path is over 2072 bytes long). This is a backport of I7db3567948bc8fa8d99ca5f5ba6647fe425186a9 BUG: 1138897 Change-Id: Ib8eb3efaac8a7ba505d830623921338689229e9a Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org> Reviewed-on: http://review.gluster.org/8864 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Harshavardhana <harsha@harshavardhana.net> Tested-by: Harshavardhana <harsha@harshavardhana.net> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
-rw-r--r--xlators/storage/posix/src/posix-handle.h22
-rw-r--r--xlators/storage/posix/src/posix.c34
-rw-r--r--xlators/storage/posix/src/posix.h3
3 files changed, 55 insertions, 4 deletions
diff --git a/xlators/storage/posix/src/posix-handle.h b/xlators/storage/posix/src/posix-handle.h
index a34b936229b..0ce9575251f 100644
--- a/xlators/storage/posix/src/posix-handle.h
+++ b/xlators/storage/posix/src/posix-handle.h
@@ -15,10 +15,16 @@
#include "config.h"
#endif
+#include <limits.h>
#include <sys/types.h>
#include "xlator.h"
#include "gf-dirent.h"
+/* From Open Group Base Specifications Issue 6 */
+#ifndef _XOPEN_PATH_MAX
+#define _XOPEN_PATH_MAX 1024
+#endif
+
#define TRASH_DIR "landfill"
#define UUID0_STR "00000000-0000-0000-0000-000000000000"
@@ -120,10 +126,18 @@
} while (0)
#define MAKE_REAL_PATH(var, this, path) do { \
- var = alloca (strlen (path) + POSIX_BASE_PATH_LEN(this) + 2); \
- strcpy (var, POSIX_BASE_PATH(this)); \
- strcpy (&var[POSIX_BASE_PATH_LEN(this)], path); \
- } while (0)
+ size_t path_len = strlen(path); \
+ size_t var_len = path_len + POSIX_BASE_PATH_LEN(this) + 1; \
+ if (POSIX_PATH_MAX(this) != -1 && \
+ var_len >= POSIX_PATH_MAX(this)) { \
+ var = alloca (path_len + 1); \
+ strcpy (var, (path[0] == '/') ? path + 1 : path); \
+ } else { \
+ var = alloca (var_len); \
+ strcpy (var, POSIX_BASE_PATH(this)); \
+ strcpy (&var[POSIX_BASE_PATH_LEN(this)], path); \
+ } \
+ } while (0)
#define MAKE_HANDLE_PATH(var, this, gfid, base) do { \
int __len; \
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index 59b2535105b..a0027055fad 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -5662,6 +5662,40 @@ init (xlator_t *this)
_private->base_path = gf_strdup (dir_data->data);
_private->base_path_length = strlen (_private->base_path);
+ /*
+ * _XOPEN_PATH_MAX is the longest file path len we MUST
+ * support according to POSIX standard. When prepended
+ * by the brick base path it may exceed backed filesystem
+ * capacity (which MAY be bigger than _XOPEN_PATH_MAX). If
+ * this is the case, chdir() to the brick base path and
+ * use relative paths when they are too long. See also
+ * MAKE_REAL_PATH in posix-handle.h
+ */
+ _private->path_max = pathconf(_private->base_path, _PC_PATH_MAX);
+ if (_private->path_max != -1 &&
+ _XOPEN_PATH_MAX + _private->base_path_length > _private->path_max) {
+ ret = chdir(_private->base_path);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "chdir() to \"%s\" failed",
+ _private->base_path);
+ goto out;
+ }
+#ifdef __NetBSD__
+ /*
+ * At least on NetBSD, the chdir() above uncovers a
+ * race condition which cause file lookup to fail
+ * with ENODATA for a few seconds. The volume quickly
+ * reaches a sane state, but regression tests are fast
+ * enough to choke on it. The reason is obscure (as
+ * often with race conditions), but sleeping here for
+ * a second seems to workaround the problem.
+ */
+ sleep(1);
+#endif
+ }
+
+
LOCK_INIT (&_private->lock);
ret = dict_get_str (this->options, "hostname", &_private->hostname);
diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h
index efd52f00b18..5bb5e873c82 100644
--- a/xlators/storage/posix/src/posix.h
+++ b/xlators/storage/posix/src/posix.h
@@ -76,6 +76,7 @@ struct posix_fd {
struct posix_private {
char *base_path;
int32_t base_path_length;
+ int32_t path_max;
gf_lock_t lock;
@@ -189,6 +190,8 @@ typedef struct {
#define POSIX_BASE_PATH_LEN(this) (((struct posix_private *)this->private)->base_path_length)
+#define POSIX_PATH_MAX(this) (((struct posix_private *)this->private)->path_max)
+
/* Helper functions */
int posix_gfid_set (xlator_t *this, const char *path, loc_t *loc,
dict_t *xattr_req);