summaryrefslogtreecommitdiffstats
path: root/xlators/features/changelog
diff options
context:
space:
mode:
authorKotresh HR <khiremat@redhat.com>2015-04-14 14:42:46 +0530
committerVenky Shankar <vshankar@redhat.com>2015-05-04 08:10:12 -0700
commit21515b3331d8d72011fef79008bcaff8ca43647a (patch)
tree359d6da85746fa815f856d394e2a2e5cf160e2a1 /xlators/features/changelog
parent2aceadae902e6f45e02afa62ee7831479d23b4a5 (diff)
feature/changelog: Capture path for deletes
PROBLEM: There is no way to get the path of deleted file if we have gfid from changelog since the file is already deleted. SOLUTION: Do a recursive readlink on parent gfid in backend .glusterfs path to get the complete path in I/O callpath in changelog translator and capture it in callback. The path captured is relative from the brick root. The field separator used is '\0'. e.g., ......\0<pgfid>/bname\0<relative-path>\0<next-record> ADDITIONAL REQUIRED CHANGES: 1. The changelog translator option called "changelog.capture-del-path" is introduced to enable or disable the capturing of deleted entry path. e.g., gluster vol set <vol-name> changelog.capture-del-path on/off If capture-del-path is disabled, '\0' is captured instead of relative path. e.g., ......\0<pgfid>/bname\0\0\0<next-record> 2. The minor number in the version of changelog is bumped up from v1.1 to v1.2. 3. If recursive readlink is failed for some reason, it will capture \0 in place of <relative path>. e.g., ......\0<pgfid>/bname\0\0\0<next-record> (same as when caputre-del-path option is disabled) 4. If bname argument passed to "resolve_pargfid_to_path" function is NULL and pargfid is ROOT, "." is returned. This is not the case with changelog, where bname is always passed. This is applicable to other consumers of "resolve_pargfid_to_path" routine. NOTE: Changelog parser should consider the above new changes and should parse accordingly. Change-Id: I040ed429b5aa7d391033fc6a540edbf07fc37827 BUG: 1214561 Signed-off-by: Kotresh HR <khiremat@redhat.com> Reviewed-on: http://review.gluster.org/10288 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Venky Shankar <vshankar@redhat.com> Tested-by: NetBSD Build System
Diffstat (limited to 'xlators/features/changelog')
-rw-r--r--xlators/features/changelog/src/changelog-encoders.c44
-rw-r--r--xlators/features/changelog/src/changelog-encoders.h4
-rw-r--r--xlators/features/changelog/src/changelog-helpers.c85
-rw-r--r--xlators/features/changelog/src/changelog-helpers.h26
-rw-r--r--xlators/features/changelog/src/changelog-misc.h2
-rw-r--r--xlators/features/changelog/src/changelog.c32
6 files changed, 188 insertions, 5 deletions
diff --git a/xlators/features/changelog/src/changelog-encoders.c b/xlators/features/changelog/src/changelog-encoders.c
index ea9db4061ca..ea395e11f90 100644
--- a/xlators/features/changelog/src/changelog-encoders.c
+++ b/xlators/features/changelog/src/changelog-encoders.c
@@ -39,6 +39,38 @@ entry_fn (void *data, char *buffer, gf_boolean_t encode)
}
size_t
+del_entry_fn (void *data, char *buffer, gf_boolean_t encode)
+{
+ char *tmpbuf = NULL;
+ size_t bufsz = 0;
+ struct changelog_entry_fields *ce = NULL;
+
+ ce = (struct changelog_entry_fields *) data;
+
+ if (encode) {
+ tmpbuf = uuid_utoa (ce->cef_uuid);
+ CHANGELOG_FILL_BUFFER (buffer, bufsz, tmpbuf, strlen (tmpbuf));
+ } else {
+ CHANGELOG_FILL_BUFFER (buffer, bufsz,
+ ce->cef_uuid, sizeof (uuid_t));
+ }
+
+ CHANGELOG_FILL_BUFFER (buffer, bufsz, "/", 1);
+ CHANGELOG_FILL_BUFFER (buffer, bufsz,
+ ce->cef_bname, strlen (ce->cef_bname));
+ CHANGELOG_FILL_BUFFER (buffer, bufsz, "\0", 1);
+
+ if (ce->cef_path[0] == '\0') {
+ CHANGELOG_FILL_BUFFER (buffer, bufsz, "\0", 1);
+ } else {
+ CHANGELOG_FILL_BUFFER (buffer, bufsz,
+ ce->cef_path, strlen (ce->cef_path));
+ }
+
+ return bufsz;
+}
+
+size_t
fop_fn (void *data, char *buffer, gf_boolean_t encode)
{
char buf[10] = {0,};
@@ -85,6 +117,18 @@ entry_free_fn (void *data)
GF_FREE (co->co_entry.cef_bname);
}
+void
+del_entry_free_fn (void *data)
+{
+ changelog_opt_t *co = data;
+
+ if (!co)
+ return;
+
+ GF_FREE (co->co_entry.cef_bname);
+ GF_FREE (co->co_entry.cef_path);
+}
+
/**
* try to write all data in one shot
*/
diff --git a/xlators/features/changelog/src/changelog-encoders.h b/xlators/features/changelog/src/changelog-encoders.h
index c5dcc8a77d9..d6a50cc9ef7 100644
--- a/xlators/features/changelog/src/changelog-encoders.h
+++ b/xlators/features/changelog/src/changelog-encoders.h
@@ -33,11 +33,15 @@
size_t
entry_fn (void *data, char *buffer, gf_boolean_t encode);
size_t
+del_entry_fn (void *data, char *buffer, gf_boolean_t encode);
+size_t
fop_fn (void *data, char *buffer, gf_boolean_t encode);
size_t
number_fn (void *data, char *buffer, gf_boolean_t encode);
void
entry_free_fn (void *data);
+void
+del_entry_free_fn (void *data);
int
changelog_encode_binary (xlator_t *, changelog_log_data_t *);
int
diff --git a/xlators/features/changelog/src/changelog-helpers.c b/xlators/features/changelog/src/changelog-helpers.c
index 585214df635..8dae5efa454 100644
--- a/xlators/features/changelog/src/changelog-helpers.c
+++ b/xlators/features/changelog/src/changelog-helpers.c
@@ -1735,3 +1735,88 @@ err:
inode_unref (parent);
return -1;
}
+
+/*
+ * resolve_pargfid_to_path:
+ * It converts given pargfid to path by doing recursive readlinks at the
+ * backend. If bname is given, it suffixes bname to pargfid to form the
+ * complete path else it doesn't. It allocates memory for the path and is
+ * caller's responsibility to free the same. If bname is NULL and pargfid
+ * is ROOT, then it returns "."
+ */
+
+int
+resolve_pargfid_to_path (xlator_t *this, uuid_t pargfid,
+ char **path, char *bname)
+{
+ char *linkname = NULL;
+ char *dir_handle = NULL;
+ char *pgfidstr = NULL;
+ char *saveptr = NULL;
+ ssize_t len = 0;
+ int ret = 0;
+ uuid_t tmp_gfid = {0, };
+ changelog_priv_t *priv = NULL;
+ char gpath[PATH_MAX] = {0,};
+ char result[PATH_MAX] = {0,};
+ char *dir_name = NULL;
+ char pre_dir_name[PATH_MAX] = {0,};
+
+ GF_ASSERT (this);
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ if (!path || gf_uuid_is_null (pargfid)) {
+ ret = -1;
+ goto out;
+ }
+
+ if (__is_root_gfid (pargfid)) {
+ if (bname)
+ *path = gf_strdup (bname);
+ else
+ *path = gf_strdup (".");
+ return ret;
+ }
+
+ dir_handle = alloca (PATH_MAX);
+ linkname = alloca (PATH_MAX);
+ (void) snprintf (gpath, PATH_MAX, "%s/.glusterfs/",
+ priv->changelog_brick);
+
+ while (!(__is_root_gfid (pargfid))) {
+ snprintf (dir_handle, PATH_MAX, "%s/%02x/%02x/%s", gpath,
+ pargfid[0], pargfid[1], uuid_utoa (pargfid));
+
+ len = readlink (dir_handle, linkname, PATH_MAX);
+ if (len < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "could not read the "
+ "link from the gfid handle %s (%s)", dir_handle,
+ strerror (errno));
+ ret = -1;
+ goto out;
+ }
+
+ linkname[len] = '\0';
+
+ pgfidstr = strtok_r (linkname + strlen("../../00/00/"), "/",
+ &saveptr);
+ dir_name = strtok_r (NULL, "/", &saveptr);
+
+ strncpy (result, dir_name, PATH_MAX);
+ strncat (result, "/", 1);
+ strncat (result, pre_dir_name, PATH_MAX);
+ strncpy (pre_dir_name, result, PATH_MAX);
+
+ gf_uuid_parse (pgfidstr, tmp_gfid);
+ gf_uuid_copy (pargfid, tmp_gfid);
+ }
+
+ if (bname)
+ strncat (result, bname, PATH_MAX);
+
+ *path = gf_strdup (result);
+
+out:
+ return ret;
+}
diff --git a/xlators/features/changelog/src/changelog-helpers.h b/xlators/features/changelog/src/changelog-helpers.h
index b552c308e0f..ccfbf9113d8 100644
--- a/xlators/features/changelog/src/changelog-helpers.h
+++ b/xlators/features/changelog/src/changelog-helpers.h
@@ -306,6 +306,9 @@ struct changelog_priv {
pthread_t *ev_dispatcher;
changelog_clnt_t connections;
+
+ /* glusterfind dependency to capture paths on deleted entries*/
+ gf_boolean_t capture_del_path;
};
struct changelog_local {
@@ -349,6 +352,7 @@ typedef enum {
struct changelog_entry_fields {
uuid_t cef_uuid;
char *cef_bname;
+ char *cef_path;
};
typedef struct {
@@ -497,6 +501,8 @@ changelog_dispatch_event (xlator_t *, changelog_priv_t *, changelog_event_t *);
changelog_inode_ctx_t *
__changelog_inode_ctx_get (xlator_t *, inode_t *, unsigned long **,
unsigned long *, changelog_log_type);
+int
+resolve_pargfid_to_path (xlator_t *this, uuid_t gfid, char **path, char *bname);
/* macros */
@@ -566,6 +572,26 @@ __changelog_inode_ctx_get (xlator_t *, inode_t *, unsigned long **,
xlen += (UUID_CANONICAL_FORM_LEN + strlen (bname)); \
} while (0)
+#define CHANGELOG_FILL_ENTRY_DIR_PATH(co, pargfid, bname, converter, \
+ del_freefn, xlen, label, capture_del) \
+ do { \
+ co->co_convert = converter; \
+ co->co_free = del_freefn; \
+ co->co_type = CHANGELOG_OPT_REC_ENTRY; \
+ gf_uuid_copy (co->co_entry.cef_uuid, pargfid); \
+ co->co_entry.cef_bname = gf_strdup(bname); \
+ if (!co->co_entry.cef_bname) \
+ goto label; \
+ xlen += (UUID_CANONICAL_FORM_LEN + strlen (bname)); \
+ if (!capture_del || resolve_pargfid_to_path (this, pargfid, \
+ &(co->co_entry.cef_path), co->co_entry.cef_bname)) { \
+ co->co_entry.cef_path = gf_strdup ("\0"); \
+ xlen += 1; \
+ } else { \
+ xlen += (strlen (co->co_entry.cef_path)); \
+ } \
+ } while (0)
+
#define CHANGELOG_INIT(this, local, inode, gfid, xrec) \
local = changelog_local_init (this, inode, gfid, xrec, _gf_false)
diff --git a/xlators/features/changelog/src/changelog-misc.h b/xlators/features/changelog/src/changelog-misc.h
index 0de0edd9516..acec6f675ac 100644
--- a/xlators/features/changelog/src/changelog-misc.h
+++ b/xlators/features/changelog/src/changelog-misc.h
@@ -23,7 +23,7 @@
#define HTIME_INITIAL_VALUE "0:0"
#define CHANGELOG_VERSION_MAJOR 1
-#define CHANGELOG_VERSION_MINOR 1
+#define CHANGELOG_VERSION_MINOR 2
#define CHANGELOG_UNIX_SOCK DEFAULT_VAR_RUN_DIRECTORY"/changelog-%s.sock"
#define CHANGELOG_TMP_UNIX_SOCK DEFAULT_VAR_RUN_DIRECTORY"/.%s%lu.sock"
diff --git a/xlators/features/changelog/src/changelog.c b/xlators/features/changelog/src/changelog.c
index 7429fc5e891..53c0cf85728 100644
--- a/xlators/features/changelog/src/changelog.c
+++ b/xlators/features/changelog/src/changelog.c
@@ -110,8 +110,15 @@ changelog_rmdir (call_frame_t *frame, xlator_t *this,
CHANGLOG_FILL_FOP_NUMBER (co, frame->root->op, fop_fn, xtra_len);
co++;
- CHANGELOG_FILL_ENTRY (co, loc->pargfid, loc->name,
- entry_fn, entry_free_fn, xtra_len, wind);
+ if (priv->capture_del_path) {
+ CHANGELOG_FILL_ENTRY_DIR_PATH (co, loc->pargfid, loc->name,
+ del_entry_fn, del_entry_free_fn,
+ xtra_len, wind, _gf_true);
+ } else {
+ CHANGELOG_FILL_ENTRY_DIR_PATH (co, loc->pargfid, loc->name,
+ del_entry_fn, del_entry_free_fn,
+ xtra_len, wind, _gf_false);
+ }
changelog_set_usable_record_and_length (frame->local, xtra_len, 2);
@@ -227,8 +234,15 @@ changelog_unlink (call_frame_t *frame, xlator_t *this,
CHANGLOG_FILL_FOP_NUMBER (co, frame->root->op, fop_fn, xtra_len);
co++;
- CHANGELOG_FILL_ENTRY (co, loc->pargfid, loc->name,
- entry_fn, entry_free_fn, xtra_len, wind);
+ if (priv->capture_del_path) {
+ CHANGELOG_FILL_ENTRY_DIR_PATH (co, loc->pargfid, loc->name,
+ del_entry_fn, del_entry_free_fn,
+ xtra_len, wind, _gf_true);
+ } else {
+ CHANGELOG_FILL_ENTRY_DIR_PATH (co, loc->pargfid, loc->name,
+ del_entry_fn, del_entry_free_fn,
+ xtra_len, wind, _gf_false);
+ }
changelog_set_usable_record_and_length (frame->local, xtra_len, 2);
@@ -2339,6 +2353,9 @@ reconfigure (xlator_t *this, dict_t *options)
timeout, options, time, out);
changelog_assign_barrier_timeout (priv, timeout);
+ GF_OPTION_RECONF ("capture-del-path", priv->capture_del_path, options,
+ bool, out);
+
if (active_now || active_earlier) {
ret = changelog_fill_rollover_data (&cld, !active_now);
if (ret)
@@ -2443,6 +2460,8 @@ changelog_init_options (xlator_t *this, changelog_priv_t *priv)
goto dealloc_2;
GF_OPTION_INIT ("changelog", priv->active, bool, dealloc_2);
+ GF_OPTION_INIT ("capture-del-path", priv->capture_del_path,
+ bool, dealloc_2);
GF_OPTION_INIT ("op-mode", tmp, str, dealloc_2);
changelog_assign_opmode (priv, tmp);
@@ -2719,6 +2738,11 @@ struct volume_options options[] = {
"operations are no longer blocked and previously "
"blocked fops are allowed to go through"
},
+ {.key = {"capture-del-path"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .description = "enable/disable capturing paths of deleted entries"
+ },
{.key = {NULL}
},
};