summaryrefslogtreecommitdiffstats
path: root/xlators/storage/posix/src/posix.c
diff options
context:
space:
mode:
authorRaghavendra G <rgowdapp@redhat.com>2013-09-16 17:50:25 +0530
committerAnand Avati <avati@redhat.com>2013-11-26 10:22:40 -0800
commitd6dc8d0e9e2052818c9858f6b073a8bacc3fca88 (patch)
tree8226967de497a4ff75c5ba5e509b465322dd5fd5 /xlators/storage/posix/src/posix.c
parent1d554b179f63a5a56ae447f2a5b0044c49ae2642 (diff)
posix: placeholders for GFID to path conversion
what? ===== The following is an attempt to generate the paths of a file when only its gfid is known. To find the path of a directory, the symlink handle to the directory maintained in the ".glusterfs" backend directory is read. The symlink handle is generated using the gfid of the directory. It (handle) contains the directory's name and parent gfid, which are used to recursively construct the absolute path as seen by the user from the mount point. A similar approach cannot be used for a regular file or a symbolic link since its hardlink handle, generated using its gfid, doesn't contain its parent gfid and basename. So xattrs are set to store the parent gfids and the number of hardlinks to a file or a symlink having the same parent gfid. When an user/application requests for the paths of a regular file or a symlink with multiple hardlinks, using the parent gfids stored in the xattrs, the paths of the parent directories are generated as mentioned earlier. The base names of the hardlinks (with the same parent gfid) are determined by matching the actual backend inode numbers of each entry in the parent directory with that of the hardlink handle. Xattr is set on a regular file, link, and symbolic link as follows, Xattr name : trusted.pgfid.<pargfidstr> Xattr value : <number of hardlinks to a regular file/symlink with the same parentgfid> If a regular file, hard link, symbolic link is created then an xattr in the above format is set in the backend. how to use? =========== This functionality can be used through getxattr interface. Two keys - glusterfs.ancestry.dentry and glusterfs.ancestry.path - enable usage of this functionality. A successful getxattr will have the result stored under same keys. Values will be, glusterfs.ancestry.dentry: -------------------------- A linked list of gf-dirent structures for all possible paths from root to this gfid. If there are multiple paths, the linked-list will be a series of paths one after another. Each path will be a series of dentries representing all components of the path. This key is primarily for internal usage within glusterfs. glusterfs.ancestry.path: ------------------------ A string containing all possible paths from root to this gfid. Multiple hardlinks of a file or a symlink are displayed as a colon seperated list (this could interfere with path components containing ':'). e.g. If there is a file "file1" in root directory with two hardlinks, "/dir2/link2tofile1" and "/dir1/link1tofile1", then [root@alpha gfsmntpt]# getfattr -n glusterfs.ancestry.path -e text file1 glusterfs.ancestry.path="/file1:/dir2/link2tofile1:/dir1/link1tofile1" Thanks Amar, Avati and Venky for the inputs. Original Author: Ramana Raja <rraja@redhat.com> BUG: 990028 Signed-off-by: Raghavendra G <rgowdapp@redhat.com> Change-Id: I0eaa9101e333e0c1f66ccefd9e95944dd4a27497 Reviewed-on: http://review.gluster.org/5951 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'xlators/storage/posix/src/posix.c')
-rw-r--r--xlators/storage/posix/src/posix.c759
1 files changed, 645 insertions, 114 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index 1a344acbb..65b52a07c 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} }
};