diff options
-rw-r--r-- | xlators/features/bit-rot/src/stub/Makefile.am | 5 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-common.h | 2 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c | 606 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h | 72 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub.c | 206 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub.h | 155 |
6 files changed, 955 insertions, 91 deletions
diff --git a/xlators/features/bit-rot/src/stub/Makefile.am b/xlators/features/bit-rot/src/stub/Makefile.am index 5b5253c4ad5..1746344f1b0 100644 --- a/xlators/features/bit-rot/src/stub/Makefile.am +++ b/xlators/features/bit-rot/src/stub/Makefile.am @@ -3,13 +3,14 @@ xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features bitrot_stub_la_LDFLAGS = $(GF_XLATOR_DEFAULT_LDFLAGS) -bitrot_stub_la_SOURCES = bit-rot-stub.c +bitrot_stub_la_SOURCES = bit-rot-stub-helpers.c bit-rot-stub.c bitrot_stub_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la noinst_HEADERS = bit-rot-stub.h bit-rot-common.h bit-rot-stub-mem-types.h \ bit-rot-object-version.h bit-rot-stub-messages.h -AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/rpc/xdr/src -I$(top_srcdir)/rpc/rpc-lib/src AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/xlators/features/bit-rot/src/stub/bit-rot-common.h b/xlators/features/bit-rot/src/stub/bit-rot-common.h index bcf931a2b0b..2afc9f47c29 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-common.h +++ b/xlators/features/bit-rot/src/stub/bit-rot-common.h @@ -21,6 +21,8 @@ #define BR_VXATTR_ALL_MISSING \ (BR_VXATTR_VERSION | BR_VXATTR_SIGNATURE) +#define BR_BAD_OBJ_CONTAINER (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8} + typedef enum br_vxattr_state { BR_VXATTR_STATUS_FULL = 0, BR_VXATTR_STATUS_MISSING = 1, diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c b/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c new file mode 100644 index 00000000000..f637e150a57 --- /dev/null +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c @@ -0,0 +1,606 @@ +/* + Copyright (c) 2015 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. +*/ + +#include "bit-rot-stub.h" + +br_stub_fd_t * +br_stub_fd_new (void) +{ + br_stub_fd_t *br_stub_fd = NULL; + + br_stub_fd = GF_CALLOC (1, sizeof (*br_stub_fd), + gf_br_stub_mt_br_stub_fd_t); + + return br_stub_fd; +} + +int +__br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd) +{ + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, br_stub_fd, out); + + value = (uint64_t)(long) br_stub_fd; + + ret = __fd_ctx_set (fd, this, value); + +out: + return ret; +} + +br_stub_fd_t * +__br_stub_fd_ctx_get (xlator_t *this, fd_t *fd) +{ + br_stub_fd_t *br_stub_fd = NULL; + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + ret = __fd_ctx_get (fd, this, &value); + if (ret) + return NULL; + + br_stub_fd = (br_stub_fd_t *) ((long) value); + +out: + return br_stub_fd; +} + +br_stub_fd_t * +br_stub_fd_ctx_get (xlator_t *this, fd_t *fd) +{ + br_stub_fd_t *br_stub_fd = NULL; + + GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + LOCK (&fd->lock); + { + br_stub_fd = __br_stub_fd_ctx_get (this, fd); + } + UNLOCK (&fd->lock); + +out: + return br_stub_fd; +} + +int32_t +br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, br_stub_fd, out); + + LOCK (&fd->lock); + { + ret = __br_stub_fd_ctx_set (this, fd, br_stub_fd); + } + UNLOCK (&fd->lock); + +out: + return ret; +} + + +/** + * prints the path to the bad object's entry into the buffer provided. + * @priv: xlator private + * @filename: gfid of the bad object. + * @file_path: buffer provided into which path of the bad object is printed + * using above 2 arguments. + */ +static void +br_stub_link_path (br_stub_private_t *priv, const char *filename, + char *file_path, size_t len) +{ + snprintf (file_path, len, "%s/%s", priv->stub_basepath, filename); +} + +/** + * Prints the path of the object which acts as a container for all the bad + * objects. Each new entry corresponding to a bad object is a hard link to + * the object with name "stub-0000000000000008". + * @priv: xlator's private + * @stub_gfid_path: buffer into which the path to the container of bad objects + * is printed. + */ +static void +br_stub_container_entry (br_stub_private_t *priv, char *stub_gfid_path, + size_t len) +{ + + snprintf (stub_gfid_path, len, "%s/stub-%s", priv->stub_basepath, + uuid_utoa (priv->bad_object_dir_gfid)); +} + +/** + * Prints the path to the bad object's entry into the buffer provided. + * @priv: xlator private + * @gfid: gfid of the bad object. + * @gfid_path: buffer provided into which path of the bad object is printed + * using above 2 arguments. + * This function is same as br_stub_link_path. But in this function the + * gfid of the bad object is obtained as an argument (i.e. uuid_t gfid), + * where as in br_stub_link_path, the gfid is received as filename + * (i.e. char *filename) + */ +static void +br_stub_linked_entry (br_stub_private_t *priv, char *gfid_path, uuid_t gfid, + size_t len) +{ + snprintf (gfid_path, len, "%s/%s", priv->stub_basepath, + uuid_utoa (gfid)); +} + +/** + * Adds an entry to the bad objects directory. + * @gfid: gfid of the bad object being added to the bad objects directory + */ +int +br_stub_add (xlator_t *this, uuid_t gfid) +{ + char gfid_path[PATH_MAX] = {0}; + char bad_gfid_path[PATH_MAX] = {0}; + int ret = 0; + uuid_t index = {0}; + br_stub_private_t *priv = NULL; + struct stat st = {0}; + int fd = 0; + + priv = this->private; + GF_ASSERT_AND_GOTO_WITH_ERROR (this->name, !gf_uuid_is_null (gfid), + out, errno, EINVAL); + + br_stub_linked_entry (priv, gfid_path, gfid, sizeof (gfid_path)); + + ret = sys_stat (gfid_path, &st); + if (!ret) + goto out; + br_stub_container_entry (priv, bad_gfid_path, sizeof (bad_gfid_path)); + + ret = sys_link (bad_gfid_path, gfid_path); + if (ret) { + if ((errno != ENOENT) && (errno != EMLINK) && (errno != EEXIST)) + goto out; + + /* + * Continue with success. At least we'll have half of the + * functionality, in the sense, object is marked bad and + * would be inaccessible. It's only scrub status that would + * show up less number of objects. That's fine as we'll have + * the log files that will have the missing information. + */ + gf_msg (this->name, GF_LOG_WARNING, errno, BRS_MSG_LINK_FAIL, + "failed to record gfid [%s]", uuid_utoa (gfid)); + } + + return 0; +out: + return -1; +} + +static int +br_stub_check_stub_directory (xlator_t *this, char *fullpath) +{ + int ret = 0; + struct stat st = {0,}; + + ret = stat (fullpath, &st); + if (!ret && !S_ISDIR (st.st_mode)) + goto error_return; + if (ret) { + if (errno != ENOENT) + goto error_return; + ret = mkdir_p (fullpath, 0600, _gf_true); + } + + if (ret) + gf_msg (this->name, GF_LOG_ERROR, errno, + BRS_MSG_BAD_OBJECT_DIR_FAIL, + "failed to create stub directory [%s]", fullpath); + return ret; + +error_return: + gf_msg (this->name, GF_LOG_ERROR, errno, + BRS_MSG_BAD_OBJECT_DIR_FAIL, + "Failed to verify stub directory [%s]", fullpath); + return -1; +} + +/** + * Function to create the container for the bad objects within the bad objects + * directory. + */ +static int +br_stub_check_stub_file (xlator_t *this, char *path) +{ + int ret = 0; + int fd = -1; + struct stat st = {0,}; + + ret = stat (path, &st); + if (!ret && !S_ISREG (st.st_mode)) + goto error_return; + if (ret) { + if (errno != ENOENT) + goto error_return; + fd = sys_creat (path, 0); + if (fd < 0) + gf_msg (this->name, GF_LOG_ERROR, errno, + BRS_MSG_BAD_OBJECT_DIR_FAIL, + "Failed ot create stub file [%s]", path); + } + + if (fd >= 0) { + sys_close (fd); + ret = 0; + } + + return ret; + +error_return: + gf_msg (this->name, GF_LOG_ERROR, errno, + BRS_MSG_BAD_OBJECT_DIR_FAIL, "Failed ot verify stub file [%s]", path); + return -1; +} + +int +br_stub_dir_create (xlator_t *this, br_stub_private_t *priv) +{ + int ret = -1; + char fullpath[PATH_MAX] = {0}; + char stub_gfid_path[PATH_MAX] = {0, }; + char path[PATH_MAX] = {0}; + size_t len = 0; + + gf_uuid_copy (priv->bad_object_dir_gfid, BR_BAD_OBJ_CONTAINER); + + snprintf (fullpath, sizeof (fullpath), "%s", priv->stub_basepath); + + br_stub_container_entry (priv, stub_gfid_path, sizeof (stub_gfid_path)); + + ret = br_stub_check_stub_directory (this, fullpath); + if (ret) + goto out; + ret = br_stub_check_stub_file (this, stub_gfid_path); + if (ret) + goto out; + + return 0; + +out: + return -1; +} + +call_stub_t * +__br_stub_dequeue (struct list_head *callstubs) +{ + call_stub_t *stub = NULL; + + if (!list_empty (callstubs)) { + stub = list_entry (callstubs->next, call_stub_t, list); + list_del_init (&stub->list); + } + + return stub; +} + +void +__br_stub_enqueue (struct list_head *callstubs, call_stub_t *stub) +{ + list_add_tail (&stub->list, callstubs); +} + +void +br_stub_worker_enqueue (xlator_t *this, call_stub_t *stub) +{ + br_stub_private_t *priv = NULL; + + priv = this->private; + pthread_mutex_lock (&priv->container.bad_lock); + { + __br_stub_enqueue (&priv->container.bad_queue, stub); + pthread_cond_signal (&priv->container.bad_cond); + } + pthread_mutex_unlock (&priv->container.bad_lock); +} + +void * +br_stub_worker (void *data) +{ + br_stub_private_t *priv = NULL; + xlator_t *this = NULL; + call_stub_t *stub = NULL; + int ret = 0; + + + THIS = data; + this = data; + priv = this->private; + + for (;;) { + pthread_mutex_lock (&priv->container.bad_lock); + { + while (list_empty (&priv->container.bad_queue)) { + ret = pthread_cond_wait (&priv->container.bad_cond, + &priv->container.bad_lock); + } + + stub = __br_stub_dequeue (&priv->container.bad_queue); + } + pthread_mutex_unlock (&priv->container.bad_lock); + + if (stub) /* guard against spurious wakeups */ + call_resume (stub); + } + + return NULL; +} + +int32_t +br_stub_lookup_wrapper (call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *xattr_req) +{ + br_stub_private_t *priv = NULL; + struct stat lstatbuf = {0}; + int ret = 0; + int32_t op_errno = EINVAL; + int32_t op_ret = -1; + struct iatt stbuf = {0, }; + struct iatt postparent = {0,}; + dict_t *xattr = NULL; + + priv = this->private; + + VALIDATE_OR_GOTO (loc, done); + if (gf_uuid_compare (loc->gfid, priv->bad_object_dir_gfid)) + goto done; + + ret = sys_lstat (priv->stub_basepath, &lstatbuf); + if (ret) { + gf_msg_debug (this->name, errno, "Stat failed on stub bad " + "object dir"); + op_errno = errno; + goto done; + } else if (!S_ISDIR (lstatbuf.st_mode)) { + gf_msg_debug (this->name, errno, "bad object container is not " + "a directory"); + op_errno = ENOTDIR; + goto done; + } + + iatt_from_stat (&stbuf, &lstatbuf); + gf_uuid_copy (stbuf.ia_gfid, priv->bad_object_dir_gfid); + + op_ret = op_errno = 0; + xattr = dict_new (); + if (!xattr) { + op_ret = -1; + op_errno = ENOMEM; + } + +done: + STACK_UNWIND_STRICT (lookup, frame, op_ret, op_errno, + loc->inode, &stbuf, xattr, &postparent); + if (xattr) + dict_unref (xattr); + return 0; +} + +static int +is_bad_gfid_file_current (char *filename, uuid_t gfid) +{ + char current_stub_gfid[GF_UUID_BUF_SIZE + 16] = {0, }; + + snprintf (current_stub_gfid, sizeof current_stub_gfid, + "stub-%s", uuid_utoa(gfid)); + return (!strcmp(filename, current_stub_gfid)); +} + +static void +check_delete_stale_bad_file (xlator_t *this, char *filename) +{ + int ret = 0; + struct stat st = {0}; + char filepath[PATH_MAX] = {0}; + br_stub_private_t *priv = NULL; + + priv = this->private; + + if (is_bad_gfid_file_current (filename, priv->bad_object_dir_gfid)) + return; + + br_stub_link_path (priv, filename, filepath, sizeof (filepath)); + + ret = sys_stat (filepath, &st); + if (!ret && st.st_nlink == 1) + sys_unlink (filepath); +} + +static int +br_stub_fill_readdir (fd_t *fd, br_stub_fd_t *fctx, DIR *dir, off_t off, + size_t size, gf_dirent_t *entries) +{ + off_t in_case = -1; + off_t last_off = 0; + size_t filled = 0; + int count = 0; + char entrybuf[sizeof(struct dirent) + 256 + 8]; + struct dirent *entry = NULL; + int32_t this_size = -1; + gf_dirent_t *this_entry = NULL; + xlator_t *this = NULL; + + this = THIS; + if (!off) { + rewinddir (dir); + } else { + seekdir (dir, off); +#ifndef GF_LINUX_HOST_OS + if ((u_long)telldir(dir) != off && + off != fctx->bad_object.dir_eof) { + gf_msg (THIS->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJECT_DIR_SEEK_FAIL, + "seekdir(0x%llx) failed on dir=%p: " + "Invalid argument (offset reused from " + "another DIR * structure?)", off, dir); + errno = EINVAL; + count = -1; + goto out; + } +#endif /* GF_LINUX_HOST_OS */ + } + + while (filled <= size) { + in_case = (u_long)telldir (dir); + + if (in_case == -1) { + gf_msg (THIS->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJECT_DIR_TELL_FAIL, + "telldir failed on dir=%p: %s", + dir, strerror (errno)); + goto out; + } + + errno = 0; + entry = NULL; + readdir_r (dir, (struct dirent *)entrybuf, &entry); + + if (!entry) { + if (errno == EBADF) { + gf_msg (THIS->name, GF_LOG_WARNING, 0, + BRS_MSG_BAD_OBJECT_DIR_READ_FAIL, + "readdir failed on dir=%p: %s", + dir, strerror (errno)); + goto out; + } + break; + } + + if (!strcmp (entry->d_name, ".") || + !strcmp (entry->d_name, "..")) + continue; + + if (!strncmp (entry->d_name, "stub-", + strlen ("stub-"))) { + check_delete_stale_bad_file (this, entry->d_name); + continue; + } + + this_size = max (sizeof (gf_dirent_t), + sizeof (gfs3_dirplist)) + + strlen (entry->d_name) + 1; + + if (this_size + filled > size) { + seekdir (dir, in_case); +#ifndef GF_LINUX_HOST_OS + if ((u_long)telldir(dir) != in_case && + in_case != fctx->bad_object.dir_eof) { + gf_msg (THIS->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJECT_DIR_SEEK_FAIL, + "seekdir(0x%llx) failed on dir=%p: " + "Invalid argument (offset reused from " + "another DIR * structure?)", + in_case, dir); + errno = EINVAL; + count = -1; + goto out; + } +#endif /* GF_LINUX_HOST_OS */ + break; + } + + this_entry = gf_dirent_for_name (entry->d_name); + + if (!this_entry) { + gf_msg (THIS->name, GF_LOG_ERROR, 0, + BRS_MSG_NO_MEMORY, + "could not create gf_dirent for entry %s: (%s)", + entry->d_name, strerror (errno)); + goto out; + } + /* + * we store the offset of next entry here, which is + * probably not intended, but code using syncop_readdir() + * (glfs-heal.c, afr-self-heald.c, pump.c) rely on it + * for directory read resumption. + */ + last_off = (u_long)telldir(dir); + this_entry->d_off = last_off; + this_entry->d_ino = entry->d_ino; + + list_add_tail (&this_entry->list, &entries->list); + + filled += this_size; + count++; + } + + if ((!sys_readdir (dir) && (errno == 0))) { + /* Indicate EOF */ + errno = ENOENT; + /* Remember EOF offset for later detection */ + fctx->bad_object.dir_eof = last_off; + } +out: + return count; +} + +int32_t +br_stub_readdir_wrapper (call_frame_t *frame, xlator_t *this, + fd_t *fd, size_t size, off_t off, dict_t *xdata) +{ + br_stub_fd_t *fctx = NULL; + DIR *dir = NULL; + int ret = -1; + int32_t op_ret = -1; + int32_t op_errno = 0; + int count = 0; + gf_dirent_t entries; + + INIT_LIST_HEAD (&entries.list); + + fctx = br_stub_fd_ctx_get (this, fd); + if (!fctx) { + gf_msg (this->name, GF_LOG_WARNING, 0, + BRS_MSG_GET_FD_CONTEXT_FAILED, + "pfd is NULL, fd=%p", fd); + op_errno = -ret; + goto done; + } + + dir = fctx->bad_object.dir; + + if (!dir) { + gf_msg (this->name, GF_LOG_WARNING, 0, + BRS_MSG_BAD_HANDLE_DIR_NULL, + "dir is NULL for fd=%p", fd); + op_errno = EINVAL; + goto done; + } + + count = br_stub_fill_readdir (fd, fctx, dir, off, size, &entries); + + /* pick ENOENT to indicate EOF */ + op_errno = errno; + op_ret = count; +done: + STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, &entries, xdata); + gf_dirent_free (&entries); + return 0; +} + diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h b/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h index 532c2beb5c1..ee39e4c6d9f 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h @@ -40,7 +40,7 @@ */ #define GLFS_BITROT_STUB_BASE GLFS_MSGID_COMP_BITROT_STUB -#define GLFS_BITROT_STUB_NUM_MESSAGES 15 +#define GLFS_BITROT_STUB_NUM_MESSAGES 30 #define GLFS_MSGID_END (GLFS_BITROT_STUB_BASE + \ GLFS_BITROT_STUB_NUM_MESSAGES + 1) /* Messaged with message IDs */ @@ -188,6 +188,76 @@ * @recommendedaction * */ +#define BRS_MSG_BAD_CONTAINER_FAIL (GLFS_BITROT_STUB_BASE + 21) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJECT_DIR_FAIL (GLFS_BITROT_STUB_BASE + 22) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJECT_DIR_SEEK_FAIL (GLFS_BITROT_STUB_BASE + 23) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJECT_DIR_TELL_FAIL (GLFS_BITROT_STUB_BASE + 24) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJECT_DIR_READ_FAIL (GLFS_BITROT_STUB_BASE + 25) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_GET_FD_CONTEXT_FAILED (GLFS_BITROT_STUB_BASE + 26) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_HANDLE_DIR_NULL (GLFS_BITROT_STUB_BASE + 27) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJ_THREAD_FAIL (GLFS_BITROT_STUB_BASE + 28) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_BAD_OBJ_DIR_CLOSE_FAIL (GLFS_BITROT_STUB_BASE + 29) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define BRS_MSG_LINK_FAIL (GLFS_BITROT_STUB_BASE + 30) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ /*------------*/ #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub.c b/xlators/features/bit-rot/src/stub/bit-rot-stub.c index 85fad6925c1..83a78604665 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub.c +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub.c @@ -55,6 +55,66 @@ mem_acct_init (xlator_t *this) } int32_t +br_stub_bad_object_container_init (xlator_t *this, br_stub_private_t *priv) +{ + pthread_attr_t w_attr; + int32_t ret = -1; + + ret = pthread_cond_init(&priv->container.bad_cond, NULL); + if (ret != 0) { + gf_msg (this->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJ_THREAD_FAIL, + "pthread_cond_init failed (%d)", ret); + goto out; + } + + ret = pthread_mutex_init(&priv->container.bad_lock, NULL); + if (ret != 0) { + gf_msg (this->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJ_THREAD_FAIL, + "pthread_mutex_init failed (%d)", ret); + goto cleanup_cond; + } + + ret = pthread_attr_init (&w_attr); + if (ret != 0) { + gf_msg (this->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJ_THREAD_FAIL, + "pthread_attr_init failed (%d)", ret); + goto cleanup_lock; + } + + ret = pthread_attr_setstacksize (&w_attr, BAD_OBJECT_THREAD_STACK_SIZE); + if (ret == EINVAL) { + gf_msg (this->name, GF_LOG_WARNING, 0, + BRS_MSG_BAD_OBJ_THREAD_FAIL, + "Using default thread stack size"); + } + + INIT_LIST_HEAD (&priv->container.bad_queue); + ret = br_stub_dir_create (this, priv); + if (ret < 0) + goto cleanup_lock; + + ret = gf_thread_create (&priv->container.thread, &w_attr, br_stub_worker, this); + if (ret) + goto cleanup_attr; + + return 0; + +cleanup_attr: + pthread_attr_destroy (&w_attr); +cleanup_lock: + pthread_mutex_destroy (&priv->container.bad_lock); +cleanup_cond: + pthread_cond_destroy (&priv->container.bad_cond); +out: + return -1; +} + +#define BR_STUB_QUARANTINE_DIR GF_HIDDEN_PATH"/quanrantine" + +int32_t init (xlator_t *this) { int32_t ret = 0; @@ -81,6 +141,9 @@ init (xlator_t *this) GF_OPTION_INIT ("export", tmp, str, free_mempool); memcpy (priv->export, tmp, strlen (tmp) + 1); + (void) snprintf (priv->stub_basepath, PATH_MAX, + "%s/%s", priv->export, BR_STUB_QUARANTINE_DIR); + (void) gettimeofday (&tv, NULL); /* boot time is in network endian format */ @@ -95,8 +158,16 @@ init (xlator_t *this) if (ret != 0) goto cleanup_lock; + ret = br_stub_bad_object_container_init (this, priv); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, BRS_MSG_BAD_CONTAINER_FAIL, + "failed to launch the thread for storing bad gfids"); + goto cleanup_lock; + } + + this->private = priv; + gf_msg_debug (this->name, 0, "bit-rot stub loaded"); - this->private = priv; return 0; @@ -117,6 +188,7 @@ fini (xlator_t *this) int32_t ret = 0; br_stub_private_t *priv = this->private; struct br_stub_signentry *sigstub = NULL; + call_stub_t *stub = NULL; if (!priv) return; @@ -141,6 +213,24 @@ fini (xlator_t *this) pthread_mutex_destroy (&priv->lock); pthread_cond_destroy (&priv->cond); + ret = gf_thread_cleanup_xint (priv->container.thread); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + BRS_MSG_CANCEL_SIGN_THREAD_FAILED, + "Could not cancel sign serializer thread"); + goto out; + } + + while (!list_empty (&priv->container.bad_queue)) { + stub = list_first_entry (&priv->container.bad_queue, call_stub_t, + list); + list_del_init (&stub->list); + call_stub_destroy (stub); + }; + + pthread_mutex_destroy (&priv->container.bad_lock); + pthread_cond_destroy (&priv->container.bad_cond); + this->private = NULL; GF_FREE (priv); @@ -1018,6 +1108,8 @@ br_stub_fsetxattr_bad_object_cbk (call_frame_t *frame, void *cookie, "failed to mark object %s as bad", uuid_utoa (local->u.context.inode->gfid)); + ret = br_stub_add (this, local->u.context.inode->gfid); + unwind: STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno, xdata); br_stub_cleanup_local (local); @@ -2306,6 +2398,74 @@ br_stub_lookup_version (xlator_t *this, /** {{{ */ +int32_t +br_stub_opendir (call_frame_t *frame, xlator_t *this, + loc_t *loc, fd_t *fd, dict_t *xdata) +{ + br_stub_private_t *priv = NULL; + br_stub_fd_t *fd_ctx = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + + priv = this->private; + if (gf_uuid_compare (fd->inode->gfid, priv->bad_object_dir_gfid)) + goto normal; + + fd_ctx = br_stub_fd_new (); + if (!fd_ctx) { + op_errno = ENOMEM; + goto unwind; + } + + fd_ctx->bad_object.dir_eof = -1; + fd_ctx->bad_object.dir = sys_opendir (priv->stub_basepath); + if (!fd_ctx->bad_object.dir) { + op_errno = errno; + goto err_freectx; + } + + op_ret = br_stub_fd_ctx_set (this, fd, fd_ctx); + if (!op_ret) + goto unwind; + + sys_closedir (fd_ctx->bad_object.dir); + +err_freectx: + GF_FREE (fd_ctx); +unwind: + STACK_UNWIND_STRICT (opendir, frame, op_ret, op_errno, fd, NULL); + return 0; + +normal: + STACK_WIND (frame, default_opendir_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->opendir, loc, fd, xdata); + return 0; +} + +int32_t +br_stub_readdir (call_frame_t *frame, xlator_t *this, + fd_t *fd, size_t size, off_t off, dict_t *xdata) +{ + call_stub_t *stub = NULL; + br_stub_private_t *priv = NULL; + + priv = this->private; + if (gf_uuid_compare (fd->inode->gfid, priv->bad_object_dir_gfid)) + goto out; + stub = fop_readdir_stub (frame, br_stub_readdir_wrapper, fd, size, off, + xdata); + if (!stub) { + STACK_UNWIND_STRICT (readdir, frame, -1, ENOMEM, NULL, NULL); + return 0; + } + br_stub_worker_enqueue (this, stub); + return 0; +out: + STACK_WIND (frame, default_readdir_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readdir, fd, size, off, xdata); + return 0; +} + int br_stub_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, gf_dirent_t *entries, @@ -2480,11 +2640,28 @@ br_stub_lookup (call_frame_t *frame, void *cookie = NULL; uint64_t ctx_addr = 0; gf_boolean_t xref = _gf_false; + br_stub_private_t *priv = NULL; + call_stub_t *stub = NULL; GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, unwind); GF_VALIDATE_OR_GOTO (this->name, loc, unwind); GF_VALIDATE_OR_GOTO (this->name, loc->inode, unwind); + priv = this->private; + + if (!gf_uuid_compare (loc->gfid, priv->bad_object_dir_gfid) || + !gf_uuid_compare (loc->pargfid, priv->bad_object_dir_gfid)) { + + stub = fop_lookup_stub (frame, br_stub_lookup_wrapper, loc, + xdata); + if (!stub) { + op_errno = ENOMEM; + goto unwind; + } + br_stub_worker_enqueue (this, stub); + return 0; + } + ret = br_stub_get_inode_ctx (this, loc->inode, &ctx_addr); if (ret < 0) ctx_addr = 0; @@ -2727,6 +2904,31 @@ br_stub_release (xlator_t *this, fd_t *fd) return 0; } +int32_t +br_stub_releasedir (xlator_t *this, fd_t *fd) +{ + br_stub_fd_t *fctx = NULL; + uint64_t ctx = 0; + int ret = 0; + + ret = fd_ctx_del (fd, this, &ctx); + if (ret < 0) + goto out; + + fctx = (br_stub_fd_t *) (long) ctx; + if (fctx->bad_object.dir) { + ret = sys_closedir (fctx->bad_object.dir); + if (ret) + gf_msg (this->name, GF_LOG_ERROR, 0, + BRS_MSG_BAD_OBJ_DIR_CLOSE_FAIL, + "closedir error: %s", strerror (errno)); + } + + GF_FREE (fctx); +out: + return 0; +} + /** }}} */ /** {{{ */ @@ -2790,6 +2992,8 @@ struct xlator_fops fops = { .removexattr = br_stub_removexattr, .fremovexattr = br_stub_fremovexattr, .setxattr = br_stub_setxattr, + .opendir = br_stub_opendir, + .readdir = br_stub_readdir, }; struct xlator_cbks cbks = { diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub.h b/xlators/features/bit-rot/src/stub/bit-rot-stub.h index 9362c129303..26ed5fe0bdb 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub.h +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub.h @@ -17,9 +17,12 @@ #include "defaults.h" #include "call-stub.h" #include "bit-rot-stub-mem-types.h" - +#include "syscall.h" #include "bit-rot-common.h" #include "bit-rot-stub-messages.h" +#include "glusterfs3-xdr.h" + +#define BAD_OBJECT_THREAD_STACK_SIZE ((size_t)(1024*1024)) typedef int (br_stub_version_cbk) (call_frame_t *, void *, xlator_t *, int32_t, int32_t, dict_t *); @@ -38,6 +41,10 @@ typedef struct br_stub_inode_ctx { typedef struct br_stub_fd { fd_t *fd; struct list_head list; + struct bad_object_dir { + DIR *dir; + off_t dir_eof; + } bad_object; } br_stub_fd_t; #define I_DIRTY (1<<0) /* inode needs writeback */ @@ -77,10 +84,35 @@ typedef struct br_stub_private { struct list_head squeue; /* ordered signing queue */ pthread_t signth; - + struct bad_objects_container { + pthread_t thread; + pthread_mutex_t bad_lock; + pthread_cond_t bad_cond; + struct list_head bad_queue; + } container; struct mem_pool *local_pool; + + char stub_basepath[PATH_MAX]; + + uuid_t bad_object_dir_gfid; } br_stub_private_t; +br_stub_fd_t * +br_stub_fd_new (void); + + +int +__br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd); + +br_stub_fd_t * +__br_stub_fd_ctx_get (xlator_t *this, fd_t *fd); + +br_stub_fd_t * +br_stub_fd_ctx_get (xlator_t *this, fd_t *fd); + +int32_t +br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd); + static inline gf_boolean_t __br_stub_is_bad_object (br_stub_inode_ctx_t *ctx) { @@ -131,91 +163,6 @@ __br_stub_is_inode_modified (br_stub_inode_ctx_t *ctx) return (ctx->need_writeback & I_MODIFIED); } -br_stub_fd_t * -br_stub_fd_new (void) -{ - br_stub_fd_t *br_stub_fd = NULL; - - br_stub_fd = GF_CALLOC (1, sizeof (*br_stub_fd), - gf_br_stub_mt_br_stub_fd_t); - - return br_stub_fd; -} - -int -__br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd) -{ - uint64_t value = 0; - int ret = -1; - - GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); - GF_VALIDATE_OR_GOTO (this->name, fd, out); - GF_VALIDATE_OR_GOTO (this->name, br_stub_fd, out); - - value = (uint64_t)(long) br_stub_fd; - - ret = __fd_ctx_set (fd, this, value); - -out: - return ret; -} - -br_stub_fd_t * -__br_stub_fd_ctx_get (xlator_t *this, fd_t *fd) -{ - br_stub_fd_t *br_stub_fd = NULL; - uint64_t value = 0; - int ret = -1; - - GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); - GF_VALIDATE_OR_GOTO (this->name, fd, out); - - ret = __fd_ctx_get (fd, this, &value); - if (ret) - return NULL; - - br_stub_fd = (br_stub_fd_t *) ((long) value); - -out: - return br_stub_fd; -} - -br_stub_fd_t * -br_stub_fd_ctx_get (xlator_t *this, fd_t *fd) -{ - br_stub_fd_t *br_stub_fd = NULL; - - GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); - GF_VALIDATE_OR_GOTO (this->name, fd, out); - - LOCK (&fd->lock); - { - br_stub_fd = __br_stub_fd_ctx_get (this, fd); - } - UNLOCK (&fd->lock); - -out: - return br_stub_fd; -} - -int32_t -br_stub_fd_ctx_set (xlator_t *this, fd_t *fd, br_stub_fd_t *br_stub_fd) -{ - int32_t ret = -1; - - GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); - GF_VALIDATE_OR_GOTO (this->name, fd, out); - GF_VALIDATE_OR_GOTO (this->name, br_stub_fd, out); - - LOCK (&fd->lock); - { - ret = __br_stub_fd_ctx_set (this, fd, br_stub_fd); - } - UNLOCK (&fd->lock); - -out: - return ret; -} static inline int br_stub_require_release_call (xlator_t *this, fd_t *fd, br_stub_fd_t **fd_ctx) @@ -477,4 +424,38 @@ br_stub_add_fd_to_inode (xlator_t *this, fd_t *fd, br_stub_inode_ctx_t *ctx); br_sign_state_t __br_stub_inode_sign_state (br_stub_inode_ctx_t *ctx, glusterfs_fop_t fop, fd_t *fd); + +int +br_stub_dir_create (xlator_t *this, br_stub_private_t *priv); + +int +br_stub_add (xlator_t *this, uuid_t gfid); + +int32_t +br_stub_create_stub_gfid (xlator_t *this, char *stub_gfid_path, uuid_t gfid); + +int +br_stub_dir_create (xlator_t *this, br_stub_private_t *priv); + +call_stub_t * +__br_stub_dequeue (struct list_head *callstubs); + +void +__br_stub_enqueue (struct list_head *callstubs, call_stub_t *stub); + +void +br_stub_worker_enqueue (xlator_t *this, call_stub_t *stub); + +void * +br_stub_worker (void *data); + +int32_t +br_stub_lookup_wrapper (call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *xattr_req); + +int32_t +br_stub_readdir_wrapper (call_frame_t *frame, xlator_t *this, + fd_t *fd, size_t size, off_t off, dict_t *xdata); + + #endif /* __BIT_ROT_STUB_H__ */ |