summaryrefslogtreecommitdiffstats
path: root/xlators/storage/posix/src/posix-helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/storage/posix/src/posix-helpers.c')
-rw-r--r--xlators/storage/posix/src/posix-helpers.c893
1 files changed, 700 insertions, 193 deletions
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
index d2cf880fb..e295f8850 100644
--- a/xlators/storage/posix/src/posix-helpers.c
+++ b/xlators/storage/posix/src/posix-helpers.c
@@ -1,22 +1,12 @@
/*
- Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com>
- This file is part of GlusterFS.
-
- GlusterFS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- GlusterFS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-*/
+ Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
@@ -32,13 +22,13 @@
#include <pthread.h>
#include <ftw.h>
#include <sys/stat.h>
+#include <signal.h>
#ifndef GF_BSD_HOST_OS
#include <alloca.h>
#endif /* GF_BSD_HOST_OS */
#include "glusterfs.h"
-#include "md5.h"
#include "checksum.h"
#include "dict.h"
#include "logging.h"
@@ -55,15 +45,12 @@
#include "timer.h"
#include "glusterfs3-xdr.h"
#include "hashfn.h"
+#include "glusterfs-acl.h"
+#include <fnmatch.h>
-
-typedef struct {
- xlator_t *this;
- const char *real_path;
- dict_t *xattr;
- struct iatt *stbuf;
- loc_t *loc;
-} posix_xattr_filler_t;
+char *marker_xattrs[] = {"trusted.glusterfs.quota.*",
+ "trusted.glusterfs.*.xtime",
+ NULL};
static char* posix_ignore_xattrs[] = {
"gfid-req",
@@ -73,6 +60,25 @@ static char* posix_ignore_xattrs[] = {
NULL
};
+gf_boolean_t
+posix_special_xattr (char **pattern, char *key)
+{
+ int i = 0;
+ gf_boolean_t flag = _gf_false;
+
+ GF_VALIDATE_OR_GOTO ("posix", pattern, out);
+ GF_VALIDATE_OR_GOTO ("posix", key, out);
+
+ for (i = 0; pattern[i]; i++) {
+ if (!fnmatch (pattern[i], key, 0)) {
+ flag = _gf_true;
+ break;
+ }
+ }
+out:
+ return flag;
+}
+
static gf_boolean_t
posix_xattr_ignorable (char *key, posix_xattr_filler_t *filler)
{
@@ -95,7 +101,7 @@ out:
return ignore;
}
-static void
+static int
_posix_xattr_get_set (dict_t *xattr_req,
char *key,
data_t *data,
@@ -165,19 +171,13 @@ _posix_xattr_get_set (dict_t *xattr_req,
err:
if (_fd != -1)
close (_fd);
- if (databuf)
- GF_FREE (databuf);
+ GF_FREE (databuf);
}
} else if (!strcmp (key, GLUSTERFS_OPEN_FD_COUNT)) {
loc = filler->loc;
- if (!list_empty (&loc->inode->fd_list)) {
- ret = dict_set_uint32 (filler->xattr, key, 1);
- if (ret < 0)
- gf_log (filler->this->name, GF_LOG_WARNING,
- "Failed to set dictionary value for %s",
- key);
- } else {
- ret = dict_set_uint32 (filler->xattr, key, 0);
+ if (loc) {
+ ret = dict_set_uint32 (filler->xattr, key,
+ loc->inode->fd_count);
if (ret < 0)
gf_log (filler->this->name, GF_LOG_WARNING,
"Failed to set dictionary value for %s",
@@ -190,22 +190,31 @@ _posix_xattr_get_set (dict_t *xattr_req,
value = GF_CALLOC (1, xattr_size + 1,
gf_posix_mt_char);
if (!value)
- return;
+ return -1;
- sys_lgetxattr (filler->real_path, key, value,
- xattr_size);
+ xattr_size = sys_lgetxattr (filler->real_path, key, value,
+ xattr_size);
+ if (xattr_size <= 0) {
+ gf_log (filler->this->name, GF_LOG_WARNING,
+ "getxattr failed. path: %s, key: %s",
+ filler->real_path, key);
+ GF_FREE (value);
+ return -1;
+ }
value[xattr_size] = '\0';
ret = dict_set_bin (filler->xattr, key,
value, xattr_size);
- if (ret < 0)
+ if (ret < 0) {
gf_log (filler->this->name, GF_LOG_DEBUG,
"dict set failed. path: %s, key: %s",
filler->real_path, key);
+ GF_FREE (value);
+ }
}
}
out:
- return;
+ return 0;
}
@@ -213,14 +222,17 @@ int
posix_fill_gfid_path (xlator_t *this, const char *path, struct iatt *iatt)
{
int ret = 0;
+ ssize_t size = 0;
if (!iatt)
return 0;
- ret = sys_lgetxattr (path, GFID_XATTR_KEY, iatt->ia_gfid, 16);
+ size = sys_lgetxattr (path, GFID_XATTR_KEY, iatt->ia_gfid, 16);
/* Return value of getxattr */
- if ((ret == 16) || (ret == -1))
+ if ((size == 16) || (size == -1))
ret = 0;
+ else
+ ret = size;
return ret;
}
@@ -230,14 +242,17 @@ int
posix_fill_gfid_fd (xlator_t *this, int fd, struct iatt *iatt)
{
int ret = 0;
+ ssize_t size = 0;
if (!iatt)
return 0;
- ret = sys_fgetxattr (fd, GFID_XATTR_KEY, iatt->ia_gfid, 16);
+ size = sys_fgetxattr (fd, GFID_XATTR_KEY, iatt->ia_gfid, 16);
/* Return value of getxattr */
- if ((ret == 16) || (ret == -1))
+ if ((size == 16) || (size == -1))
ret = 0;
+ else
+ ret = size;
return ret;
}
@@ -255,7 +270,7 @@ posix_fill_ino_from_gfid (xlator_t *this, struct iatt *buf)
goto out;
}
for (i = 15; i > (15 - 8); i--) {
- temp_ino += buf->ia_gfid[i] << j;
+ temp_ino += (uint64_t)(buf->ia_gfid[i]) << j;
j += 8;
}
buf->ia_ino = temp_ino;
@@ -264,19 +279,22 @@ out:
}
int
-posix_lstat_with_gfid (xlator_t *this, const char *path, struct iatt *stbuf_p)
+posix_fdstat (xlator_t *this, int fd, struct iatt *stbuf_p)
{
int ret = 0;
- struct stat lstatbuf = {0, };
+ struct stat fstatbuf = {0, };
struct iatt stbuf = {0, };
- ret = lstat (path, &lstatbuf);
+ ret = fstat (fd, &fstatbuf);
if (ret == -1)
goto out;
- iatt_from_stat (&stbuf, &lstatbuf);
+ if (fstatbuf.st_nlink && !S_ISDIR (fstatbuf.st_mode))
+ fstatbuf.st_nlink--;
- ret = posix_fill_gfid_path (this, path, &stbuf);
+ iatt_from_stat (&stbuf, &fstatbuf);
+
+ ret = posix_fill_gfid_fd (this, fd, &stbuf);
if (ret)
gf_log_callingfn (this->name, GF_LOG_DEBUG, "failed to get gfid");
@@ -284,33 +302,125 @@ posix_lstat_with_gfid (xlator_t *this, const char *path, struct iatt *stbuf_p)
if (stbuf_p)
*stbuf_p = stbuf;
+
out:
return ret;
}
int
-posix_fstat_with_gfid (xlator_t *this, int fd, struct iatt *stbuf_p)
+posix_istat (xlator_t *this, uuid_t gfid, const char *basename,
+ struct iatt *buf_p)
{
- int ret = 0;
- struct stat fstatbuf = {0, };
- struct iatt stbuf = {0, };
+ char *real_path = NULL;
+ struct stat lstatbuf = {0, };
+ struct iatt stbuf = {0, };
+ int ret = 0;
+ struct posix_private *priv = NULL;
- ret = fstat (fd, &fstatbuf);
- if (ret == -1)
+
+ priv = this->private;
+
+ MAKE_HANDLE_PATH (real_path, this, gfid, basename);
+
+ ret = lstat (real_path, &lstatbuf);
+
+ if (ret != 0) {
+ if (ret == -1) {
+ if (errno != ENOENT && errno != ELOOP)
+ gf_log (this->name, GF_LOG_WARNING,
+ "lstat failed on %s (%s)",
+ real_path, strerror (errno));
+ } else {
+ // may be some backend filesystem issue
+ gf_log (this->name, GF_LOG_ERROR, "lstat failed on "
+ "%s and return value is %d instead of -1. "
+ "Please see dmesg output to check whether the "
+ "failure is due to backend filesystem issue",
+ real_path, ret);
+ ret = -1;
+ }
goto out;
+ }
- iatt_from_stat (&stbuf, &fstatbuf);
+ if ((lstatbuf.st_ino == priv->handledir.st_ino) &&
+ (lstatbuf.st_dev == priv->handledir.st_dev)) {
+ errno = ENOENT;
+ return -1;
+ }
- ret = posix_fill_gfid_fd (this, fd, &stbuf);
- if (ret)
- gf_log_callingfn (this->name, GF_LOG_DEBUG, "failed to get gfid");
+ if (!S_ISDIR (lstatbuf.st_mode))
+ lstatbuf.st_nlink --;
+
+ iatt_from_stat (&stbuf, &lstatbuf);
+
+ if (basename)
+ posix_fill_gfid_path (this, real_path, &stbuf);
+ else
+ uuid_copy (stbuf.ia_gfid, gfid);
posix_fill_ino_from_gfid (this, &stbuf);
- if (stbuf_p)
- *stbuf_p = stbuf;
+ if (buf_p)
+ *buf_p = stbuf;
+out:
+ return ret;
+}
+
+
+int
+posix_pstat (xlator_t *this, uuid_t gfid, const char *path,
+ struct iatt *buf_p)
+{
+ struct stat lstatbuf = {0, };
+ struct iatt stbuf = {0, };
+ int ret = 0;
+ struct posix_private *priv = NULL;
+
+
+ priv = this->private;
+
+ ret = lstat (path, &lstatbuf);
+
+ if (ret != 0) {
+ if (ret == -1) {
+ if (errno != ENOENT)
+ gf_log (this->name, GF_LOG_WARNING,
+ "lstat failed on %s (%s)",
+ path, strerror (errno));
+ } else {
+ // may be some backend filesytem issue
+ gf_log (this->name, GF_LOG_ERROR, "lstat failed on "
+ "%s and return value is %d instead of -1. "
+ "Please see dmesg output to check whether the "
+ "failure is due to backend filesystem issue",
+ path, ret);
+ ret = -1;
+ }
+ goto out;
+ }
+
+ if ((lstatbuf.st_ino == priv->handledir.st_ino) &&
+ (lstatbuf.st_dev == priv->handledir.st_dev)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (!S_ISDIR (lstatbuf.st_mode))
+ lstatbuf.st_nlink --;
+
+ iatt_from_stat (&stbuf, &lstatbuf);
+
+ if (gfid && !uuid_is_null (gfid))
+ uuid_copy (stbuf.ia_gfid, gfid);
+ else
+ posix_fill_gfid_path (this, path, &stbuf);
+
+ posix_fill_ino_from_gfid (this, &stbuf);
+
+ if (buf_p)
+ *buf_p = stbuf;
out:
return ret;
}
@@ -340,83 +450,50 @@ out:
}
-/*
- * If the parent directory of {real_path} has the setgid bit set,
- * then set {gid} to the gid of the parent. Otherwise,
- * leave {gid} unchanged.
- */
-
int
-setgid_override (xlator_t *this, char *real_path, gid_t *gid)
-{
- char * tmp_path = NULL;
- char * parent_path = NULL;
- struct iatt parent_stbuf;
-
- int op_ret = 0;
-
- tmp_path = gf_strdup (real_path);
- if (!tmp_path) {
- op_ret = -ENOMEM;
- goto out;
- }
-
- parent_path = dirname (tmp_path);
-
- op_ret = posix_lstat_with_gfid (this, parent_path, &parent_stbuf);
- if (op_ret == -1) {
- op_ret = -errno;
- gf_log_callingfn (this->name, GF_LOG_ERROR,
- "lstat on parent directory (%s) failed: %s",
- parent_path, strerror (errno));
- goto out;
- }
-
- if (parent_stbuf.ia_prot.sgid) {
- /*
- * Entries created inside a setgid directory
- * should inherit the gid from the parent
- */
-
- *gid = parent_stbuf.ia_gid;
- }
-out:
-
- if (tmp_path)
- GF_FREE (tmp_path);
-
- return op_ret;
-}
-
-
-int
-posix_gfid_set (xlator_t *this, const char *path, dict_t *xattr_req)
+posix_gfid_set (xlator_t *this, const char *path, loc_t *loc, dict_t *xattr_req)
{
void *uuid_req = NULL;
uuid_t uuid_curr;
int ret = 0;
+ ssize_t size = 0;
struct stat stat = {0, };
+
if (!xattr_req)
goto out;
if (sys_lstat (path, &stat) != 0)
goto out;
- ret = sys_lgetxattr (path, GFID_XATTR_KEY, uuid_curr, 16);
- if (ret == 16) {
+ size = sys_lgetxattr (path, GFID_XATTR_KEY, uuid_curr, 16);
+ if (size == 16) {
ret = 0;
- goto out;
+ goto verify_handle;
}
ret = dict_get_ptr (xattr_req, "gfid-req", &uuid_req);
if (ret) {
- gf_log_callingfn (this->name, GF_LOG_DEBUG,
- "failed to get the gfid from dict");
+ gf_log (this->name, GF_LOG_DEBUG,
+ "failed to get the gfid from dict for %s",
+ loc->path);
goto out;
}
ret = sys_lsetxattr (path, GFID_XATTR_KEY, uuid_req, 16, XATTR_CREATE);
+ if (ret != 0) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "setting GFID on %s failed (%s)", path,
+ strerror (errno));
+ goto out;
+ }
+ uuid_copy (uuid_curr, uuid_req);
+
+verify_handle:
+ if (!S_ISDIR (stat.st_mode))
+ ret = posix_handle_hard (this, path, uuid_curr, &stat);
+ else
+ ret = posix_handle_soft (this, path, loc, uuid_curr, &stat);
out:
return ret;
@@ -424,36 +501,39 @@ out:
int
-posix_set_file_contents (xlator_t *this, const char *real_path,
- data_pair_t *trav, int flags)
+posix_set_file_contents (xlator_t *this, const char *path, char *keyp,
+ data_t *value, int flags)
{
char * key = NULL;
- char real_filepath[ZR_PATH_MAX] = {0,};
+ char real_path[PATH_MAX];
int32_t file_fd = -1;
int op_ret = 0;
int ret = -1;
- key = &(trav->key[15]);
- sprintf (real_filepath, "%s/%s", real_path, key);
+
+ /* XXX: does not handle assigning GFID to created files */
+ return -1;
+
+ key = &(keyp[15]);
+ sprintf (real_path, "%s/%s", path, key);
if (flags & XATTR_REPLACE) {
/* if file exists, replace it
* else, error out */
- file_fd = open (real_filepath, O_TRUNC|O_WRONLY);
+ file_fd = open (real_path, O_TRUNC|O_WRONLY);
if (file_fd == -1) {
goto create;
}
- if (trav->value->len) {
- ret = write (file_fd, trav->value->data,
- trav->value->len);
+ if (value->len) {
+ ret = write (file_fd, value->data, value->len);
if (ret == -1) {
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR,
"write failed while doing setxattr "
"for key %s on path %s: %s",
- key, real_filepath, strerror (errno));
+ key, real_path, strerror (errno));
goto out;
}
@@ -462,14 +542,14 @@ posix_set_file_contents (xlator_t *this, const char *real_path,
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR,
"close failed on %s: %s",
- real_filepath, strerror (errno));
+ real_path, strerror (errno));
goto out;
}
}
create: /* we know file doesn't exist, create it */
- file_fd = open (real_filepath, O_CREAT|O_WRONLY, 0644);
+ file_fd = open (real_path, O_CREAT|O_WRONLY, 0644);
if (file_fd == -1) {
op_ret = -errno;
@@ -479,13 +559,13 @@ posix_set_file_contents (xlator_t *this, const char *real_path,
goto out;
}
- ret = write (file_fd, trav->value->data, trav->value->len);
+ ret = write (file_fd, value->data, value->len);
if (ret == -1) {
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR,
"write failed on %s while setxattr with "
"key %s: %s",
- real_filepath, key, strerror (errno));
+ real_path, key, strerror (errno));
goto out;
}
@@ -495,7 +575,7 @@ posix_set_file_contents (xlator_t *this, const char *real_path,
gf_log (this->name, GF_LOG_ERROR,
"close failed on %s while setxattr with "
"key %s: %s",
- real_filepath, key, strerror (errno));
+ real_path, key, strerror (errno));
goto out;
}
}
@@ -506,33 +586,32 @@ out:
int
-posix_get_file_contents (xlator_t *this, const char *real_path,
+posix_get_file_contents (xlator_t *this, uuid_t pargfid,
const char *name, char **contents)
{
- char real_filepath[ZR_PATH_MAX] = {0,};
- char * key = NULL;
+ char *real_path = NULL;
int32_t file_fd = -1;
struct iatt stbuf = {0,};
int op_ret = 0;
int ret = -1;
- key = (char *) &(name[15]);
- sprintf (real_filepath, "%s/%s", real_path, key);
- op_ret = posix_lstat_with_gfid (this, real_filepath, &stbuf);
+ MAKE_HANDLE_PATH (real_path, this, pargfid, name);
+
+ op_ret = posix_istat (this, pargfid, name, &stbuf);
if (op_ret == -1) {
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR, "lstat failed on %s: %s",
- real_filepath, strerror (errno));
+ real_path, strerror (errno));
goto out;
}
- file_fd = open (real_filepath, O_RDONLY);
+ file_fd = open (real_path, O_RDONLY);
if (file_fd == -1) {
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR, "open failed on %s: %s",
- real_filepath, strerror (errno));
+ real_path, strerror (errno));
goto out;
}
@@ -547,7 +626,7 @@ posix_get_file_contents (xlator_t *this, const char *real_path,
if (ret <= 0) {
op_ret = -1;
gf_log (this->name, GF_LOG_ERROR, "read on %s failed: %s",
- real_filepath, strerror (errno));
+ real_path, strerror (errno));
goto out;
}
@@ -558,14 +637,13 @@ posix_get_file_contents (xlator_t *this, const char *real_path,
if (op_ret == -1) {
op_ret = -errno;
gf_log (this->name, GF_LOG_ERROR, "close on %s failed: %s",
- real_filepath, strerror (errno));
+ real_path, strerror (errno));
goto out;
}
out:
if (op_ret < 0) {
- if (*contents)
- GF_FREE (*contents);
+ GF_FREE (*contents);
if (file_fd != -1)
close (file_fd);
}
@@ -577,28 +655,33 @@ static int gf_xattr_enotsup_log;
int
posix_handle_pair (xlator_t *this, const char *real_path,
- data_pair_t *trav, int flags)
+ char *key, data_t *value, int flags)
{
int sys_ret = -1;
int ret = 0;
- if (ZR_FILE_CONTENT_REQUEST(trav->key)) {
- ret = posix_set_file_contents (this, real_path, trav, flags);
+ if (ZR_FILE_CONTENT_REQUEST(key)) {
+ ret = posix_set_file_contents (this, real_path, key, value,
+ flags);
} else {
- sys_ret = sys_lsetxattr (real_path, trav->key,
- trav->value->data,
- trav->value->len, flags);
+ sys_ret = sys_lsetxattr (real_path, key, value->data,
+ value->len, flags);
if (sys_ret < 0) {
if (errno == ENOTSUP) {
GF_LOG_OCCASIONALLY(gf_xattr_enotsup_log,
this->name,GF_LOG_WARNING,
"Extended attributes not "
- "supported");
+ "supported (try remounting "
+ "brick with 'user_xattr' "
+ "flag)");
} else if (errno == ENOENT) {
- gf_log (this->name, GF_LOG_ERROR,
- "setxattr on %s failed: %s", real_path,
- strerror (errno));
+ if (!posix_special_xattr (marker_xattrs,
+ key)) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "setxattr on %s failed: %s",
+ real_path, strerror (errno));
+ }
} else {
#ifdef GF_DARWIN_HOST_OS
@@ -606,12 +689,12 @@ posix_handle_pair (xlator_t *this, const char *real_path,
((errno == EINVAL) ?
GF_LOG_DEBUG : GF_LOG_ERROR),
"%s: key:%s error:%s",
- real_path, trav->key,
+ real_path, key,
strerror (errno));
#else /* ! DARWIN */
gf_log (this->name, GF_LOG_ERROR,
"%s: key:%s error:%s",
- real_path, trav->key,
+ real_path, key,
strerror (errno));
#endif /* DARWIN */
}
@@ -626,20 +709,22 @@ out:
int
posix_fhandle_pair (xlator_t *this, int fd,
- data_pair_t *trav, int flags)
+ char *key, data_t *value, int flags)
{
int sys_ret = -1;
int ret = 0;
- sys_ret = sys_fsetxattr (fd, trav->key, trav->value->data,
- trav->value->len, flags);
+ sys_ret = sys_fsetxattr (fd, key, value->data,
+ value->len, flags);
if (sys_ret < 0) {
if (errno == ENOTSUP) {
GF_LOG_OCCASIONALLY(gf_xattr_enotsup_log,
this->name,GF_LOG_WARNING,
"Extended attributes not "
- "supported");
+ "supported (try remounting "
+ "brick with 'user_xattr' "
+ "flag)");
} else if (errno == ENOENT) {
gf_log (this->name, GF_LOG_ERROR,
"fsetxattr on fd=%d failed: %s", fd,
@@ -651,13 +736,11 @@ posix_fhandle_pair (xlator_t *this, int fd,
((errno == EINVAL) ?
GF_LOG_DEBUG : GF_LOG_ERROR),
"fd=%d: key:%s error:%s",
- fd, trav->key,
- strerror (errno));
+ fd, key, strerror (errno));
#else /* ! DARWIN */
gf_log (this->name, GF_LOG_ERROR,
"fd=%d: key:%s error:%s",
- fd, trav->key,
- strerror (errno));
+ fd, key, strerror (errno));
#endif /* DARWIN */
}
@@ -674,6 +757,11 @@ static int
janitor_walker (const char *fpath, const struct stat *sb,
int typeflag, struct FTW *ftwbuf)
{
+ struct iatt stbuf = {0, };
+ xlator_t *this = NULL;
+
+ this = THIS;
+ posix_pstat (this, NULL, fpath, &stbuf);
switch (sb->st_mode & S_IFMT) {
case S_IFREG:
case S_IFBLK:
@@ -684,6 +772,8 @@ janitor_walker (const char *fpath, const struct stat *sb,
gf_log (THIS->name, GF_LOG_TRACE,
"unlinking %s", fpath);
unlink (fpath);
+ if (stbuf.ia_nlink == 1)
+ posix_handle_unset (this, stbuf.ia_gfid, NULL);
break;
case S_IFDIR:
@@ -692,6 +782,7 @@ janitor_walker (const char *fpath, const struct stat *sb,
"removing directory %s", fpath);
rmdir (fpath);
+ posix_handle_unset (this, stbuf.ia_gfid, NULL);
}
break;
}
@@ -753,7 +844,7 @@ posix_janitor_thread_proc (void *data)
time (&now);
if ((now - priv->last_landfill_check) > priv->janitor_sleep_duration) {
gf_log (this->name, GF_LOG_TRACE,
- "janitor cleaning out /" GF_REPLICATE_TRASH_DIR);
+ "janitor cleaning out %s", priv->trash_path);
nftw (priv->trash_path,
janitor_walker,
@@ -775,9 +866,6 @@ posix_janitor_thread_proc (void *data)
closedir (pfd->dir);
}
- if (pfd->path)
- GF_FREE (pfd->path);
-
GF_FREE (pfd);
}
}
@@ -797,8 +885,8 @@ posix_spawn_janitor_thread (xlator_t *this)
LOCK (&priv->lock);
{
if (!priv->janitor_present) {
- ret = pthread_create (&priv->janitor, NULL,
- posix_janitor_thread_proc, this);
+ ret = gf_thread_create (&priv->janitor, NULL,
+ posix_janitor_thread_proc, this);
if (ret < 0) {
gf_log (this->name, GF_LOG_ERROR,
@@ -814,6 +902,74 @@ unlock:
UNLOCK (&priv->lock);
}
+static int
+is_fresh_file (struct stat *stat)
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ if ((stat->st_ctime >= (tv.tv_sec - 1))
+ && (stat->st_ctime <= tv.tv_sec))
+ return 1;
+
+ return 0;
+}
+
+
+int
+posix_gfid_heal (xlator_t *this, const char *path, loc_t *loc, dict_t *xattr_req)
+{
+ /* The purpose of this function is to prevent a race
+ where an inode creation FOP (like mkdir/mknod/create etc)
+ races with lookup in the following way:
+
+ {create thread} | {lookup thread}
+ |
+ t0
+ mkdir ("name") |
+ t1
+ | posix_gfid_set ("name", 2);
+ t2
+ posix_gfid_set ("name", 1); |
+ t3
+ lstat ("name"); | lstat ("name");
+
+ In the above case mkdir FOP would have resulted with GFID 2 while
+ it should have been GFID 1. It matters in the case where GFID would
+ have gotten set to 1 on other subvolumes of replciate/distribute
+
+ The "solution" here is that, if we detect lookup is attempting to
+ set a GFID on a file which is created very recently, but does not
+ yet have a GFID (i.e, between t1 and t2), then "fake" it as though
+ posix_gfid_heal was called at t0 instead.
+ */
+
+ uuid_t uuid_curr;
+ int ret = 0;
+ struct stat stat = {0, };
+
+ if (!xattr_req)
+ goto out;
+
+ if (sys_lstat (path, &stat) != 0)
+ goto out;
+
+ ret = sys_lgetxattr (path, GFID_XATTR_KEY, uuid_curr, 16);
+ if (ret != 16) {
+ if (is_fresh_file (&stat)) {
+ ret = -1;
+ errno = ENOENT;
+ goto out;
+ }
+ }
+
+ ret = posix_gfid_set (this, path, loc, xattr_req);
+out:
+ return ret;
+}
+
+
int
posix_acl_xattr_set (xlator_t *this, const char *path, dict_t *xattr_req)
{
@@ -827,17 +983,17 @@ posix_acl_xattr_set (xlator_t *this, const char *path, dict_t *xattr_req)
if (sys_lstat (path, &stat) != 0)
goto out;
- data = dict_get (xattr_req, "system.posix_acl_access");
+ data = dict_get (xattr_req, POSIX_ACL_ACCESS_XATTR);
if (data) {
- ret = sys_lsetxattr (path, "system.posix_acl_access",
+ ret = sys_lsetxattr (path, POSIX_ACL_ACCESS_XATTR,
data->data, data->len, 0);
if (ret != 0)
goto out;
}
- data = dict_get (xattr_req, "system.posix_acl_default");
+ data = dict_get (xattr_req, POSIX_ACL_DEFAULT_XATTR);
if (data) {
- ret = sys_lsetxattr (path, "system.posix_acl_default",
+ ret = sys_lsetxattr (path, POSIX_ACL_DEFAULT_XATTR,
data->data, data->len, 0);
if (ret != 0)
goto out;
@@ -847,38 +1003,389 @@ out:
return ret;
}
+static int
+_handle_entry_create_keyvalue_pair (dict_t *d, char *k, data_t *v,
+ void *tmp)
+{
+ int ret = -1;
+ posix_xattr_filler_t *filler = NULL;
+
+ filler = tmp;
+
+ if (!strcmp (GFID_XATTR_KEY, k) ||
+ !strcmp ("gfid-req", k) ||
+ !strcmp (POSIX_ACL_DEFAULT_XATTR, k) ||
+ !strcmp (POSIX_ACL_ACCESS_XATTR, k) ||
+ ZR_FILE_CONTENT_REQUEST(k)) {
+ return 0;
+ }
+
+ ret = posix_handle_pair (filler->this, filler->real_path, k, v,
+ XATTR_CREATE);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return 0;
+}
+
int
posix_entry_create_xattr_set (xlator_t *this, const char *path,
dict_t *dict)
{
- data_pair_t *trav = NULL;
int ret = -1;
+ posix_xattr_filler_t filler = {0,};
+
if (!dict)
goto out;
- trav = dict->members_list;
- while (trav) {
- if (!strcmp (GFID_XATTR_KEY, trav->key) ||
- !strcmp ("gfid-req", trav->key) ||
- !strcmp ("system.posix_acl_default", trav->key) ||
- !strcmp ("system.posix_acl_access", trav->key) ||
- ZR_FILE_CONTENT_REQUEST(trav->key)) {
- trav = trav->next;
- continue;
+ filler.this = this;
+ filler.real_path = path;
+
+ ret = dict_foreach (dict, _handle_entry_create_keyvalue_pair, &filler);
+
+out:
+ return ret;
+}
+
+
+static int
+__posix_fd_ctx_get (fd_t *fd, xlator_t *this, struct posix_fd **pfd_p)
+{
+ uint64_t tmp_pfd = 0;
+ struct posix_fd *pfd = NULL;
+ int ret = -1;
+ char *real_path = NULL;
+ int _fd = -1;
+ DIR *dir = NULL;
+
+ ret = __fd_ctx_get (fd, this, &tmp_pfd);
+ if (ret == 0) {
+ pfd = (void *)(long) tmp_pfd;
+ ret = 0;
+ goto out;
+ }
+
+ if (!fd_is_anonymous(fd))
+ /* anonymous fd */
+ goto out;
+
+ MAKE_HANDLE_PATH (real_path, this, fd->inode->gfid, NULL);
+
+ pfd = GF_CALLOC (1, sizeof (*pfd), gf_posix_mt_posix_fd);
+ if (!pfd) {
+ goto out;
+ }
+ pfd->fd = -1;
+
+ if (fd->inode->ia_type == IA_IFDIR) {
+ dir = opendir (real_path);
+ if (!dir) {
+ GF_FREE (pfd);
+ pfd = NULL;
+ goto out;
}
+ _fd = dirfd (dir);
+ }
- ret = posix_handle_pair (this, path, trav, XATTR_CREATE);
- if (ret < 0) {
- errno = -ret;
- ret = -1;
+ if (fd->inode->ia_type == IA_IFREG) {
+ _fd = open (real_path, O_RDWR|O_LARGEFILE);
+ if (_fd == -1) {
+ GF_FREE (pfd);
+ pfd = NULL;
goto out;
}
- trav = trav->next;
}
- ret = 0;
+ pfd->fd = _fd;
+ pfd->dir = dir;
+
+ ret = __fd_ctx_set (fd, this, (uint64_t) (long) pfd);
+ if (ret != 0) {
+ if (_fd != -1)
+ close (_fd);
+ if (dir)
+ closedir (dir);
+ GF_FREE (pfd);
+ pfd = NULL;
+ goto out;
+ }
+ ret = 0;
out:
+ if (pfd_p)
+ *pfd_p = pfd;
+ return ret;
+}
+
+
+int
+posix_fd_ctx_get (fd_t *fd, xlator_t *this, struct posix_fd **pfd)
+{
+ int ret;
+
+ LOCK (&fd->inode->lock);
+ {
+ ret = __posix_fd_ctx_get (fd, this, pfd);
+ }
+ UNLOCK (&fd->inode->lock);
+
return ret;
}
+
+static void *
+posix_health_check_thread_proc (void *data)
+{
+ xlator_t *this = NULL;
+ struct posix_private *priv = NULL;
+ uint32_t interval = 0;
+ int ret = -1;
+ struct stat sb = {0, };
+
+ this = data;
+ priv = this->private;
+
+ /* prevent races when the interval is updated */
+ interval = priv->health_check_interval;
+ if (interval == 0)
+ goto out;
+
+ gf_log (this->name, GF_LOG_DEBUG, "health-check thread started, "
+ "interval = %d seconds", interval);
+
+ while (1) {
+ /* aborting sleep() is a request to exit this thread, sleep()
+ * will normally not return when cancelled */
+ ret = sleep (interval);
+ if (ret > 0)
+ break;
+
+ /* prevent thread errors while doing the health-check(s) */
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+
+ /* Do the health-check, it should be moved to its own function
+ * in case it gets more complex. */
+ ret = stat (priv->base_path, &sb);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "stat() on %s returned: %s", priv->base_path,
+ strerror (errno));
+ goto abort;
+ }
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ }
+
+out:
+ gf_log (this->name, GF_LOG_DEBUG, "health-check thread exiting");
+
+ LOCK (&priv->lock);
+ {
+ priv->health_check_active = _gf_false;
+ }
+ UNLOCK (&priv->lock);
+
+ return NULL;
+
+abort:
+ /* health-check failed */
+ gf_log (this->name, GF_LOG_EMERG, "health-check failed, going down");
+ xlator_notify (this->parents->xlator, GF_EVENT_CHILD_DOWN, this);
+
+ ret = sleep (30);
+ if (ret == 0) {
+ gf_log (this->name, GF_LOG_EMERG, "still alive! -> SIGTERM");
+ kill (getpid(), SIGTERM);
+ }
+
+ ret = sleep (30);
+ if (ret == 0) {
+ gf_log (this->name, GF_LOG_EMERG, "still alive! -> SIGKILL");
+ kill (getpid(), SIGKILL);
+ }
+
+ return NULL;
+}
+
+void
+posix_spawn_health_check_thread (xlator_t *xl)
+{
+ struct posix_private *priv = NULL;
+ int ret = -1;
+
+ priv = xl->private;
+
+ LOCK (&priv->lock);
+ {
+ /* cancel the running thread */
+ if (priv->health_check_active == _gf_true) {
+ pthread_cancel (priv->health_check);
+ priv->health_check_active = _gf_false;
+ }
+
+ /* prevent scheduling a check in a tight loop */
+ if (priv->health_check_interval == 0)
+ goto unlock;
+
+ ret = gf_thread_create (&priv->health_check, NULL,
+ posix_health_check_thread_proc, xl);
+ if (ret < 0) {
+ priv->health_check_interval = 0;
+ priv->health_check_active = _gf_false;
+ gf_log (xl->name, GF_LOG_ERROR,
+ "unable to setup health-check thread: %s",
+ strerror (errno));
+ goto unlock;
+ }
+
+ /* run the thread detached, resources will be freed on exit */
+ pthread_detach (priv->health_check);
+ priv->health_check_active = _gf_true;
+ }
+unlock:
+ UNLOCK (&priv->lock);
+}
+
+int
+posix_fsyncer_pick (xlator_t *this, struct list_head *head)
+{
+ struct posix_private *priv = NULL;
+ int count = 0;
+
+ priv = this->private;
+ pthread_mutex_lock (&priv->fsync_mutex);
+ {
+ while (list_empty (&priv->fsyncs))
+ pthread_cond_wait (&priv->fsync_cond,
+ &priv->fsync_mutex);
+
+ count = priv->fsync_queue_count;
+ priv->fsync_queue_count = 0;
+ list_splice_init (&priv->fsyncs, head);
+ }
+ pthread_mutex_unlock (&priv->fsync_mutex);
+
+ return count;
+}
+
+
+void
+posix_fsyncer_process (xlator_t *this, call_stub_t *stub, gf_boolean_t do_fsync)
+{
+ struct posix_fd *pfd = NULL;
+ int ret = -1;
+ struct posix_private *priv = NULL;
+
+ priv = this->private;
+
+ ret = posix_fd_ctx_get (stub->args.fd, this, &pfd);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not get fdctx for fd(%s)",
+ uuid_utoa (stub->args.fd->inode->gfid));
+ call_unwind_error (stub, -1, EINVAL);
+ return;
+ }
+
+ if (do_fsync) {
+#ifdef HAVE_FDATASYNC
+ if (stub->args.datasync)
+ ret = fdatasync (pfd->fd);
+ else
+#endif
+ ret = fsync (pfd->fd);
+ } else {
+ ret = 0;
+ }
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "could not fstat fd(%s)",
+ uuid_utoa (stub->args.fd->inode->gfid));
+ call_unwind_error (stub, -1, errno);
+ return;
+ }
+
+ call_unwind_error (stub, 0, 0);
+}
+
+
+static void
+posix_fsyncer_syncfs (xlator_t *this, struct list_head *head)
+{
+ call_stub_t *stub = NULL;
+ struct posix_fd *pfd = NULL;
+ int ret = -1;
+
+ stub = list_entry (head->prev, call_stub_t, list);
+ ret = posix_fd_ctx_get (stub->args.fd, this, &pfd);
+ if (ret)
+ return;
+
+#ifdef GF_LINUX_HOST_OS
+ /* syncfs() is not "declared" in RHEL's glibc even though
+ the kernel has support.
+ */
+#include <sys/syscall.h>
+#include <unistd.h>
+#ifdef SYS_syncfs
+ syscall (SYS_syncfs, pfd->fd);
+#else
+ sync();
+#endif
+#else
+ sync();
+#endif
+}
+
+
+void *
+posix_fsyncer (void *d)
+{
+ xlator_t *this = d;
+ struct posix_private *priv = NULL;
+ call_stub_t *stub = NULL;
+ call_stub_t *tmp = NULL;
+ struct list_head list;
+ int count = 0;
+ gf_boolean_t do_fsync = _gf_true;
+
+ priv = this->private;
+
+ for (;;) {
+ INIT_LIST_HEAD (&list);
+
+ count = posix_fsyncer_pick (this, &list);
+
+ usleep (priv->batch_fsync_delay_usec);
+
+ gf_log (this->name, GF_LOG_DEBUG,
+ "picked %d fsyncs", count);
+
+ switch (priv->batch_fsync_mode) {
+ case BATCH_NONE:
+ case BATCH_REVERSE_FSYNC:
+ break;
+ case BATCH_SYNCFS:
+ case BATCH_SYNCFS_SINGLE_FSYNC:
+ case BATCH_SYNCFS_REVERSE_FSYNC:
+ posix_fsyncer_syncfs (this, &list);
+ break;
+ }
+
+ if (priv->batch_fsync_mode == BATCH_SYNCFS)
+ do_fsync = _gf_false;
+ else
+ do_fsync = _gf_true;
+
+ list_for_each_entry_safe_reverse (stub, tmp, &list, list) {
+ list_del_init (&stub->list);
+
+ posix_fsyncer_process (this, stub, do_fsync);
+
+ if (priv->batch_fsync_mode == BATCH_SYNCFS_SINGLE_FSYNC)
+ do_fsync = _gf_false;
+ }
+ }
+}