summaryrefslogtreecommitdiffstats
path: root/xlators/storage/posix/src/posix-entry-ops.c
diff options
context:
space:
mode:
authorShyamsundarR <srangana@redhat.com>2017-11-28 18:51:00 -0500
committerShyamsundarR <srangana@redhat.com>2017-12-02 13:56:19 -0500
commit8a0b115b20cfa2dd3c5a9e22a8244c9c2f03e17b (patch)
treee0dc5088e9931d4d2cff442e8a780da0ff7caa15 /xlators/storage/posix/src/posix-entry-ops.c
parent09cb795587772b60ba102f4369ab3f4501cdc01a (diff)
posix: Reorganize posix xlator to prepare for reuse with rio
1. Split out entry and inode/fd based FOPs into separate files from posix.c 2. Split out common routines (init, fini, reconf, and such) into its own file, from posix.c 3. Retain just the method assignments in posix.c (such that posix2 for RIO can assign its own methods in the future for entry operations and such) 4. Based on the split in (1) and (2) split out posix-handle.h into 2 files, such that macros that are needed for inode ops are in one and rest are in the other If the split is done as above, posix2 can compile with its own entry ops, and hence not compile, the entry ops as split in (1) above. The split described in (4) can again help posix2 to define its own macros to make entry and inode handles, thus not impact existing POSIX xlator code. Noted problems - There are path references in certain cases where quota is used (in the xattr FOPs), and thus will fail on reuse in posix2, this needs to be handled when we get there. - posix_init does set root GFID on the brick root, and this is incorrect for posix2, again will need handling later when posix2 evolves based on this code (other init checks seem fine on current inspection) Merge of experimental branch patches with the following gerrit change-IDs > Change-Id: I965ce6dffe70a62c697f790f3438559520e0af20 > Change-Id: I089a4d9cf470c2f9c121611e8ef18dea92b2be70 > Change-Id: I2cec103f6ba8f3084443f3066bcc70b2f5ecb49a Fixes gluster/glusterfs#327 Change-Id: I0ccfa78559a7c5a68f5e861e144cf856f5c9e19c Signed-off-by: ShyamsundarR <srangana@redhat.com>
Diffstat (limited to 'xlators/storage/posix/src/posix-entry-ops.c')
-rw-r--r--xlators/storage/posix/src/posix-entry-ops.c2125
1 files changed, 2125 insertions, 0 deletions
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
new file mode 100644
index 00000000000..7a83eb3dfba
--- /dev/null
+++ b/xlators/storage/posix/src/posix-entry-ops.c
@@ -0,0 +1,2125 @@
+/*
+ Copyright (c) 2006-2017 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.
+*/
+#define __XOPEN_SOURCE 500
+
+/* for SEEK_HOLE and SEEK_DATA */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <openssl/md5.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <ftw.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <ftw.h>
+
+#ifndef GF_BSD_HOST_OS
+#include <alloca.h>
+#endif /* GF_BSD_HOST_OS */
+
+#ifdef HAVE_LINKAT
+#include <fcntl.h>
+#endif /* HAVE_LINKAT */
+
+#include "glusterfs.h"
+#include "checksum.h"
+#include "dict.h"
+#include "logging.h"
+#include "posix.h"
+#include "posix-handle.h"
+#include "xlator.h"
+#include "defaults.h"
+#include "common-utils.h"
+#include "compat-errno.h"
+#include "compat.h"
+#include "byte-order.h"
+#include "syscall.h"
+#include "statedump.h"
+#include "locking.h"
+#include "timer.h"
+#include "glusterfs3-xdr.h"
+#include "hashfn.h"
+#include "posix-aio.h"
+#include "glusterfs-acl.h"
+#include "posix-messages.h"
+#include "events.h"
+#include "posix-gfid-path.h"
+#include "compat-uuid.h"
+
+extern char *marker_xattrs[];
+#define ALIGN_SIZE 4096
+
+#undef HAVE_SET_FSID
+#ifdef HAVE_SET_FSID
+
+#define DECLARE_OLD_FS_ID_VAR uid_t old_fsuid; gid_t old_fsgid;
+
+#define SET_FS_ID(uid, gid) do { \
+ old_fsuid = setfsuid (uid); \
+ old_fsgid = setfsgid (gid); \
+ } while (0)
+
+#define SET_TO_OLD_FS_ID() do { \
+ setfsuid (old_fsuid); \
+ setfsgid (old_fsgid); \
+ } while (0)
+
+#else
+
+#define DECLARE_OLD_FS_ID_VAR
+#define SET_FS_ID(uid, gid)
+#define SET_TO_OLD_FS_ID()
+
+#endif
+
+/* Setting microseconds or nanoseconds depending on what's supported:
+ The passed in `tv` can be
+ struct timespec
+ if supported (better, because it supports nanosecond resolution) or
+ struct timeval
+ otherwise. */
+#if HAVE_UTIMENSAT
+#define SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv, nanosecs) \
+ tv.tv_nsec = nanosecs
+#define PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv) \
+ (sys_utimensat (AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW))
+#else
+#define SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv, nanosecs) \
+ tv.tv_usec = nanosecs / 1000
+#define PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv) \
+ (lutimes (path, tv))
+#endif
+
+gf_boolean_t
+posix_symlinks_match (xlator_t *this, loc_t *loc, uuid_t gfid)
+{
+ struct posix_private *priv = NULL;
+ char linkname_actual[PATH_MAX] = {0,};
+ char linkname_expected[PATH_MAX] = {0};
+ char *dir_handle = NULL;
+ ssize_t len = 0;
+ size_t handle_size = 0;
+ gf_boolean_t ret = _gf_false;
+
+ priv = this->private;
+ handle_size = POSIX_GFID_HANDLE_SIZE(priv->base_path_length);
+ dir_handle = alloca0 (handle_size);
+
+ snprintf (linkname_expected, handle_size, "../../%02x/%02x/%s/%s",
+ loc->pargfid[0], loc->pargfid[1], uuid_utoa (loc->pargfid),
+ loc->name);
+
+ MAKE_HANDLE_GFID_PATH (dir_handle, this, gfid, NULL);
+ len = sys_readlink (dir_handle, linkname_actual, PATH_MAX);
+ if (len < 0)
+ goto out;
+ linkname_actual[len] = '\0';
+
+ if (!strncmp (linkname_actual, linkname_expected, handle_size))
+ ret = _gf_true;
+
+out:
+ return ret;
+}
+
+dict_t*
+posix_dict_set_nlink (dict_t *req, dict_t *res, int32_t nlink)
+{
+ int ret = -1;
+
+ if (req == NULL || !dict_get (req, GF_REQUEST_LINK_COUNT_XDATA))
+ goto out;
+
+ if (res == NULL)
+ res = dict_new ();
+ if (res == NULL)
+ goto out;
+
+ ret = dict_set_uint32 (res, GF_RESPONSE_LINK_COUNT_XDATA, nlink);
+ if (ret == -1)
+ gf_msg ("posix", GF_LOG_WARNING, 0, P_MSG_SET_XDATA_FAIL,
+ "Failed to set GF_RESPONSE_LINK_COUNT_XDATA");
+out:
+ return res;
+}
+
+/* Regular fops */
+
+int32_t
+posix_lookup (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, dict_t *xdata)
+{
+ struct iatt buf = {0, };
+ int32_t op_ret = -1;
+ int32_t entry_ret = 0;
+ int32_t op_errno = 0;
+ dict_t * xattr = NULL;
+ char * real_path = NULL;
+ char * par_path = NULL;
+ struct iatt postparent = {0,};
+ int32_t gfidless = 0;
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
+ struct posix_private *priv = NULL;
+ posix_inode_ctx_t *ctx = NULL;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ priv = this->private;
+
+ /* The Hidden directory should be for housekeeping purpose and it
+ should not get any gfid on it */
+ if (__is_root_gfid (loc->pargfid) && loc->name
+ && (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {
+ gf_msg (this->name, GF_LOG_WARNING, EPERM,
+ P_MSG_LOOKUP_NOT_PERMITTED, "Lookup issued on %s,"
+ " which is not permitted", GF_HIDDEN_PATH);
+ op_errno = EPERM;
+ op_ret = -1;
+ goto out;
+ }
+
+ op_ret = dict_get_int32 (xdata, GF_GFIDLESS_LOOKUP, &gfidless);
+ op_ret = -1;
+ if (gf_uuid_is_null (loc->pargfid) || (loc->name == NULL)) {
+ /* nameless lookup */
+ MAKE_INODE_HANDLE (real_path, this, loc, &buf);
+ } else {
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, &buf);
+
+ if (gf_uuid_is_null (loc->inode->gfid)) {
+ op_ret = posix_gfid_heal (this, real_path, loc, xdata);
+ if (op_ret < 0) {
+ op_errno = -op_ret;
+ op_ret = -1;
+ goto out;
+ }
+ MAKE_ENTRY_HANDLE (real_path, par_path, this,
+ loc, &buf);
+ }
+ }
+
+ op_errno = errno;
+
+ if (op_ret == -1) {
+ if (op_errno != ENOENT) {
+ gf_msg (this->name, GF_LOG_WARNING, op_errno,
+ P_MSG_LSTAT_FAILED,
+ "lstat on %s failed",
+ real_path ? real_path : "null");
+ }
+
+ entry_ret = -1;
+ goto parent;
+ }
+
+ if (xdata && (op_ret == 0)) {
+ xattr = posix_xattr_fill (this, real_path, loc, NULL, -1, xdata,
+ &buf);
+ }
+
+ if (priv->update_pgfid_nlinks) {
+ if (!gf_uuid_is_null (loc->pargfid) && !IA_ISDIR (buf.ia_type)) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key,
+ PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+
+ op_ret = posix_inode_ctx_get_all (loc->inode, this,
+ &ctx);
+ if (op_ret < 0) {
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ pthread_mutex_lock (&ctx->pgfid_lock);
+ {
+ SET_PGFID_XATTR_IF_ABSENT (real_path,
+ pgfid_xattr_key,
+ nlink_samepgfid,
+ XATTR_CREATE, op_ret,
+ this, unlock);
+ }
+unlock:
+ pthread_mutex_unlock (&ctx->pgfid_lock);
+ }
+ }
+
+parent:
+ if (par_path) {
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_LSTAT_FAILED, "post-operation lstat on"
+ " parent %s failed", par_path);
+ if (op_errno == ENOENT)
+ /* If parent directory is missing in a lookup,
+ errno should be ESTALE (bad handle) and not
+ ENOENT (missing entry)
+ */
+ op_errno = ESTALE;
+ goto out;
+ }
+ }
+
+ op_ret = entry_ret;
+out:
+ if (!op_ret && !gfidless && gf_uuid_is_null (buf.ia_gfid)) {
+ gf_msg (this->name, GF_LOG_ERROR, ENODATA, P_MSG_NULL_GFID,
+ "buf->ia_gfid is null for "
+ "%s", (real_path) ? real_path: "");
+ op_ret = -1;
+ op_errno = ENODATA;
+ }
+
+ if (op_ret == 0)
+ op_errno = 0;
+ STACK_UNWIND_STRICT (lookup, frame, op_ret, op_errno,
+ (loc)?loc->inode:NULL, &buf, xattr, &postparent);
+
+ if (xattr)
+ dict_unref (xattr);
+
+ return 0;
+}
+
+int
+posix_mknod (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, mode_t mode, dev_t dev, mode_t umask, dict_t *xdata)
+{
+ int tmp_fd = 0;
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_path = 0;
+ char *par_path = 0;
+ struct iatt stbuf = { 0, };
+ struct posix_private *priv = NULL;
+ gid_t gid = 0;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ void * uuid_req = NULL;
+ int32_t nlink_samepgfid = 0;
+ char *pgfid_xattr_key = NULL;
+ gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false;
+ gf_boolean_t linked = _gf_false;
+ gf_loglevel_t level = GF_LOG_NONE;
+ mode_t mode_bit = 0;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ GFID_NULL_CHECK_AND_GOTO (frame, this, loc, xdata, op_ret, op_errno,
+ out);
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, NULL);
+
+ mode_bit = (priv->create_mask & mode) | priv->force_create_mode;
+ mode = posix_override_umask (mode, mode_bit);
+
+ gid = frame->root->gid;
+
+ SET_FS_ID (frame->root->uid, gid);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent of %s failed",
+ real_path);
+ goto out;
+ }
+
+ if (preparent.ia_prot.sgid) {
+ gid = preparent.ia_gid;
+ }
+
+ /* Check if the 'gfid' already exists, because this mknod may be an
+ internal call from distribute for creating 'linkfile', and that
+ linkfile may be for a hardlinked file */
+ if (dict_get (xdata, GLUSTERFS_INTERNAL_FOP_KEY)) {
+ dict_del (xdata, GLUSTERFS_INTERNAL_FOP_KEY);
+ op_ret = dict_get_ptr (xdata, "gfid-req", &uuid_req);
+ if (op_ret) {
+ gf_msg_debug (this->name, 0, "failed to get the gfid from "
+ "dict for %s", loc->path);
+ goto real_op;
+ }
+ op_ret = posix_create_link_if_gfid_exists (this, uuid_req,
+ real_path,
+ loc->inode->table);
+ if (!op_ret) {
+ linked = _gf_true;
+ goto post_op;
+ }
+ }
+
+real_op:
+#ifdef __NetBSD__
+ if (S_ISFIFO(mode))
+ op_ret = mkfifo (real_path, mode);
+ else
+#endif /* __NetBSD__ */
+ op_ret = sys_mknod (real_path, mode, dev);
+
+ if (op_ret == -1) {
+ op_errno = errno;
+ if ((op_errno == EINVAL) && S_ISREG (mode)) {
+ /* Over Darwin, mknod with (S_IFREG|mode)
+ doesn't work */
+ tmp_fd = sys_creat (real_path, mode);
+ if (tmp_fd == -1) {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_CREATE_FAILED, "create failed on"
+ "%s", real_path);
+ goto out;
+ }
+ sys_close (tmp_fd);
+ } else {
+ if (op_errno == EEXIST)
+ level = GF_LOG_DEBUG;
+ else
+ level = GF_LOG_ERROR;
+ gf_msg (this->name, level, errno, P_MSG_MKNOD_FAILED,
+ "mknod on %s failed", real_path);
+ goto out;
+ }
+ }
+
+ entry_created = _gf_true;
+
+#ifndef HAVE_SET_FSID
+ op_ret = sys_lchown (real_path, frame->root->uid, gid);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LCHOWN_FAILED,
+ "lchown on %s failed", real_path);
+ goto out;
+ }
+#endif
+
+post_op:
+ op_ret = posix_acl_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0, P_MSG_ACL_FAILED,
+ "setting ACLs on %s failed", real_path);
+ }
+
+ if (priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+ nlink_samepgfid = 1;
+
+ SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid,
+ XATTR_CREATE, op_ret, this, ignore);
+ }
+
+ if (priv->gfid2path) {
+ posix_set_gfid2path_xattr (this, real_path, loc->pargfid,
+ loc->name);
+ }
+
+ignore:
+ op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ if (errno != EEXIST)
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_XATTR_FAILED,
+ "setting xattrs on %s failed", real_path);
+ else
+ gf_msg_debug (this->name, 0,
+ "setting xattrs on %s failed", real_path);
+ }
+
+ if (!linked) {
+ op_ret = posix_gfid_set (this, real_path, loc, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0, P_MSG_GFID_FAILED,
+ "setting gfid on %s failed", real_path);
+ } else {
+ gfid_set = _gf_true;
+ }
+ }
+
+ op_ret = posix_pstat (this, NULL, real_path, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_MKNOD_FAILED,
+ "mknod on %s failed", real_path);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ op_ret = 0;
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (mknod, frame, op_ret, op_errno,
+ (loc)?loc->inode:NULL, &stbuf, &preparent,
+ &postparent, NULL);
+
+ if (op_ret < 0) {
+ if (entry_created) {
+ if (S_ISREG (mode))
+ sys_unlink (real_path);
+ else
+ sys_rmdir (real_path);
+ }
+
+ if (gfid_set)
+ posix_gfid_unset (this, xdata);
+ }
+
+ return 0;
+}
+
+int
+posix_mkdir (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, mode_t mode, mode_t umask, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_path = NULL, *gfid_path = NULL;
+ char *par_path = NULL, *xattr_name = NULL;
+ struct iatt stbuf = {0, };
+ struct posix_private *priv = NULL;
+ gid_t gid = 0;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false;
+ void *uuid_req = NULL;
+ ssize_t size = 0;
+ dict_t *xdata_rsp = NULL;
+ void *disk_xattr = NULL;
+ data_t *arg_data = NULL;
+ char pgfid[GF_UUID_BUF_SIZE] = {0};
+ char value_buf[4096] = {0,};
+ gf_boolean_t have_val = _gf_false;
+ mode_t mode_bit = 0;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ /* The Hidden directory should be for housekeeping purpose and it
+ should not get created from a user request */
+ if (__is_root_gfid (loc->pargfid) &&
+ (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {
+ gf_msg (this->name, GF_LOG_WARNING, EPERM,
+ P_MSG_MKDIR_NOT_PERMITTED, "mkdir issued on %s, which"
+ "is not permitted", GF_HIDDEN_PATH);
+ op_errno = EPERM;
+ op_ret = -1;
+ goto out;
+ }
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ GFID_NULL_CHECK_AND_GOTO (frame, this, loc, xdata, op_ret, op_errno,
+ out);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, NULL);
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ if (loc->parent)
+ gf_uuid_unparse (loc->parent->gfid, pgfid);
+ else
+ gf_uuid_unparse (loc->pargfid, pgfid);
+
+ gid = frame->root->gid;
+
+ op_ret = posix_pstat (this, NULL, real_path, &stbuf);
+
+ SET_FS_ID (frame->root->uid, gid);
+
+ mode_bit = (priv->create_directory_mask & mode)
+ | priv->force_directory_mode;
+ mode = posix_override_umask (mode, mode_bit);
+
+ if (xdata) {
+ op_ret = dict_get_ptr (xdata, "gfid-req", &uuid_req);
+ if (!op_ret && !gf_uuid_compare (stbuf.ia_gfid, uuid_req)) {
+ op_ret = -1;
+ op_errno = EEXIST;
+ goto out;
+ }
+ }
+
+ if (uuid_req && !gf_uuid_is_null (uuid_req)) {
+ op_ret = posix_istat (this, uuid_req, NULL, &stbuf);
+ if ((op_ret == 0) && IA_ISDIR (stbuf.ia_type)) {
+ size = posix_handle_path (this, uuid_req, NULL, NULL,
+ 0);
+ if (size > 0)
+ gfid_path = alloca (size);
+
+ if (gfid_path)
+ posix_handle_path (this, uuid_req, NULL,
+ gfid_path, size);
+
+ if (frame->root->pid != GF_CLIENT_PID_SELF_HEALD) {
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ P_MSG_DIR_OF_SAME_ID, "mkdir (%s): "
+ "gfid (%s) is already associated with "
+ "directory (%s). Hence, both "
+ "directories will share same gfid and "
+ "this can lead to inconsistencies.",
+ loc->path, uuid_utoa (uuid_req),
+ gfid_path ? gfid_path : "<NULL>");
+
+ gf_event (EVENT_POSIX_SAME_GFID, "gfid=%s;"
+ "path=%s;newpath=%s;brick=%s:%s",
+ uuid_utoa (uuid_req),
+ gfid_path ? gfid_path : "<NULL>",
+ loc->path, priv->hostname,
+ priv->base_path);
+ }
+ if (!posix_symlinks_match (this, loc, uuid_req))
+ /* For afr selfheal of dir renames, we need to
+ * remove the old symlink in order for
+ * posix_gfid_set to set the symlink to the
+ * new dir.*/
+ posix_handle_unset (this, stbuf.ia_gfid, NULL);
+ }
+ } else if (!uuid_req && frame->root->pid != GF_SERVER_PID_TRASH) {
+ op_ret = -1;
+ op_errno = EPERM;
+ gf_msg_callingfn (this->name, GF_LOG_WARNING, op_errno,
+ P_MSG_NULL_GFID, "mkdir (%s): is issued without "
+ "gfid-req %p", loc->path, xdata);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ if (preparent.ia_prot.sgid) {
+ gid = preparent.ia_gid;
+ mode |= S_ISGID;
+ }
+
+ op_ret = dict_get_str (xdata, GF_PREOP_PARENT_KEY, &xattr_name);
+ if (xattr_name != NULL) {
+ arg_data = dict_get (xdata, xattr_name);
+ if (arg_data) {
+ size = sys_lgetxattr (par_path, xattr_name, value_buf,
+ sizeof(value_buf) - 1);
+ if (size >= 0) {
+ have_val = _gf_true;
+ } else {
+ if (errno == ERANGE) {
+ gf_msg (this->name, GF_LOG_INFO, errno,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): getxattr on key "
+ "(%s) path (%s) failed due to "
+ " buffer overflow", pgfid,
+ loc->name, xattr_name,
+ par_path);
+ size = sys_lgetxattr (par_path,
+ xattr_name, NULL,
+ 0);
+ }
+ if (size < 0) {
+ op_ret = -1;
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): getxattr on key (%s)"
+ " path (%s) failed ", pgfid,
+ loc->name, xattr_name,
+ par_path);
+ goto out;
+ }
+ }
+ disk_xattr = alloca (size);
+ if (disk_xattr == NULL) {
+ op_ret = -1;
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): alloca failed during"
+ " preop of mkdir (%s)", pgfid,
+ loc->name, real_path);
+ goto out;
+ }
+ if (have_val) {
+ memcpy (disk_xattr, value_buf, size);
+ } else {
+ size = sys_lgetxattr (par_path, xattr_name,
+ disk_xattr, size);
+ if (size < 0) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): getxattr on "
+ " key (%s) path (%s) failed "
+ "(%s)", pgfid, loc->name,
+ xattr_name, par_path,
+ strerror (errno));
+ goto out;
+ }
+ }
+ if ((arg_data->len != size)
+ || (memcmp (arg_data->data, disk_xattr, size))) {
+ gf_msg (this->name, GF_LOG_INFO, EIO,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): failing preop of "
+ "mkdir (%s) as on-disk"
+ " xattr value differs from argument "
+ "value for key %s", pgfid, loc->name,
+ real_path, xattr_name);
+ op_ret = -1;
+ op_errno = EIO;
+
+ xdata_rsp = dict_new ();
+ if (xdata_rsp == NULL) {
+ gf_msg (this->name, GF_LOG_ERROR,
+ ENOMEM,
+ P_MSG_PREOP_CHECK_FAILED,
+ "mkdir (%s/%s): "
+ "dict allocation failed", pgfid,
+ loc->name);
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ op_errno = dict_set_int8 (xdata_rsp,
+ GF_PREOP_CHECK_FAILED, 1);
+ goto out;
+ }
+
+ dict_del (xdata, xattr_name);
+ }
+
+ dict_del (xdata, GF_PREOP_PARENT_KEY);
+ }
+
+ op_ret = sys_mkdir (real_path, mode);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_MKDIR_FAILED,
+ "mkdir of %s failed", real_path);
+ goto out;
+ }
+
+ entry_created = _gf_true;
+
+#ifndef HAVE_SET_FSID
+ op_ret = sys_chown (real_path, frame->root->uid, gid);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_CHOWN_FAILED,
+ "chown on %s failed", real_path);
+ goto out;
+ }
+#endif
+ op_ret = posix_acl_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_ACL_FAILED,
+ "setting ACLs on %s failed ", real_path);
+ }
+
+ op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
+ "setting xattrs on %s failed", real_path);
+ }
+
+ op_ret = posix_gfid_set (this, real_path, loc, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0, P_MSG_GFID_FAILED,
+ "setting gfid on %s failed", real_path);
+ } else {
+ gfid_set = _gf_true;
+ }
+
+ op_ret = posix_pstat (this, NULL, real_path, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat on %s failed", real_path);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent of %s failed",
+ real_path);
+ goto out;
+ }
+
+ op_ret = 0;
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno,
+ (loc)?loc->inode:NULL, &stbuf, &preparent,
+ &postparent, xdata_rsp);
+
+ if (op_ret < 0) {
+ if (entry_created)
+ sys_rmdir (real_path);
+
+ if (gfid_set)
+ posix_gfid_unset (this, xdata);
+ }
+
+ if (xdata_rsp)
+ dict_unref (xdata_rsp);
+
+ return 0;
+}
+
+int
+posix_add_unlink_to_ctx (inode_t *inode, xlator_t *this, char *unlink_path)
+{
+ uint64_t ctx = GF_UNLINK_FALSE;
+ int ret = 0;
+
+ if (!unlink_path) {
+ gf_msg (this->name, GF_LOG_ERROR, ENOMEM,
+ P_MSG_UNLINK_FAILED,
+ "Creation of unlink entry failed for gfid: %s",
+ unlink_path);
+ ret = -1;
+ goto out;
+ }
+
+ ctx = GF_UNLINK_TRUE;
+ ret = posix_inode_ctx_set_unlink_flag (inode, this, ctx);
+ if (ret < 0) {
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+posix_move_gfid_to_unlink (xlator_t *this, uuid_t gfid, loc_t *loc)
+{
+ char *unlink_path = NULL;
+ char *gfid_path = NULL;
+ int ret = 0;
+ struct posix_private *priv_posix = NULL;
+
+ priv_posix = (struct posix_private *) this->private;
+
+ MAKE_HANDLE_GFID_PATH (gfid_path, this, gfid, NULL);
+
+ POSIX_GET_FILE_UNLINK_PATH (priv_posix->base_path,
+ loc->inode->gfid, unlink_path);
+ if (!unlink_path) {
+ ret = -1;
+ goto out;
+ }
+ gf_msg_debug (this->name, 0,
+ "Moving gfid: %s to unlink_path : %s",
+ gfid_path, unlink_path);
+ ret = sys_rename (gfid_path, unlink_path);
+ if (ret < 0) {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_UNLINK_FAILED,
+ "Creation of unlink entry failed for gfid: %s",
+ unlink_path);
+ goto out;
+ }
+ ret = posix_add_unlink_to_ctx (loc->inode, this, unlink_path);
+ if (ret < 0)
+ goto out;
+
+out:
+ return ret;
+}
+
+int32_t
+posix_unlink_gfid_handle_and_entry (xlator_t *this, const char *real_path,
+ struct iatt *stbuf, int32_t *op_errno,
+ loc_t *loc, gf_boolean_t get_link_count,
+ dict_t *rsp_dict)
+{
+ int32_t ret = 0;
+ struct iatt prebuf = {0,};
+ gf_boolean_t locked = _gf_false;
+
+ /* Unlink the gfid_handle_first */
+ if (stbuf && stbuf->ia_nlink == 1) {
+
+ LOCK (&loc->inode->lock);
+
+ if (loc->inode->fd_count == 0) {
+ UNLOCK (&loc->inode->lock);
+ ret = posix_handle_unset (this, stbuf->ia_gfid, NULL);
+ } else {
+ UNLOCK (&loc->inode->lock);
+ ret = posix_move_gfid_to_unlink (this, stbuf->ia_gfid,
+ loc);
+ }
+ if (ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_UNLINK_FAILED, "unlink of gfid handle "
+ "failed for path:%s with gfid %s",
+ real_path, uuid_utoa (stbuf->ia_gfid));
+ }
+ }
+
+ if (get_link_count) {
+ LOCK (&loc->inode->lock);
+ locked = _gf_true;
+ ret = posix_pstat (this, loc->gfid, real_path, &prebuf);
+ if (ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_LSTAT_FAILED, "lstat on %s failed",
+ real_path);
+ goto err;
+ }
+ }
+
+ /* Unlink the actual file */
+ ret = sys_unlink (real_path);
+ if (ret == -1) {
+ if (op_errno)
+ *op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_UNLINK_FAILED,
+ "unlink of %s failed", real_path);
+ goto err;
+ }
+
+ if (locked) {
+ UNLOCK (&loc->inode->lock);
+ locked = _gf_false;
+ }
+
+ ret = dict_set_uint32 (rsp_dict, GET_LINK_COUNT, prebuf.ia_nlink);
+ if (ret)
+ gf_msg (this->name, GF_LOG_WARNING, 0, P_MSG_SET_XDATA_FAIL,
+ "failed to set "GET_LINK_COUNT" for %s", real_path);
+
+ return 0;
+
+err:
+ if (locked) {
+ UNLOCK (&loc->inode->lock);
+ locked = _gf_false;
+ }
+ return -1;
+}
+
+gf_boolean_t
+posix_skip_non_linkto_unlink (dict_t *xdata, loc_t *loc, char *key,
+ const char *linkto_xattr, struct iatt *stbuf,
+ const char *real_path)
+{
+ gf_boolean_t skip_unlink = _gf_false;
+ gf_boolean_t is_dht_linkto_file = _gf_false;
+ int unlink_if_linkto = 0;
+ ssize_t xattr_size = -1;
+ int op_ret = -1;
+
+ op_ret = dict_get_int32 (xdata, key,
+ &unlink_if_linkto);
+
+ if (!op_ret && unlink_if_linkto) {
+
+ is_dht_linkto_file = IS_DHT_LINKFILE_MODE (stbuf);
+ if (!is_dht_linkto_file)
+ return _gf_true;
+
+ LOCK (&loc->inode->lock);
+
+ xattr_size = sys_lgetxattr (real_path, linkto_xattr, NULL, 0);
+
+ if (xattr_size <= 0)
+ skip_unlink = _gf_true;
+
+ UNLOCK (&loc->inode->lock);
+
+ gf_msg ("posix", GF_LOG_INFO, 0, P_MSG_XATTR_STATUS,
+ "linkto_xattr status: %"PRIu32" for %s", skip_unlink,
+ real_path);
+ }
+ return skip_unlink;
+
+}
+
+int32_t
+posix_unlink (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, int xflag, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_path = NULL;
+ char *par_path = NULL;
+ int32_t fd = -1;
+ struct iatt stbuf = {0,};
+ struct iatt postbuf = {0,};
+ struct posix_private *priv = NULL;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
+ int32_t check_open_fd = 0;
+ int32_t skip_unlink = 0;
+ int32_t fdstat_requested = 0;
+ dict_t *unwind_dict = NULL;
+ void *uuid = NULL;
+ char uuid_str[GF_UUID_BUF_SIZE] = {0};
+ char gfid_str[GF_UUID_BUF_SIZE] = {0};
+ gf_boolean_t get_link_count = _gf_false;
+ posix_inode_ctx_t *ctx = NULL;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ SET_FS_ID (frame->root->uid, frame->root->gid);
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, &stbuf);
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ priv = this->private;
+
+ op_ret = dict_get_ptr (xdata, TIER_LINKFILE_GFID, &uuid);
+
+ if (!op_ret && gf_uuid_compare (uuid, stbuf.ia_gfid)) {
+ op_errno = ENOENT;
+ op_ret = -1;
+ gf_uuid_unparse (uuid, uuid_str);
+ gf_uuid_unparse (stbuf.ia_gfid, gfid_str);
+ gf_msg_debug (this->name, op_errno, "Mismatch in gfid for path "
+ "%s. Aborting the unlink. loc->gfid = %s, "
+ "stbuf->ia_gfid = %s", real_path,
+ uuid_str, gfid_str);
+ goto out;
+ }
+
+ op_ret = dict_get_int32 (xdata, DHT_SKIP_OPEN_FD_UNLINK,
+ &check_open_fd);
+
+ if (!op_ret && check_open_fd) {
+
+ LOCK (&loc->inode->lock);
+
+ if (loc->inode->fd_count) {
+ skip_unlink = 1;
+ }
+
+ UNLOCK (&loc->inode->lock);
+
+ gf_msg (this->name, GF_LOG_INFO, 0, P_MSG_KEY_STATUS_INFO,
+ "open-fd-key-status: %"PRIu32" for %s", skip_unlink,
+ real_path);
+
+ if (skip_unlink) {
+ op_ret = -1;
+ op_errno = EBUSY;
+ goto out;
+ }
+ }
+ /*
+ * If either of the function return true, skip_unlink.
+ * If first first function itself return true,
+ * we don't need to call second function, skip unlink.
+ */
+ skip_unlink = posix_skip_non_linkto_unlink (xdata, loc,
+ DHT_SKIP_NON_LINKTO_UNLINK,
+ DHT_LINKTO, &stbuf,
+ real_path);
+ skip_unlink = skip_unlink || posix_skip_non_linkto_unlink (xdata, loc,
+ TIER_SKIP_NON_LINKTO_UNLINK,
+ TIER_LINKTO, &stbuf,
+ real_path);
+ if (skip_unlink) {
+ op_ret = -1;
+ op_errno = EBUSY;
+ goto out;
+ }
+
+ if (IA_ISREG (loc->inode->ia_type) &&
+ xdata && dict_get (xdata, DHT_IATT_IN_XDATA_KEY)) {
+ fdstat_requested = 1;
+ }
+
+ if (fdstat_requested ||
+ (priv->background_unlink && IA_ISREG (loc->inode->ia_type))) {
+ fd = sys_open (real_path, O_RDONLY, 0);
+ if (fd == -1) {
+ op_ret = -1;
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_OPEN_FAILED,
+ "open of %s failed", real_path);
+ goto out;
+ }
+ }
+
+ if (priv->update_pgfid_nlinks && (stbuf.ia_nlink > 1)) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+ op_ret = posix_inode_ctx_get_all (loc->inode, this, &ctx);
+ if (op_ret < 0) {
+ op_errno = ENOMEM;
+ goto out;
+ }
+ pthread_mutex_lock (&ctx->pgfid_lock);
+ {
+ UNLINK_MODIFY_PGFID_XATTR (real_path, pgfid_xattr_key,
+ nlink_samepgfid, 0, op_ret,
+ this, unlock);
+ }
+ unlock:
+ pthread_mutex_unlock (&ctx->pgfid_lock);
+
+ if (op_ret < 0) {
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ P_MSG_XATTR_FAILED, "modification of "
+ "parent gfid xattr failed (path:%s gfid:%s)",
+ real_path, uuid_utoa (loc->inode->gfid));
+ if (op_errno != ENOATTR)
+ /* Allow unlink if pgfid xattr is not set. */
+ goto out;
+ }
+ }
+
+ if (priv->gfid2path && (stbuf.ia_nlink > 1)) {
+ op_ret = posix_remove_gfid2path_xattr (this, real_path,
+ loc->pargfid,
+ loc->name);
+ if (op_ret < 0) {
+ /* Allow unlink if pgfid xattr is not set. */
+ if (errno != ENOATTR)
+ goto out;
+ }
+ }
+
+ unwind_dict = dict_new ();
+ if (!unwind_dict) {
+ op_errno = -ENOMEM;
+ op_ret = -1;
+ goto out;
+ }
+
+ if (xdata && dict_get (xdata, GET_LINK_COUNT))
+ get_link_count = _gf_true;
+ op_ret = posix_unlink_gfid_handle_and_entry (this, real_path, &stbuf,
+ &op_errno, loc,
+ get_link_count,
+ unwind_dict);
+ if (op_ret == -1) {
+ goto out;
+ }
+
+ if (fdstat_requested) {
+ op_ret = posix_fdstat (this, fd, &postbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_FSTAT_FAILED, "post operation "
+ "fstat failed on fd=%d", fd);
+ goto out;
+ }
+ op_ret = posix_set_iatt_in_dict (unwind_dict, &postbuf);
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ unwind_dict = posix_dict_set_nlink (xdata, unwind_dict, stbuf.ia_nlink);
+ op_ret = 0;
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (unlink, frame, op_ret, op_errno,
+ &preparent, &postparent, unwind_dict);
+
+ if (fd != -1) {
+ sys_close (fd);
+ }
+
+ /* unref unwind_dict*/
+ if (unwind_dict) {
+ dict_unref (unwind_dict);
+ }
+
+ return 0;
+}
+
+
+int
+posix_rmdir (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, int flags, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_path = NULL;
+ char *par_path = NULL;
+ char *gfid_str = NULL;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ struct iatt stbuf = {0,};
+ struct posix_private *priv = NULL;
+ char tmp_path[PATH_MAX] = {0,};
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ SET_FS_ID (frame->root->uid, frame->root->gid);
+
+ /* The Hidden directory should be for housekeeping purpose and it
+ should not get deleted from inside process */
+ if (__is_root_gfid (loc->pargfid) &&
+ (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {
+ gf_msg (this->name, GF_LOG_WARNING, EPERM,
+ P_MSG_RMDIR_NOT_PERMITTED, "rmdir issued on %s, which"
+ "is not permitted", GF_HIDDEN_PATH);
+ op_errno = EPERM;
+ op_ret = -1;
+ goto out;
+ }
+
+ priv = this->private;
+
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, &stbuf);
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ if (flags) {
+ gfid_str = uuid_utoa (stbuf.ia_gfid);
+
+ op_ret = sys_mkdir (priv->trash_path, 0755);
+ if (errno != EEXIST && op_ret == -1) {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_MKDIR_FAILED,
+ "mkdir of %s failed", priv->trash_path);
+ } else {
+ (void) snprintf (tmp_path, sizeof(tmp_path), "%s/%s",
+ priv->trash_path, gfid_str);
+ op_ret = sys_rename (real_path, tmp_path);
+ pthread_cond_signal (&priv->janitor_cond);
+ }
+ } else {
+ op_ret = sys_rmdir (real_path);
+ }
+ op_errno = errno;
+
+ if (op_ret == 0) {
+ if (posix_symlinks_match (this, loc, stbuf.ia_gfid))
+ posix_handle_unset (this, stbuf.ia_gfid, NULL);
+ }
+
+ if (op_errno == EEXIST)
+ /* Solaris sets errno = EEXIST instead of ENOTEMPTY */
+ op_errno = ENOTEMPTY;
+
+ /* No need to log a common error as ENOTEMPTY */
+ if (op_ret == -1 && op_errno != ENOTEMPTY) {
+ gf_msg (this->name, GF_LOG_ERROR, op_errno, P_MSG_RMDIR_FAILED,
+ "rmdir of %s failed", real_path);
+ }
+
+ if (op_ret == -1) {
+ if (op_errno == ENOTEMPTY) {
+ gf_msg_debug (this->name, 0, "%s on %s failed", (flags)
+ ? "rename" : "rmdir", real_path);
+ } else {
+ gf_msg (this->name, GF_LOG_ERROR, op_errno,
+ P_MSG_DIR_OPERATION_FAILED, "%s on %s failed",
+ (flags) ? "rename" : "rmdir", real_path);
+ }
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent of %s failed",
+ par_path);
+ goto out;
+ }
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno,
+ &preparent, &postparent, NULL);
+
+ return 0;
+}
+
+
+int
+posix_symlink (call_frame_t *frame, xlator_t *this,
+ const char *linkname, loc_t *loc, mode_t umask, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char * real_path = 0;
+ char * par_path = 0;
+ struct iatt stbuf = { 0, };
+ struct posix_private *priv = NULL;
+ gid_t gid = 0;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
+ gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (linkname, out);
+ VALIDATE_OR_GOTO (loc, out);
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ GFID_NULL_CHECK_AND_GOTO (frame, this, loc, xdata, op_ret, op_errno,
+ out);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, &stbuf);
+
+ gid = frame->root->gid;
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ SET_FS_ID (frame->root->uid, gid);
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ if (preparent.ia_prot.sgid) {
+ gid = preparent.ia_gid;
+ }
+
+ op_ret = sys_symlink (linkname, real_path);
+
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_SYMLINK_FAILED,
+ "symlink of %s --> %s failed",
+ real_path, linkname);
+ goto out;
+ }
+
+ entry_created = _gf_true;
+
+#ifndef HAVE_SET_FSID
+ op_ret = sys_lchown (real_path, frame->root->uid, gid);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LCHOWN_FAILED,
+ "lchown failed on %s", real_path);
+ goto out;
+ }
+#endif
+ op_ret = posix_acl_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_ACL_FAILED,
+ "setting ACLs on %s failed", real_path);
+ }
+
+ if (priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+ nlink_samepgfid = 1;
+ SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid,
+ XATTR_CREATE, op_ret, this, ignore);
+ }
+
+ if (priv->gfid2path) {
+ posix_set_gfid2path_xattr (this, real_path, loc->pargfid,
+ loc->name);
+ }
+
+ignore:
+ op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
+ "setting xattrs on %s failed ", real_path);
+ }
+
+ op_ret = posix_gfid_set (this, real_path, loc, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0, P_MSG_GFID_FAILED,
+ "setting gfid on %s failed", real_path);
+ } else {
+ gfid_set = _gf_true;
+ }
+
+ op_ret = posix_pstat (this, NULL, real_path, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat failed on %s", real_path);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ op_ret = 0;
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (symlink, frame, op_ret, op_errno,
+ (loc)?loc->inode:NULL, &stbuf, &preparent,
+ &postparent, NULL);
+
+ if (op_ret < 0) {
+ if (entry_created)
+ sys_unlink (real_path);
+
+ if (gfid_set)
+ posix_gfid_unset (this, xdata);
+ }
+
+ return 0;
+}
+
+
+int
+posix_rename (call_frame_t *frame, xlator_t *this,
+ loc_t *oldloc, loc_t *newloc, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_oldpath = NULL;
+ char *real_newpath = NULL;
+ char *par_oldpath = NULL;
+ char *par_newpath = NULL;
+ struct iatt stbuf = {0, };
+ struct posix_private *priv = NULL;
+ char was_present = 1;
+ struct iatt preoldparent = {0, };
+ struct iatt postoldparent = {0, };
+ struct iatt prenewparent = {0, };
+ struct iatt postnewparent = {0, };
+ char olddirid[64];
+ char newdirid[64];
+ uuid_t victim = {0};
+ int was_dir = 0;
+ int nlink = 0;
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
+ char *gfid_path = NULL;
+ dict_t *unwind_dict = NULL;
+ gf_boolean_t locked = _gf_false;
+ gf_boolean_t get_link_count = _gf_false;
+ posix_inode_ctx_t *ctx_old = NULL;
+ posix_inode_ctx_t *ctx_new = NULL;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (oldloc, out);
+ VALIDATE_OR_GOTO (newloc, out);
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+
+ SET_FS_ID (frame->root->uid, frame->root->gid);
+ MAKE_ENTRY_HANDLE (real_oldpath, par_oldpath, this, oldloc, NULL);
+ if (!real_oldpath || !par_oldpath) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ MAKE_ENTRY_HANDLE (real_newpath, par_newpath, this, newloc, &stbuf);
+ if (!real_newpath || !par_newpath) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ unwind_dict = dict_new ();
+ if (!unwind_dict) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, oldloc->pargfid, par_oldpath, &preoldparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_oldpath);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, newloc->pargfid, par_newpath, &prenewparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent of %s failed",
+ par_newpath);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, NULL, real_newpath, &stbuf);
+ if ((op_ret == -1) && (errno == ENOENT)){
+ was_present = 0;
+ } else {
+ gf_uuid_copy (victim, stbuf.ia_gfid);
+ if (IA_ISDIR (stbuf.ia_type))
+ was_dir = 1;
+ nlink = stbuf.ia_nlink;
+ }
+
+ if (was_present && IA_ISDIR(stbuf.ia_type) && !newloc->inode) {
+ gf_msg (this->name, GF_LOG_WARNING, EEXIST, P_MSG_DIR_FOUND,
+ "found directory at %s while expecting ENOENT",
+ real_newpath);
+ op_ret = -1;
+ op_errno = EEXIST;
+ goto out;
+ }
+
+ if (was_present && IA_ISDIR(stbuf.ia_type) &&
+ gf_uuid_compare (newloc->inode->gfid, stbuf.ia_gfid)) {
+ gf_msg (this->name, GF_LOG_WARNING, EEXIST, P_MSG_DIR_FOUND,
+ "found directory %s at %s while renaming %s",
+ uuid_utoa_r (newloc->inode->gfid, olddirid),
+ real_newpath,
+ uuid_utoa_r (stbuf.ia_gfid, newdirid));
+ op_ret = -1;
+ op_errno = EEXIST;
+ goto out;
+ }
+
+ op_ret = posix_inode_ctx_get_all (oldloc->inode, this, &ctx_old);
+ if (op_ret < 0) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ if (newloc->inode) {
+ op_ret = posix_inode_ctx_get_all (newloc->inode, this, &ctx_new);
+ if (op_ret < 0) {
+ op_ret = -1;
+ op_errno = ENOMEM;
+ goto out;
+ }
+ }
+
+ if (IA_ISDIR (oldloc->inode->ia_type))
+ posix_handle_unset (this, oldloc->inode->gfid, NULL);
+
+ pthread_mutex_lock (&ctx_old->pgfid_lock);
+ {
+ if (!IA_ISDIR (oldloc->inode->ia_type)
+ && priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key,
+ PGFID_XATTR_KEY_PREFIX,
+ oldloc->pargfid);
+ UNLINK_MODIFY_PGFID_XATTR (real_oldpath,
+ pgfid_xattr_key,
+ nlink_samepgfid, 0,
+ op_ret,
+ this, unlock);
+ }
+
+ if ((xdata) && (dict_get (xdata, GET_LINK_COUNT))
+ && (real_newpath) && (was_present)) {
+ pthread_mutex_lock (&ctx_new->pgfid_lock);
+ locked = _gf_true;
+ get_link_count = _gf_true;
+ op_ret = posix_pstat (this, newloc->gfid, real_newpath,
+ &stbuf);
+ if ((op_ret == -1) && (errno != ENOENT)) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_LSTAT_FAILED,
+ "lstat on %s failed", real_newpath);
+ goto unlock;
+ }
+ }
+
+ op_ret = sys_rename (real_oldpath, real_newpath);
+ if (op_ret == -1) {
+ op_errno = errno;
+ if (op_errno == ENOTEMPTY) {
+ gf_msg_debug (this->name, 0, "rename of %s to"
+ " %s failed: %s", real_oldpath,
+ real_newpath,
+ strerror (op_errno));
+ } else {
+ gf_msg (this->name, GF_LOG_ERROR, errno,
+ P_MSG_RENAME_FAILED,
+ "rename of %s to %s failed",
+ real_oldpath, real_newpath);
+ }
+
+ if (priv->update_pgfid_nlinks
+ && !IA_ISDIR (oldloc->inode->ia_type)) {
+ LINK_MODIFY_PGFID_XATTR (real_oldpath,
+ pgfid_xattr_key,
+ nlink_samepgfid, 0,
+ op_ret,
+ this, unlock);
+ }
+
+ goto unlock;
+ }
+
+ if (locked) {
+ pthread_mutex_unlock (&ctx_new->pgfid_lock);
+ locked = _gf_false;
+ }
+
+ if ((get_link_count) &&
+ (dict_set_uint32 (unwind_dict, GET_LINK_COUNT,
+ stbuf.ia_nlink)))
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ P_MSG_SET_XDATA_FAIL, "failed to set "
+ GET_LINK_COUNT" for %s", real_newpath);
+
+ if (!IA_ISDIR (oldloc->inode->ia_type)
+ && priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key,
+ PGFID_XATTR_KEY_PREFIX,
+ newloc->pargfid);
+ LINK_MODIFY_PGFID_XATTR (real_newpath,
+ pgfid_xattr_key,
+ nlink_samepgfid, 0,
+ op_ret,
+ this, unlock);
+ }
+
+ if (!IA_ISDIR (oldloc->inode->ia_type) && priv->gfid2path) {
+ MAKE_HANDLE_ABSPATH (gfid_path, this,
+ oldloc->inode->gfid);
+
+ posix_remove_gfid2path_xattr (this, gfid_path,
+ oldloc->pargfid,
+ oldloc->name);
+ posix_set_gfid2path_xattr (this, gfid_path,
+ newloc->pargfid,
+ newloc->name);
+ }
+ }
+
+unlock:
+ if (locked) {
+ pthread_mutex_unlock (&ctx_new->pgfid_lock);
+ locked = _gf_false;
+ }
+ pthread_mutex_unlock (&ctx_old->pgfid_lock);
+
+ if (op_ret < 0) {
+ gf_msg (this->name, GF_LOG_WARNING, 0, P_MSG_XATTR_FAILED,
+ "modification of "
+ "parent gfid xattr failed (gfid:%s)",
+ uuid_utoa (oldloc->inode->gfid));
+ goto out;
+ }
+
+ if (was_dir)
+ posix_handle_unset (this, victim, NULL);
+
+ if (was_present && !was_dir && nlink == 1)
+ posix_handle_unset (this, victim, NULL);
+
+ if (IA_ISDIR (oldloc->inode->ia_type)) {
+ posix_handle_soft (this, real_newpath, newloc,
+ oldloc->inode->gfid, NULL);
+ }
+
+ op_ret = posix_pstat (this, NULL, real_newpath, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat on %s failed", real_newpath);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, oldloc->pargfid, par_oldpath, &postoldparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_oldpath);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, newloc->pargfid, par_newpath, &postnewparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_newpath);
+ goto out;
+ }
+
+ if (was_present)
+ unwind_dict = posix_dict_set_nlink (xdata, unwind_dict, nlink);
+ op_ret = 0;
+out:
+
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, &stbuf,
+ &preoldparent, &postoldparent,
+ &prenewparent, &postnewparent, unwind_dict);
+
+ if (unwind_dict)
+ dict_unref (unwind_dict);
+
+ return 0;
+}
+
+
+int
+posix_link (call_frame_t *frame, xlator_t *this,
+ loc_t *oldloc, loc_t *newloc, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char *real_oldpath = 0;
+ char *real_newpath = 0;
+ char *par_newpath = 0;
+ struct iatt stbuf = {0, };
+ struct posix_private *priv = NULL;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ int32_t nlink_samepgfid = 0;
+ char *pgfid_xattr_key = NULL;
+ gf_boolean_t entry_created = _gf_false;
+ posix_inode_ctx_t *ctx = NULL;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (oldloc, out);
+ VALIDATE_OR_GOTO (newloc, out);
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+
+ SET_FS_ID (frame->root->uid, frame->root->gid);
+ MAKE_INODE_HANDLE (real_oldpath, this, oldloc, &stbuf);
+ if (!real_oldpath) {
+ op_errno = errno;
+ goto out;
+ }
+
+ MAKE_ENTRY_HANDLE (real_newpath, par_newpath, this, newloc, &stbuf);
+ if (!real_newpath || !par_newpath) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, newloc->pargfid, par_newpath, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat failed: %s", par_newpath);
+ goto out;
+ }
+
+
+ op_ret = sys_link (real_oldpath, real_newpath);
+
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LINK_FAILED,
+ "link %s to %s failed",
+ real_oldpath, real_newpath);
+ goto out;
+ }
+
+ entry_created = _gf_true;
+
+ op_ret = posix_pstat (this, NULL, real_newpath, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat on %s failed", real_newpath);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, newloc->pargfid, par_newpath, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "lstat failed: %s", par_newpath);
+ goto out;
+ }
+
+ if (priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ newloc->pargfid);
+
+ op_ret = posix_inode_ctx_get_all (newloc->inode, this, &ctx);
+ if (op_ret < 0) {
+ op_errno = ENOMEM;
+ goto out;
+ }
+
+ pthread_mutex_lock (&ctx->pgfid_lock);
+ {
+ LINK_MODIFY_PGFID_XATTR (real_newpath, pgfid_xattr_key,
+ nlink_samepgfid, 0, op_ret,
+ this, unlock);
+ }
+ unlock:
+ pthread_mutex_unlock (&ctx->pgfid_lock);
+
+ if (op_ret < 0) {
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ P_MSG_XATTR_FAILED, "modification of "
+ "parent gfid xattr failed (path:%s gfid:%s)",
+ real_newpath, uuid_utoa (newloc->inode->gfid));
+ goto out;
+ }
+ }
+
+ if (priv->gfid2path) {
+ if (stbuf.ia_nlink <= MAX_GFID2PATH_LINK_SUP) {
+ op_ret = posix_set_gfid2path_xattr (this, real_newpath,
+ newloc->pargfid,
+ newloc->name);
+ if (op_ret) {
+ op_errno = errno;
+ goto out;
+ }
+ } else {
+ gf_msg (this->name, GF_LOG_INFO, 0,
+ P_MSG_XATTR_NOTSUP, "Link count exceeded. "
+ "gfid2path xattr not set (path:%s gfid:%s)",
+ real_newpath, uuid_utoa (newloc->inode->gfid));
+ }
+ }
+
+ op_ret = 0;
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ STACK_UNWIND_STRICT (link, frame, op_ret, op_errno,
+ (oldloc)?oldloc->inode:NULL, &stbuf, &preparent,
+ &postparent, NULL);
+
+ if (op_ret < 0) {
+ if (entry_created)
+ sys_unlink (real_newpath);
+ }
+
+ return 0;
+}
+
+int
+posix_create (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, int32_t flags, mode_t mode,
+ mode_t umask, fd_t *fd, dict_t *xdata)
+{
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ int32_t _fd = -1;
+ int _flags = 0;
+ char * real_path = NULL;
+ char * par_path = NULL;
+ struct iatt stbuf = {0, };
+ struct posix_fd * pfd = NULL;
+ struct posix_private * priv = NULL;
+ char was_present = 1;
+
+ gid_t gid = 0;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+
+ int nlink_samepgfid = 0;
+ char * pgfid_xattr_key = NULL;
+ gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false;
+ mode_t mode_bit = 0;
+
+ DECLARE_OLD_FS_ID_VAR;
+
+ VALIDATE_OR_GOTO (frame, out);
+ VALIDATE_OR_GOTO (this, out);
+ VALIDATE_OR_GOTO (this->private, out);
+ VALIDATE_OR_GOTO (loc, out);
+ VALIDATE_OR_GOTO (fd, out);
+
+ priv = this->private;
+ VALIDATE_OR_GOTO (priv, out);
+ GFID_NULL_CHECK_AND_GOTO (frame, this, loc, xdata, op_ret, op_errno,
+ out);
+ DISK_SPACE_CHECK_AND_GOTO (frame, priv, xdata, op_ret, op_errno, out);
+
+ MAKE_ENTRY_HANDLE (real_path, par_path, this, loc, &stbuf);
+
+ gid = frame->root->gid;
+
+ SET_FS_ID (frame->root->uid, gid);
+ if (!real_path || !par_path) {
+ op_ret = -1;
+ op_errno = ESTALE;
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &preparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "pre-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ if (preparent.ia_prot.sgid) {
+ gid = preparent.ia_gid;
+ }
+
+ if (!flags) {
+ _flags = O_CREAT | O_RDWR | O_EXCL;
+ }
+ else {
+ _flags = flags | O_CREAT;
+ }
+
+ op_ret = posix_pstat (this, NULL, real_path, &stbuf);
+ if ((op_ret == -1) && (errno == ENOENT)) {
+ was_present = 0;
+ }
+
+ if (priv->o_direct)
+ _flags |= O_DIRECT;
+
+ mode_bit = (priv->create_mask & mode) | priv->force_create_mode;
+ mode = posix_override_umask (mode, mode_bit);
+ _fd = sys_open (real_path, _flags, mode);
+
+ if (_fd == -1) {
+ op_errno = errno;
+ op_ret = -1;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_OPEN_FAILED,
+ "open on %s failed", real_path);
+ goto out;
+ }
+
+ if ((_flags & O_CREAT) && (_flags & O_EXCL)) {
+ entry_created = _gf_true;
+ }
+
+
+ if (was_present)
+ goto fill_stat;
+
+#ifndef HAVE_SET_FSID
+ op_ret = sys_chown (real_path, frame->root->uid, gid);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_CHOWN_FAILED,
+ "chown on %s failed", real_path);
+ }
+#endif
+ op_ret = posix_acl_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_ACL_FAILED,
+ "setting ACLs on %s failed", real_path);
+ }
+
+ if (priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+ nlink_samepgfid = 1;
+ SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid,
+ XATTR_CREATE, op_ret, this, ignore);
+ }
+
+ if (priv->gfid2path) {
+ posix_set_gfid2path_xattr (this, real_path, loc->pargfid,
+ loc->name);
+ }
+ignore:
+ op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
+ "setting xattrs on %s failed ", real_path);
+ }
+
+fill_stat:
+ op_ret = posix_gfid_set (this, real_path, loc, xdata);
+ if (op_ret) {
+ gf_msg (this->name, GF_LOG_ERROR, 0, P_MSG_GFID_FAILED,
+ "setting gfid on %s failed", real_path);
+ } else {
+ gfid_set = _gf_true;
+ }
+
+ op_ret = posix_fdstat (this, _fd, &stbuf);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_FSTAT_FAILED,
+ "fstat on %d failed", _fd);
+ goto out;
+ }
+
+ op_ret = posix_pstat (this, loc->pargfid, par_path, &postparent);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_LSTAT_FAILED,
+ "post-operation lstat on parent %s failed",
+ par_path);
+ goto out;
+ }
+
+ op_ret = -1;
+ pfd = GF_CALLOC (1, sizeof (*pfd), gf_posix_mt_posix_fd);
+ if (!pfd) {
+ op_errno = errno;
+ goto out;
+ }
+
+ pfd->flags = flags;
+ pfd->fd = _fd;
+
+ op_ret = fd_ctx_set (fd, this, (uint64_t)(long)pfd);
+ if (op_ret)
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ P_MSG_FD_PATH_SETTING_FAILED,
+ "failed to set the fd context path=%s fd=%p",
+ real_path, fd);
+
+ LOCK (&priv->lock);
+ {
+ priv->nr_files++;
+ }
+ UNLOCK (&priv->lock);
+
+ op_ret = 0;
+
+out:
+ SET_TO_OLD_FS_ID ();
+
+ if ((-1 == op_ret) && (_fd != -1)) {
+ sys_close (_fd);
+ }
+
+ STACK_UNWIND_STRICT (create, frame, op_ret, op_errno,
+ fd, (loc)?loc->inode:NULL, &stbuf, &preparent,
+ &postparent, xdata);
+
+ if (op_ret < 0) {
+ if (entry_created)
+ sys_unlink (real_path);
+
+ if (gfid_set)
+ posix_gfid_unset (this, xdata);
+ }
+
+ return 0;
+}