summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/glusterfs.h4
-rwxr-xr-xtests/bugs/bug-990028.t156
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-quota.c1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c51
-rw-r--r--xlators/storage/posix/src/posix-handle.c162
-rw-r--r--xlators/storage/posix/src/posix-handle.h96
-rw-r--r--xlators/storage/posix/src/posix-helpers.c87
-rw-r--r--xlators/storage/posix/src/posix.c759
-rw-r--r--xlators/storage/posix/src/posix.h11
9 files changed, 1156 insertions, 171 deletions
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index d8c7060f7ef..525d6909a59 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -101,10 +101,14 @@
#define GF_XATTR_LINKINFO_KEY "trusted.distribute.linkinfo"
#define GFID_XATTR_KEY "trusted.gfid"
+#define PGFID_XATTR_KEY_PREFIX "trusted.pgfid."
#define VIRTUAL_GFID_XATTR_KEY_STR "glusterfs.gfid.string"
#define VIRTUAL_GFID_XATTR_KEY "glusterfs.gfid"
#define UUID_CANONICAL_FORM_LEN 36
+#define GET_ANCESTRY_PATH_KEY "glusterfs.ancestry.path"
+#define GET_ANCESTRY_DENTRY_KEY "glusterfs.ancestry.dentry"
+
#define GLUSTERFS_INTERNAL_FOP_KEY "glusterfs-internal-fop"
#define ZR_FILE_CONTENT_STR "glusterfs.file."
diff --git a/tests/bugs/bug-990028.t b/tests/bugs/bug-990028.t
new file mode 100755
index 00000000000..ece7235cd96
--- /dev/null
+++ b/tests/bugs/bug-990028.t
@@ -0,0 +1,156 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../fileio.rc
+
+cleanup;
+
+TESTS_EXPECTED_IN_LOOP=153
+
+function __init()
+{
+ TEST glusterd
+ TEST pidof glusterd
+ TEST $CLI volume info;
+
+ TEST $CLI volume create $V0 $H0:$B0/brick
+
+ EXPECT 'Created' volinfo_field $V0 'Status';
+
+ TEST $CLI volume start $V0
+
+ TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0
+
+ TEST $CLI volume quota $V0 enable
+ sleep 15
+}
+
+#CASE-1
+#checking pgfid under same directory
+function links_in_same_directory()
+{
+ # create a file file1
+ TEST touch $M0/file1
+
+ # create 50 hardlinks for file1
+ for i in `seq 2 50`; do
+ TEST_IN_LOOP ln $M0/file1 $M0/file$i
+ done
+
+ # store the pgfid of file1 in PGFID_FILE1 [should be 50 now (0x000000032)]
+ PGFID_FILE1=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/file1 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'`
+
+ # compare the pgfid(link value ) of each hard links are equal or not
+ for i in `seq 2 50`; do
+ TEMP=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/file$i 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'`
+ TEST_IN_LOOP [ $PGFID_FILE1 = $TEMP ]
+ done
+
+ # check if no of links value is 50 or not
+ TEST [ $PGFID_FILE1 = "0x00000032" ]
+
+ # unlink file 2 to 50
+ for i in `seq 2 50`; do
+ TEST_IN_LOOP unlink $M0/file$i;
+ done
+
+ # now check if pgfid value is 1 or not
+ PGFID_FILE1=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/file1 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'`;
+
+ TEST [ $PGFID_FILE1 = "0x00000001" ]
+
+ TEST rm -f $M0/*
+}
+
+##checking pgfid under diff directories
+function links_across_directories()
+{
+ TEST mkdir $M0/dir1 $M0/dir2;
+
+ # create a file in dir1
+ TEST touch $M0/dir1/file1;
+
+ # create hard link for file1 in dir2
+ TEST ln $M0/dir1/file1 $M0/dir2/file2;
+
+ #first check is to find whether there are two pgfids or not
+ LINES=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | wc -l`
+ TEST [ $LINES = 2 ]
+
+ for i in $(seq 1 2); do
+ HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir$i/file$i 2>&1 | grep "trusted.pgfid" | cut -d$'\n' -f$i | cut -d'=' -f2`
+ TEST_IN_LOOP [ $HL = "0x00000001" ]
+ done
+
+ #now unlink file2 and check the pgfid of file1
+ #1. no. of pgfid should be one
+ #2. no. of hard link should be one
+ TEST unlink $M0/dir2/file2
+
+ LINES=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | wc -l`
+ TEST [ $LINES == 1 ]
+
+ #next to check is to whether they contain hard link value of one or not
+ HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`
+ TEST [ $HL = "0x00000001" ]
+
+ #rename file under same directory
+
+ TEST touch $M0/r_file1
+ PGFID_rfile1=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file1 2>&1 | grep "trusted.pgfid"`
+
+ #cross check whether hard link count is one
+ HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file1 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`
+
+ TEST [ $HL = "0x00000001" ]
+
+ #now rename the file to r_file1
+ TEST mv $M0/r_file1 $M0/r_file2
+
+ #now check the pgfid hard link count is still one or not
+ HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file2 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`
+
+ TEST [ $HL = "0x00000001" ]
+
+ #now move the file to a different directory where it has no hard link and check
+ TEST mkdir $M0/dir3;
+ TEST mv $M0/r_file2 $M0/dir3;
+
+ #now check the pgfid has changed or not and hard limit is one or not
+ PGFID_newDir=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir3/r_file2 2>&1 | grep "trusted.pgfid"`
+
+ #now the older pgfid and new pgfid shouldn't match
+ TEST [ $PGFID_rfile1 != $PGFID_newDir ]
+
+ HL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir3/r_file2 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`
+ TEST [ $HL = "0x00000001" ]
+
+ TEST touch $M0/dir1/rl_file_1
+ ln $M0/dir1/rl_file_1 $M0/dir2/rl_file_2
+ mv $M0/dir1/rl_file_1 $M0/dir2
+
+ #now the there should be just one pgfid for both files
+ for i in $(seq 1 2); do
+ NL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_$i 2>&1 | grep "trusted.pgfid"|wc -l `
+ TEST_IN_LOOP [ $HL = "0x00000001" ]
+ done
+
+ #now pgfid of both files should match
+ P_rl_file_1=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_1 2>&1 | grep "trusted.pgfid"`
+ P_rl_file_2=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_2 2>&1 | grep "trusted.pgfid"`
+ TEST [ $P_rl_file_1 = $P_rl_file_2 ]
+
+ #now the no of hard link should be two for both rl_file_1 and rl_file_2
+ for i in $(seq 1 2); do
+ HL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_$i 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`
+ TEST_IN_LOOP [ $HL = "0x00000002" ]
+ done
+
+ TEST rm -rf $M0/*
+}
+
+__init;
+links_in_same_directory;
+links_across_directories;
+
+cleanup
diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c
index 31826719947..cef2baf599c 100644
--- a/xlators/mgmt/glusterd/src/glusterd-quota.c
+++ b/xlators/mgmt/glusterd/src/glusterd-quota.c
@@ -260,6 +260,7 @@ glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname)
runner_add_args (&runner, SBIN_DIR"/glusterfs",
"-s", "localhost",
"--volfile-id", volname,
+ "--use-readdirp=no",
"-l", DEFAULT_LOG_FILE_DIRECTORY"/quota-crawl.log",
mountdir, NULL);
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 0de71a49afe..da8ace953cf 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -1404,25 +1404,27 @@ static int
server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
dict_t *set_dict, void *param)
{
- char *volname = NULL;
- char *path = NULL;
- int pump = 0;
- xlator_t *xl = NULL;
- xlator_t *txl = NULL;
- xlator_t *rbxl = NULL;
- char transt[16] = {0,};
- char *ptranst = NULL;
- char volume_id[64] = {0,};
- char tstamp_file[PATH_MAX] = {0,};
- int ret = 0;
- char *xlator = NULL;
- char *loglevel = NULL;
- char *username = NULL;
- char *password = NULL;
- char index_basepath[PATH_MAX] = {0};
- char key[1024] = {0};
- glusterd_brickinfo_t *brickinfo = NULL;
- char changelog_basepath[PATH_MAX] = {0,};
+ char *volname = NULL;
+ char *path = NULL;
+ int pump = 0;
+ xlator_t *xl = NULL;
+ xlator_t *txl = NULL;
+ xlator_t *rbxl = NULL;
+ char transt[16] = {0,};
+ char *ptranst = NULL;
+ char volume_id[64] = {0,};
+ char tstamp_file[PATH_MAX] = {0,};
+ int ret = 0;
+ char *xlator = NULL;
+ char *loglevel = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ char index_basepath[PATH_MAX] = {0};
+ char key[1024] = {0};
+ glusterd_brickinfo_t *brickinfo = NULL;
+ char changelog_basepath[PATH_MAX] = {0,};
+ gf_boolean_t quota_enabled = _gf_true;
+ char *value = NULL;
brickinfo = param;
path = brickinfo->path;
@@ -1441,6 +1443,13 @@ server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
}
}
+ ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_QUOTA, &value);
+ if (value) {
+ ret = gf_string2boolean (value, &quota_enabled);
+ if (ret)
+ goto out;
+ }
+
xl = volgen_graph_add (graph, "storage/posix", volname);
if (!xl)
return -1;
@@ -1454,6 +1463,10 @@ server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
if (ret)
return -1;
+ if (quota_enabled)
+ xlator_set_option (xl, "update-link-count-parent",
+ value);
+
ret = check_and_add_debug_xl (graph, set_dict, volname,
"posix");
if (ret)
diff --git a/xlators/storage/posix/src/posix-handle.c b/xlators/storage/posix/src/posix-handle.c
index 219a582c9f7..1d8e986314f 100644
--- a/xlators/storage/posix/src/posix-handle.c
+++ b/xlators/storage/posix/src/posix-handle.c
@@ -26,13 +26,167 @@
#include "xlator.h"
#include "syscall.h"
+inode_t *
+posix_resolve (xlator_t *this, inode_table_t *itable, inode_t *parent,
+ char *bname, struct iatt *iabuf)
+{
+ inode_t *inode = NULL, *linked_inode = NULL;
+ int ret = -1;
+
+ ret = posix_istat (this, parent->gfid, bname, iabuf);
+ if (ret < 0)
+ goto out;
+
+ inode = inode_find (itable, iabuf->ia_gfid);
+ if (inode == NULL) {
+ inode = inode_new (itable);
+ }
+
+ linked_inode = inode_link (inode, parent, bname, iabuf);
+
+ inode_unref (inode);
+
+out:
+ return linked_inode;
+}
+
+int
+posix_make_ancestral_node (const char *priv_base_path, char *path, int pathsize,
+ gf_dirent_t *head,
+ char *dir_name, struct iatt *iabuf, inode_t *inode,
+ int type, dict_t *xdata)
+{
+ gf_dirent_t *entry = NULL;
+ char real_path[PATH_MAX + 1] = {0, }, len = 0;
+ loc_t loc = {0, };
+ int ret = -1;
+
+ len = strlen (path) + strlen (dir_name) + 1;
+ if (len > pathsize) {
+ goto out;
+ }
+
+ strcat (path, dir_name);
+
+ if (type & POSIX_ANCESTRY_DENTRY) {
+ entry = gf_dirent_for_name (dir_name);
+ if (!entry) {
+ gf_log (THIS->name, GF_LOG_ERROR,
+ "could not create gf_dirent for entry %s: (%s)",
+ dir_name, strerror (errno));
+ goto out;
+ }
+
+ entry->d_stat = *iabuf;
+ entry->inode = inode_ref (inode);
+
+ list_add_tail (&entry->list, &head->list);
+ strcpy (real_path, priv_base_path);
+ strcat (real_path, "/");
+ strcat (real_path, path);
+ loc.inode = inode_ref (inode);
+ uuid_copy (loc.gfid, inode->gfid);
+
+ entry->dict = posix_lookup_xattr_fill (THIS, real_path, &loc,
+ xdata, iabuf);
+ loc_wipe (&loc);
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+int
+posix_make_ancestryfromgfid (xlator_t *this, char *path, int pathsize,
+ gf_dirent_t *head, int type, uuid_t gfid,
+ const size_t handle_size,
+ const char *priv_base_path, inode_table_t *itable,
+ inode_t **parent, dict_t *xdata)
+{
+ char *linkname = NULL; /* "../../<gfid[0]>/<gfid[1]/"
+ "<gfidstr>/<NAME_MAX>" */
+ char *dir_handle = NULL;
+ char *dir_name = NULL;
+ char *pgfidstr = NULL;
+ char *saveptr = NULL;
+ ssize_t len = 0;
+ inode_t *inode = NULL;
+ struct iatt iabuf = {0, };
+ int ret = -1;
+ uuid_t tmp_gfid = {0, };
+
+ if (!path || !parent || !priv_base_path || uuid_is_null (gfid)) {
+ goto out;
+ }
+
+ if (__is_root_gfid (gfid)) {
+ if (parent) {
+ if (*parent) {
+ inode_unref (*parent);
+ }
+
+ *parent = inode_ref (itable->root);
+ }
+
+ inode = itable->root;
+
+ memset (&iabuf, 0, sizeof (iabuf));
+ uuid_copy (iabuf.ia_gfid, inode->gfid);
+ iabuf.ia_type = inode->ia_type;
+
+ ret = posix_make_ancestral_node (priv_base_path, path, pathsize,
+ head, "/", &iabuf, inode, type,
+ xdata);
+ return ret;
+ }
+
+ dir_handle = alloca (handle_size);
+ linkname = alloca (PATH_MAX);
+ snprintf (dir_handle, handle_size, "%s/%s/%02x/%02x/%s",
+ priv_base_path, HANDLE_PFX, gfid[0], gfid[1],
+ uuid_utoa (gfid));
+
+ 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));
+ goto out;
+ }
+
+ linkname[len] = '\0';
+
+ pgfidstr = strtok_r (linkname + SLEN("../../00/00/"), "/", &saveptr);
+ dir_name = strtok_r (NULL, "/", &saveptr);
+ strcat (dir_name, "/");
-#define HANDLE_PFX ".glusterfs"
-#define TRASH_DIR "landfill"
+ uuid_parse (pgfidstr, tmp_gfid);
+
+ ret = posix_make_ancestryfromgfid (this, path, pathsize, head, type,
+ tmp_gfid, handle_size,
+ priv_base_path, itable, parent,
+ xdata);
+ if (ret < 0) {
+ goto out;
+ }
-#define UUID0_STR "00000000-0000-0000-0000-000000000000"
-#define SLEN(str) (sizeof(str) - 1)
+ memset (&iabuf, 0, sizeof (iabuf));
+ inode = posix_resolve (this, itable, *parent, dir_name, &iabuf);
+
+ ret = posix_make_ancestral_node (priv_base_path, path, pathsize, head,
+ dir_name, &iabuf, inode, type, xdata);
+ if (*parent != NULL) {
+ inode_unref (*parent);
+ }
+
+ *parent = inode;
+
+out:
+ return ret;
+}
int
posix_handle_relpath (xlator_t *this, uuid_t gfid, const char *basename,
diff --git a/xlators/storage/posix/src/posix-handle.h b/xlators/storage/posix/src/posix-handle.h
index f1163b72795..8874ca2655f 100644
--- a/xlators/storage/posix/src/posix-handle.h
+++ b/xlators/storage/posix/src/posix-handle.h
@@ -17,9 +17,86 @@
#include <sys/types.h>
#include "xlator.h"
+#include "gf-dirent.h"
+#define HANDLE_PFX ".glusterfs"
+#define TRASH_DIR "landfill"
-#define LOC_HAS_ABSPATH(loc) ((loc) && (loc->path) && (loc->path[0] == '/'))
+#define UUID0_STR "00000000-0000-0000-0000-000000000000"
+#define SLEN(str) (sizeof(str) - 1)
+
+#define LOC_HAS_ABSPATH(loc) (loc && (loc->path) && (loc->path[0] == '/'))
+
+#define MAKE_PGFID_XATTR_KEY(var, prefix, pgfid) do { \
+ var = alloca (strlen (prefix) + UUID_CANONICAL_FORM_LEN + 1); \
+ strcpy (var, prefix); \
+ strcat (var, uuid_utoa (pgfid)); \
+ } while (0)
+
+#define SET_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do { \
+ value = hton32 (value); \
+ op_ret = sys_lsetxattr (path, key, &value, sizeof (value), \
+ flags); \
+ if (op_ret == -1) { \
+ op_errno = errno; \
+ gf_log (this->name, GF_LOG_WARNING, \
+ "setting xattr failed on %s: key = %s (%s)", \
+ path, key, strerror (op_errno)); \
+ goto label; \
+ } \
+ } while (0)
+
+
+#define REMOVE_PGFID_XATTR(path, key, op_ret, this, label) do { \
+ op_ret = sys_lremovexattr (path, key); \
+ if (op_ret == -1) { \
+ op_errno = errno; \
+ gf_log (this->name, GF_LOG_WARNING, "removing xattr " \
+ "failed on %s: key = %s (%s)", path, key, \
+ strerror (op_errno)); \
+ goto label; \
+ } \
+ } while (0)
+
+/* should be invoked holding a lock */
+#define LINK_MODIFY_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do { \
+ op_ret = sys_lgetxattr (path, key, &value, sizeof (value)); \
+ if (op_ret == -1) { \
+ op_errno = errno; \
+ if (op_errno == ENOATTR) { \
+ value = 1; \
+ } else { \
+ gf_log (this->name, GF_LOG_WARNING,"getting xattr " \
+ "failed on %s: key = %s (%s)", path, key, \
+ strerror (op_errno)); \
+ goto label; \
+ } \
+ } else { \
+ value = ntoh32 (value); \
+ value++; \
+ } \
+ SET_PGFID_XATTR (path, key, value, flags, op_ret, this, label); \
+ } while (0)
+
+/* should be invoked holding a lock */
+#define UNLINK_MODIFY_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do { \
+ op_ret = sys_lgetxattr (path, key, &value, sizeof (value)); \
+ if (op_ret == -1) { \
+ op_errno = errno; \
+ gf_log (this->name, GF_LOG_WARNING, "getting xattr failed on " \
+ "%s: key = %s (%s)", path, key, strerror (op_errno)); \
+ goto label; \
+ } else { \
+ value = ntoh32 (value); \
+ value--; \
+ if (value > 0) { \
+ SET_PGFID_XATTR (path, key, value, flags, op_ret, \
+ this, label); \
+ } else { \
+ REMOVE_PGFID_XATTR (path, key, op_ret, this, label); \
+ } \
+ } \
+ } while (0)
#define MAKE_REAL_PATH(var, this, path) do { \
var = alloca (strlen (path) + POSIX_BASE_PATH_LEN(this) + 2); \
@@ -27,7 +104,6 @@
strcpy (&var[POSIX_BASE_PATH_LEN(this)], path); \
} while (0)
-
#define MAKE_HANDLE_PATH(var, this, gfid, base) do { \
int __len; \
__len = posix_handle_path (this, gfid, base, NULL, 0); \
@@ -61,12 +137,12 @@
#define MAKE_INODE_HANDLE(rpath, this, loc, iatt_p) do { \
if (uuid_is_null (loc->gfid)) { \
gf_log (this->name, GF_LOG_ERROR, \
- "null gfid for path %s", loc->path); \
+ "null gfid for path %s", (loc)->path); \
break; \
} \
if (LOC_HAS_ABSPATH (loc)) { \
- MAKE_REAL_PATH (rpath, this, loc->path); \
- op_ret = posix_pstat (this, loc->gfid, rpath, iatt_p); \
+ MAKE_REAL_PATH (rpath, this, (loc)->path); \
+ op_ret = posix_pstat (this, (loc)->gfid, rpath, iatt_p); \
break; \
} \
errno = 0; \
@@ -107,10 +183,20 @@
} while (0)
+#define POSIX_ANCESTRY_PATH (1 << 0)
+#define POSIX_ANCESTRY_DENTRY (1 << 1)
int
posix_handle_path (xlator_t *this, uuid_t gfid, const char *basename, char *buf,
size_t len);
+
+int
+posix_make_ancestryfromgfid (xlator_t *this, char *path, int pathsize,
+ gf_dirent_t *head, int type, uuid_t gfid,
+ const size_t handle_size,
+ const char *priv_base_path,
+ inode_table_t *table, inode_t **parent,
+ dict_t *xdata);
int
posix_handle_path_safe (xlator_t *this, uuid_t gfid, const char *basename,
char *buf, size_t len);
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
index e295f8850b4..4db15bf571c 100644
--- a/xlators/storage/posix/src/posix-helpers.c
+++ b/xlators/storage/posix/src/posix-helpers.c
@@ -102,14 +102,54 @@ out:
}
static int
+_posix_xattr_get_set_from_backend (posix_xattr_filler_t *filler, char *key)
+{
+ ssize_t xattr_size = -1;
+ int ret = 0;
+ char *value = NULL;
+
+ xattr_size = sys_lgetxattr (filler->real_path, key, NULL, 0);
+
+ if (xattr_size > 0) {
+ value = GF_CALLOC (1, xattr_size + 1,
+ gf_posix_mt_char);
+ if (!value)
+ goto out;
+
+ xattr_size = sys_lgetxattr (filler->real_path, key, value,
+ xattr_size);
+ if (xattr_size <= 0) {
+ gf_log (filler->this->name, GF_LOG_WARNING,
+ "getxattr failed. path: %s, key: %s",
+ filler->real_path, key);
+ GF_FREE (value);
+ goto out;
+ }
+
+ value[xattr_size] = '\0';
+ ret = dict_set_bin (filler->xattr, key,
+ value, xattr_size);
+ if (ret < 0) {
+ gf_log (filler->this->name, GF_LOG_DEBUG,
+ "dict set failed. path: %s, key: %s",
+ filler->real_path, key);
+ GF_FREE (value);
+ goto out;
+ }
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+
+static int
_posix_xattr_get_set (dict_t *xattr_req,
char *key,
data_t *data,
void *xattrargs)
{
posix_xattr_filler_t *filler = xattrargs;
- char *value = NULL;
- ssize_t xattr_size = -1;
int ret = -1;
char *databuf = NULL;
int _fd = -1;
@@ -183,35 +223,24 @@ _posix_xattr_get_set (dict_t *xattr_req,
"Failed to set dictionary value for %s",
key);
}
- } else {
- xattr_size = sys_lgetxattr (filler->real_path, key, NULL, 0);
-
- if (xattr_size > 0) {
- value = GF_CALLOC (1, xattr_size + 1,
- gf_posix_mt_char);
- if (!value)
- return -1;
-
- xattr_size = sys_lgetxattr (filler->real_path, key, value,
- xattr_size);
- if (xattr_size <= 0) {
- gf_log (filler->this->name, GF_LOG_WARNING,
- "getxattr failed. path: %s, key: %s",
- filler->real_path, key);
- GF_FREE (value);
- return -1;
- }
+ } else if (!strcmp (key, GET_ANCESTRY_PATH_KEY)) {
+ char *path = NULL;
+ ret = posix_get_ancestry (filler->this, filler->loc->inode,
+ NULL, &path, POSIX_ANCESTRY_PATH,
+ &filler->op_errno, xattr_req);
+ if (ret < 0) {
+ goto out;
+ }
- value[xattr_size] = '\0';
- ret = dict_set_bin (filler->xattr, key,
- value, xattr_size);
- if (ret < 0) {
- gf_log (filler->this->name, GF_LOG_DEBUG,
- "dict set failed. path: %s, key: %s",
- filler->real_path, key);
- GF_FREE (value);
- }
+ ret = dict_set_dynstr (filler->xattr, GET_ANCESTRY_PATH_KEY,
+ path);
+ if (ret < 0) {
+ GF_FREE (path);
+ goto out;
}
+
+ } else {
+ ret = _posix_xattr_get_set_from_backend (filler, key);
}
out:
return 0;
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index 1a344acbb5a..65b52a07cd5 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -79,7 +79,6 @@ extern char *marker_xattrs[];
#define SET_TO_OLD_FS_ID()
#endif
-
int
posix_forget (xlator_t *this, inode_t *inode)
{
@@ -105,15 +104,18 @@ posix_lookup (call_frame_t *frame, xlator_t *this,
char * par_path = NULL;
struct iatt postparent = {0,};
int32_t gfidless = 0;
+ struct posix_private *priv = 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) &&
- (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {
+ if (__is_root_gfid (loc->pargfid) && loc->name
+ && (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {
gf_log (this->name, GF_LOG_WARNING,
"Lookup issued on %s, which is not permitted",
GF_HIDDEN_PATH);
@@ -124,7 +126,7 @@ posix_lookup (call_frame_t *frame, xlator_t *this,
op_ret = dict_get_int32 (xdata, GF_GFIDLESS_LOOKUP, &gfidless);
op_ret = -1;
- if (uuid_is_null (loc->pargfid)) {
+ if (uuid_is_null (loc->pargfid) || (loc->name == NULL)) {
/* nameless lookup */
MAKE_INODE_HANDLE (real_path, this, loc, &buf);
} else {
@@ -1029,18 +1031,20 @@ 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, };
- char was_present = 1;
- struct posix_private *priv = NULL;
- gid_t gid = 0;
- struct iatt preparent = {0,};
- struct iatt postparent = {0,};
- void * uuid_req = NULL;
+ 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, };
+ char was_present = 1;
+ 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;
DECLARE_OLD_FS_ID_VAR;
@@ -1143,6 +1147,16 @@ post_op:
strerror (errno));
}
+ 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);
+ }
+
+ignore:
op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -1271,7 +1285,6 @@ posix_mkdir (call_frame_t *frame, xlator_t *this,
goto out;
}
#endif
-
op_ret = posix_acl_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -1325,15 +1338,17 @@ 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 posix_private *priv = NULL;
- struct iatt preparent = {0,};
- struct iatt postparent = {0,};
+ 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 posix_private *priv = NULL;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
DECLARE_OLD_FS_ID_VAR;
@@ -1371,6 +1386,26 @@ posix_unlink (call_frame_t *frame, xlator_t *this,
}
}
+ if (priv->update_pgfid_nlinks && (stbuf.ia_nlink > 1)) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ loc->pargfid);
+ LOCK (&loc->inode->lock);
+ {
+ UNLINK_MODIFY_PGFID_XATTR (real_path, pgfid_xattr_key,
+ nlink_samepgfid, 0, op_ret,
+ this, unlock);
+ }
+ unlock:
+ UNLOCK (&loc->inode->lock);
+
+ if (op_ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "modification of "
+ "parent gfid xattr failed (path:%s gfid:%s)",
+ real_path, uuid_utoa (loc->inode->gfid));
+ goto out;
+ }
+ }
+
op_ret = sys_unlink (real_path);
if (op_ret == -1) {
op_errno = errno;
@@ -1512,16 +1547,18 @@ 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;
- char was_present = 1;
- struct iatt preparent = {0,};
- struct iatt postparent = {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;
+ char was_present = 1;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
DECLARE_OLD_FS_ID_VAR;
@@ -1582,7 +1619,6 @@ posix_symlink (call_frame_t *frame, xlator_t *this,
goto out;
}
#endif
-
op_ret = posix_acl_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -1590,6 +1626,14 @@ posix_symlink (call_frame_t *frame, xlator_t *this,
strerror (errno));
}
+ 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);
+ }
+ignore:
op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -1636,24 +1680,26 @@ 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, };
+ 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;
+ uuid_t victim = {0};
+ int was_dir = 0;
+ int nlink = 0;
+ char *pgfid_xattr_key = NULL;
+ int32_t nlink_samepgfid = 0;
DECLARE_OLD_FS_ID_VAR;
@@ -1718,17 +1764,64 @@ posix_rename (call_frame_t *frame, xlator_t *this,
goto out;
}
- if (IA_ISDIR (oldloc->inode->ia_type)) {
+ if (IA_ISDIR (oldloc->inode->ia_type))
posix_handle_unset (this, oldloc->inode->gfid, NULL);
+
+ LOCK (&oldloc->inode->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);
+ }
+
+ op_ret = sys_rename (real_oldpath, real_newpath);
+ if (op_ret == -1) {
+ op_errno = errno;
+ gf_log (this->name,
+ (op_errno == ENOTEMPTY ? GF_LOG_DEBUG
+ : GF_LOG_ERROR),
+ "rename of %s to %s failed: %s",
+ real_oldpath, real_newpath,
+ strerror (op_errno));
+
+ 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 (!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);
+ }
}
+unlock:
+ UNLOCK (&oldloc->inode->lock);
- op_ret = sys_rename (real_oldpath, real_newpath);
- if (op_ret == -1) {
- op_errno = errno;
- gf_log (this->name,
- (op_errno == ENOTEMPTY ? GF_LOG_DEBUG : GF_LOG_ERROR),
- "rename of %s to %s failed: %s",
- real_oldpath, real_newpath, strerror (op_errno));
+ if (op_ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "modification of "
+ "parent gfid xattr failed (gfid:%s)",
+ uuid_utoa (oldloc->inode->gfid));
goto out;
}
@@ -1792,16 +1885,18 @@ 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;
- char was_present = 1;
- struct iatt preparent = {0,};
- struct iatt postparent = {0,};
+ 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;
+ char was_present = 1;
+ struct iatt preparent = {0,};
+ struct iatt postparent = {0,};
+ int32_t nlink_samepgfid = 0;
+ char *pgfid_xattr_key = NULL;
DECLARE_OLD_FS_ID_VAR;
@@ -1866,6 +1961,27 @@ posix_link (call_frame_t *frame, xlator_t *this,
goto out;
}
+ if (priv->update_pgfid_nlinks) {
+ MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX,
+ newloc->pargfid);
+
+ LOCK (&newloc->inode->lock);
+ {
+ LINK_MODIFY_PGFID_XATTR (real_newpath, pgfid_xattr_key,
+ nlink_samepgfid, 0, op_ret,
+ this, unlock);
+ }
+ unlock:
+ UNLOCK (&newloc->inode->lock);
+
+ if (op_ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "modification of "
+ "parent gfid xattr failed (path:%s gfid:%s)",
+ real_newpath, uuid_utoa (newloc->inode->gfid));
+ goto out;
+ }
+ }
+
op_ret = 0;
out:
@@ -1932,7 +2048,6 @@ posix_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,
}
op_ret = 0;
-
out:
SET_TO_OLD_FS_ID ();
@@ -1948,20 +2063,23 @@ 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,};
+ 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;
DECLARE_OLD_FS_ID_VAR;
@@ -2037,7 +2155,6 @@ posix_create (call_frame_t *frame, xlator_t *this,
real_path, strerror (op_errno));
}
#endif
-
op_ret = posix_acl_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -2045,6 +2162,14 @@ posix_create (call_frame_t *frame, xlator_t *this,
strerror (errno));
}
+ 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);
+ }
+ignore:
op_ret = posix_entry_create_xattr_set (this, real_path, xdata);
if (op_ret) {
gf_log (this->name, GF_LOG_ERROR,
@@ -2876,6 +3001,335 @@ posix_xattr_get_real_filename (call_frame_t *frame, xlator_t *this, loc_t *loc,
return ret;
}
+int
+posix_get_ancestry_directory (xlator_t *this, inode_t *leaf_inode,
+ gf_dirent_t *head, char **path, int type,
+ int32_t *op_errno, dict_t *xdata)
+{
+ ssize_t handle_size = 0;
+ struct posix_private *priv = NULL;
+ char dirpath[PATH_MAX+1] = {0,};
+ inode_t *inode = NULL;
+ int ret = -1;
+
+ priv = this->private;
+
+ handle_size = POSIX_GFID_HANDLE_SIZE(priv->base_path_length);
+
+ ret = posix_make_ancestryfromgfid (this, dirpath, PATH_MAX + 1, head,
+ type | POSIX_ANCESTRY_PATH,
+ leaf_inode->gfid,
+ handle_size, priv->base_path,
+ leaf_inode->table, &inode, xdata);
+ if (ret < 0)
+ goto out;
+
+
+ /* there is already a reference in loc->inode */
+ inode_unref (inode);
+
+ if ((type & POSIX_ANCESTRY_PATH) && (path != NULL)) {
+ if (strcmp (dirpath, "/"))
+ dirpath[strlen (dirpath) - 1] = '\0';
+
+ *path = gf_strdup (dirpath);
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+posix_links_in_same_directory (char *dirpath, int count, inode_t *leaf_inode,
+ inode_t *parent, uint64_t ino,
+ gf_dirent_t *head, char **path,
+ int type, dict_t *xdata, int32_t *op_errno)
+{
+ DIR *dirp = NULL;
+ int op_ret = -1;
+ struct dirent *entry = NULL;
+ struct dirent *result = NULL;
+ inode_t *linked_inode = NULL;
+ gf_dirent_t *gf_entry = NULL;
+ char temppath[PATH_MAX+1] = {0,};
+ xlator_t *this = NULL;
+ struct posix_private *priv = NULL;
+ char *tempv = NULL;
+
+ this = THIS;
+
+ priv = this->private;
+
+ dirp = opendir (dirpath);
+ if (!dirp) {
+ *op_errno = errno;
+ gf_log (this->name, GF_LOG_WARNING,
+ "could not opendir %s: %s", dirpath,
+ strerror (*op_errno));
+ goto out;
+ }
+
+ entry = alloca (offsetof(struct dirent, d_name) + NAME_MAX + 1);
+ if (entry == NULL)
+ goto out;
+
+ while (count > 0) {
+ *op_errno = readdir_r (dirp, entry, &result);
+ if ((result == NULL) || *op_errno)
+ break;
+
+ if (entry->d_ino != ino)
+ continue;
+
+ linked_inode = inode_link (leaf_inode, parent,
+ entry->d_name, NULL);
+
+ GF_ASSERT (linked_inode == leaf_inode);
+ inode_unref (linked_inode);
+
+ if (type & POSIX_ANCESTRY_DENTRY) {
+ loc_t loc = {0, };
+
+ loc.inode = inode_ref (leaf_inode);
+ uuid_copy (loc.gfid, leaf_inode->gfid);
+
+ strcpy (temppath, dirpath);
+ strcat (temppath, "/");
+ strcat (temppath, entry->d_name);
+
+ gf_entry = gf_dirent_for_name (entry->d_name);
+ gf_entry->inode = inode_ref (leaf_inode);
+ gf_entry->dict
+ = posix_lookup_xattr_fill (this,
+ temppath,
+ &loc, xdata,
+ NULL);
+ list_add_tail (&gf_entry->list, &head->list);
+ loc_wipe (&loc);
+ }
+
+ if (type & POSIX_ANCESTRY_PATH) {
+ strcpy (temppath,
+ &dirpath[priv->base_path_length]);
+ strcat (temppath, "/");
+ strcat (temppath, entry->d_name);
+ if (!*path) {
+ *path = gf_strdup (temppath);
+ } else {
+ /* creating a colon separated */
+ /* list of hard links */
+ tempv = GF_REALLOC (*path, strlen (*path)
+ + 1 // ':'
+ + strlen (temppath) + 1 );
+ if (!tempv) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "realloc failed on path");
+ GF_FREE (*path);
+ op_ret = -1;
+ *op_errno = ENOMEM;
+ goto out;
+ }
+
+ *path = tempv;
+ strcat (*path, ":");
+ strcat (*path, temppath);
+ }
+ }
+
+ count--;
+ }
+
+out:
+ if (dirp) {
+ op_ret = closedir (dirp);
+ if (op_ret == -1) {
+ *op_errno = errno;
+ gf_log (this->name, GF_LOG_WARNING,
+ "closedir failed: %s",
+ strerror (*op_errno));
+ }
+ }
+
+ return op_ret;
+}
+
+int
+posix_get_ancestry_non_directory (xlator_t *this, inode_t *leaf_inode,
+ gf_dirent_t *head, char **path, int type,
+ int32_t *op_errno, dict_t *xdata)
+{
+ size_t remaining_size = 0;
+ char dirpath[PATH_MAX+1] = {0,}, *leaf_path = NULL;
+ int op_ret = -1, pathlen = -1;
+ ssize_t handle_size = 0;
+ char pgfidstr[UUID_CANONICAL_FORM_LEN+1] = {0,};
+ uuid_t pgfid = {0, };
+ int nlink_samepgfid = 0;
+ struct stat stbuf = {0,};
+ char *list = NULL;
+ int32_t list_offset = 0;
+ char key[4096] = {0,};
+ struct posix_private *priv = NULL;
+ ssize_t size = 0;
+ inode_t *parent = NULL;
+ loc_t *loc = NULL;
+
+ priv = this->private;
+
+ loc = GF_CALLOC (1, sizeof (*loc), gf_posix_mt_char);
+ if (loc == NULL) {
+ op_ret = -1;
+ *op_errno = ENOMEM;
+ goto out;
+ }
+
+ uuid_copy (loc->gfid, leaf_inode->gfid);
+
+ MAKE_INODE_HANDLE (leaf_path, this, loc, NULL);
+
+ GF_FREE (loc);
+
+ size = sys_llistxattr (leaf_path, NULL, 0);
+ if (size == -1) {
+ *op_errno = errno;
+ if ((errno == ENOTSUP) || (errno == ENOSYS)) {
+ GF_LOG_OCCASIONALLY (gf_posix_xattr_enotsup_log,
+ this->name, GF_LOG_WARNING,
+ "Extended attributes not "
+ "supported (try remounting brick"
+ " with 'user_xattr' flag)");
+
+ } else {
+ gf_log (this->name, GF_LOG_WARNING,
+ "listxattr failed on %s: %s",
+ leaf_path, strerror (*op_errno));
+
+ }
+
+ goto out;
+ }
+
+ if (size == 0) {
+ op_ret = 0;
+ goto out;
+ }
+
+ list = alloca (size + 1);
+ if (!list) {
+ *op_errno = errno;
+ goto out;
+ }
+
+ size = sys_llistxattr (leaf_path, list, size);
+ remaining_size = size;
+ list_offset = 0;
+
+ op_ret = sys_lstat (leaf_path, &stbuf);
+ if (op_ret == -1) {
+ *op_errno = errno;
+ gf_log (this->name, GF_LOG_WARNING, "lstat failed"
+ " on %s: %s", leaf_path,
+ strerror (*op_errno));
+ goto out;
+ }
+
+ while (remaining_size > 0) {
+ if (*(list + list_offset) == '\0')
+ break;
+ strcpy (key, list + list_offset);
+ if (strncmp (key, PGFID_XATTR_KEY_PREFIX,
+ strlen (PGFID_XATTR_KEY_PREFIX)) != 0)
+ goto next;
+
+ op_ret = sys_lgetxattr (leaf_path, key,
+ &nlink_samepgfid,
+ sizeof(nlink_samepgfid));
+ if (op_ret == -1) {
+ *op_errno = errno;
+ gf_log (this->name, GF_LOG_ERROR,
+ "getxattr failed on "
+ "%s: key = %s (%s)",
+ leaf_path,
+ key,
+ strerror (*op_errno));
+ goto out;
+ }
+
+ nlink_samepgfid = ntoh32 (nlink_samepgfid);
+
+ strcpy (pgfidstr, key + strlen(PGFID_XATTR_KEY_PREFIX));
+ uuid_parse (pgfidstr, pgfid);
+
+ handle_size = POSIX_GFID_HANDLE_SIZE(priv->base_path_length);
+
+ /* constructing the absolute real path of parent dir */
+ strcpy (dirpath, priv->base_path);
+ pathlen = PATH_MAX + 1 - priv->base_path_length;
+
+ op_ret = posix_make_ancestryfromgfid (this,
+ dirpath + priv->base_path_length,
+ pathlen,
+ head,
+ POSIX_ANCESTRY_PATH | POSIX_ANCESTRY_DENTRY,
+ pgfid,
+ handle_size,
+ priv->base_path,
+ leaf_inode->table,
+ &parent, xdata);
+ if (op_ret < 0) {
+ goto next;
+ }
+
+ dirpath[strlen (dirpath) - 1] = '\0';
+
+ posix_links_in_same_directory (dirpath, nlink_samepgfid,
+ leaf_inode,
+ parent, stbuf.st_ino, head,
+ path, type, xdata, op_errno);
+
+ if (parent != NULL) {
+ inode_unref (parent);
+ parent = NULL;
+ }
+
+ next:
+ remaining_size -= strlen (key) + 1;
+ list_offset += strlen (key) + 1;
+ } /* while (remaining_size > 0) */
+
+ op_ret = 0;
+
+out:
+ return op_ret;
+}
+
+int
+posix_get_ancestry (xlator_t *this, inode_t *leaf_inode,
+ gf_dirent_t *head, char **path, int type, int32_t *op_errno,
+ dict_t *xdata)
+{
+ int ret = -1;
+ struct posix_private *priv = NULL;
+
+ priv = this->private;
+
+ if (!priv->update_pgfid_nlinks)
+ goto out;
+
+ if (IA_ISDIR (leaf_inode->ia_type)) {
+ ret = posix_get_ancestry_directory (this, leaf_inode,
+ head, path, type, op_errno,
+ xdata);
+ } else {
+ ret = posix_get_ancestry_non_directory (this, leaf_inode,
+ head, path, type,
+ op_errno, xdata);
+ }
+
+out:
+ return ret;
+}
+
/**
* posix_getxattr - this function returns a dictionary with all the
* key:value pair present as xattr. used for
@@ -2885,23 +3339,23 @@ int32_t
posix_getxattr (call_frame_t *frame, xlator_t *this,
loc_t *loc, const char *name, dict_t *xdata)
{
- struct posix_private *priv = NULL;
- int32_t op_ret = -1;
- int32_t op_errno = 0;
- int32_t list_offset = 0;
- ssize_t size = 0;
- size_t remaining_size = 0;
- char key[4096] = {0,};
- char host_buf[1024] = {0,};
- char *value = NULL;
- char *list = NULL;
- char *real_path = NULL;
- dict_t *dict = NULL;
- char *file_contents = NULL;
- int ret = -1;
- char *path = NULL;
- char *rpath = NULL;
- char *dyn_rpath = NULL;
+ struct posix_private *priv = NULL;
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ char host_buf[1024] = {0,};
+ char *value = NULL;
+ char *real_path = NULL;
+ dict_t *dict = NULL;
+ char *file_contents = NULL;
+ int ret = -1;
+ char *path = NULL;
+ char *rpath = NULL;
+ char *dyn_rpath = NULL;
+ ssize_t size = 0;
+ char *list = NULL;
+ int32_t list_offset = 0;
+ size_t remaining_size = 0;
+ char key[4096] = {0,};
DECLARE_OLD_FS_ID_VAR;
@@ -3045,6 +3499,31 @@ posix_getxattr (call_frame_t *frame, xlator_t *this,
goto done;
}
+ if (loc->inode && name
+ && (strcmp (name, GET_ANCESTRY_PATH_KEY) == 0)) {
+ int type = POSIX_ANCESTRY_PATH;
+
+ op_ret = posix_get_ancestry (this, loc->inode, NULL,
+ &path, type, &op_errno,
+ xdata);
+ if (op_ret < 0) {
+ op_ret = -1;
+ op_errno = ENODATA;
+ goto out;
+ }
+
+ op_ret = dict_set_dynstr (dict, GET_ANCESTRY_PATH_KEY, path);
+ if (op_ret < 0) {
+ gf_log (this->name, GF_LOG_WARNING, "could not get "
+ "value for key (%s)", GET_ANCESTRY_PATH_KEY);
+ GF_FREE (path);
+ op_errno = -op_ret;
+ op_ret = -1;
+ }
+
+ goto done;
+ }
+
if (name) {
strcpy (key, name);
@@ -3189,8 +3668,9 @@ out:
STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict, NULL);
- if (dict)
+ if (dict) {
dict_unref (dict);
+ }
return 0;
}
@@ -4322,15 +4802,14 @@ int32_t
posix_do_readdir (call_frame_t *frame, xlator_t *this,
fd_t *fd, size_t size, off_t off, int whichop, dict_t *dict)
{
- struct posix_fd *pfd = NULL;
- DIR *dir = NULL;
- int ret = -1;
- int count = 0;
- int32_t op_ret = -1;
- int32_t op_errno = 0;
- gf_dirent_t entries;
- int32_t skip_dirs = 0;
-
+ struct posix_fd *pfd = NULL;
+ DIR *dir = NULL;
+ int ret = -1;
+ int count = 0;
+ int32_t op_ret = -1;
+ int32_t op_errno = 0;
+ gf_dirent_t entries;
+ int32_t skip_dirs = 0;
VALIDATE_OR_GOTO (frame, out);
VALIDATE_OR_GOTO (this, out);
@@ -4409,6 +4888,32 @@ int32_t
posix_readdirp (call_frame_t *frame, xlator_t *this,
fd_t *fd, size_t size, off_t off, dict_t *dict)
{
+ gf_dirent_t entries;
+ int32_t op_ret = -1, op_errno = 0;
+ gf_dirent_t *entry = NULL;
+
+
+ if ((dict != NULL) && (dict_get (dict, GET_ANCESTRY_DENTRY_KEY))) {
+ INIT_LIST_HEAD (&entries.list);
+
+ op_ret = posix_get_ancestry (this, fd->inode, &entries, NULL,
+ POSIX_ANCESTRY_DENTRY,
+ &op_errno, dict);
+ if (op_ret >= 0) {
+ op_ret = 0;
+
+ list_for_each_entry (entry, &entries.list, list) {
+ op_ret++;
+ }
+ }
+
+ STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, &entries,
+ NULL);
+
+ gf_dirent_free (&entries);
+ return 0;
+ }
+
posix_do_readdir (frame, this, fd, size, off, GF_FOP_READDIRP, dict);
return 0;
}
@@ -4635,6 +5140,9 @@ reconfigure (xlator_t *this, dict_t *options)
else
posix_aio_off (this);
+ GF_OPTION_RECONF ("update-link-count-parent", priv->update_pgfid_nlinks,
+ options, bool, out);
+
GF_OPTION_RECONF ("node-uuid-pathinfo", priv->node_uuid_pathinfo,
options, bool, out);
@@ -4912,6 +5420,24 @@ init (xlator_t *this)
"for every open)");
}
+ tmp_data = dict_get (this->options, "update-link-count-parent");
+ if (tmp_data) {
+ if (gf_string2boolean (tmp_data->data,
+ &_private->update_pgfid_nlinks) == -1) {
+ ret = -1;
+ gf_log (this->name, GF_LOG_ERROR,
+ "wrong value provided for "
+ "'update-link-count-parent'");
+ goto out;
+ }
+ if (_private->update_pgfid_nlinks)
+ gf_log (this->name, GF_LOG_DEBUG,
+ "update-link-count-parent is enabled. Thus for each "
+ "file an extended attribute representing the "
+ "number of hardlinks for that file within the "
+ "same parent directory is set.");
+ }
+
ret = dict_get_str (this->options, "glusterd-uuid", &guuid);
if (!ret) {
if (uuid_parse (guuid, _private->glusterd_uuid))
@@ -5203,5 +5729,10 @@ struct volume_options options[] = {
.description = "Num of usecs to wait for aggregating fsync"
" requests",
},
+ { .key = {"update-link-count-parent"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "false",
+ .description = "Enable placeholders for gfid to path conversion"
+ },
{ .key = {NULL} }
};
diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h
index 3121db2717e..d579bf673db 100644
--- a/xlators/storage/posix/src/posix.h
+++ b/xlators/storage/posix/src/posix.h
@@ -52,6 +52,12 @@
#define VECTOR_SIZE 64 * 1024 /* vector size 64KB*/
#define MAX_NO_VECT 1024
+
+#define POSIX_GFID_HANDLE_SIZE(base_path_len) (base_path_len + SLEN("/") \
+ + SLEN(HANDLE_PFX) + SLEN("/") \
+ + SLEN("00/") \
+ + SLEN("00/") + SLEN(UUID0_STR) + 1) /* '\0' */;
+
/**
* posix_fd - internal structure common to file and directory fd's
*/
@@ -146,6 +152,7 @@ struct posix_private {
} batch_fsync_mode;
uint32_t batch_fsync_delay_usec;
+ gf_boolean_t update_pgfid_nlinks;
/* seconds to sleep between health checks */
uint32_t health_check_interval;
@@ -205,4 +212,8 @@ __posix_fd_set_odirect (fd_t *fd, struct posix_fd *pfd, int opflags,
void posix_spawn_health_check_thread (xlator_t *this);
void *posix_fsyncer (void *);
+int
+posix_get_ancestry (xlator_t *this, inode_t *leaf_inode,
+ gf_dirent_t *head, char **path, int type, int32_t *op_errno,
+ dict_t *xdata);
#endif /* _POSIX_H */