diff options
author | Emmanuel Dreyfus <manu@netbsd.org> | 2014-10-02 02:14:07 +0200 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-10-03 02:05:48 -0700 |
commit | baa6f0ad759af024e4731a0f3889fe857ae2f1bf (patch) | |
tree | 0e38bc2c2ee77fa6261e54d236e1d7c596629563 /xlators/storage | |
parent | a97ad9b69bb17f2351c59512fa9c6cb25d82b4da (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).
BUG: 1129939
Change-Id: I7db3567948bc8fa8d99ca5f5ba6647fe425186a9
Signed-off-by: Emmanuel Dreyfus <manu@netbsd.org>
Reviewed-on: http://review.gluster.org/8596
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>
Diffstat (limited to 'xlators/storage')
-rw-r--r-- | xlators/storage/posix/src/posix-handle.h | 22 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix.c | 34 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix.h | 3 |
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 4abea837765..6b12d39df79 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -5663,6 +5663,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); |