summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/src/gfapi-messages.h3
-rw-r--r--api/src/gfapi.aliases5
-rw-r--r--api/src/gfapi.map9
-rw-r--r--api/src/glfs-fops.c137
-rw-r--r--api/src/glfs-handleops.c45
-rw-r--r--api/src/glfs-handles.h16
-rw-r--r--api/src/glfs-internal.h15
-rw-r--r--api/src/glfs-mem-types.h1
-rw-r--r--api/src/glfs.c10
-rw-r--r--api/src/glfs.h66
-rw-r--r--tests/basic/gfapi/glfs_xreaddirplus_r.c107
-rwxr-xr-xtests/basic/gfapi/glfs_xreaddirplus_r.t27
12 files changed, 437 insertions, 4 deletions
diff --git a/api/src/gfapi-messages.h b/api/src/gfapi-messages.h
index b4ecefbeb56..6fcbd9d392e 100644
--- a/api/src/gfapi-messages.h
+++ b/api/src/gfapi-messages.h
@@ -40,7 +40,7 @@
*/
#define GLFS_GFAPI_BASE GLFS_MSGID_COMP_API
-#define GLFS_NUM_MESSAGES 49
+#define GLFS_NUM_MESSAGES 50
#define GLFS_MSGID_END (GLFS_GFAPI_BASE + GLFS_NUM_MESSAGES + 1)
/* Messages with message IDs */
#define glfs_msg_start_x GLFS_GFAPI_BASE, "Invalid: Start of messages"
@@ -95,6 +95,7 @@
#define API_MSG_CREATE_HANDLE_FAILED (GLFS_GFAPI_BASE + 47)
#define API_MSG_INODE_LINK_FAILED (GLFS_GFAPI_BASE + 48)
#define API_MSG_STATEDUMP_FAILED (GLFS_GFAPI_BASE + 49)
+#define API_MSG_XREADDIRP_R_FAILED (GLFS_GFAPI_BASE + 50)
/*------------*/
#define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
diff --git a/api/src/gfapi.aliases b/api/src/gfapi.aliases
index fed2fd82b1e..f3726a33484 100644
--- a/api/src/gfapi.aliases
+++ b/api/src/gfapi.aliases
@@ -158,4 +158,9 @@ _pub_glfs_realpath _glfs_realpath$GFAPI_3.7.17
_pub_glfs_sysrq _glfs_sysrq$GFAPI_3.10.0
+_pub_glfs_xreaddirplus_r _glfs_xreaddirplus_r$GFAPI_3.11.0
+_pub_glfs_xreaddirplus_r_get_stat _glfs_xreaddirplus_r_get_stat$GFAPI_3.11.0
+_pub_glfs_xreaddirplus_r_get_object _glfs_xreaddirplus_r_get_object$GFAPI_3.11.0
+_pub_glfs_object_copy _glfs_object_copy$GFAPI_3.11.0
+
_pub_glfs_ipc _glfs_ipc$GFAPI_4.0.0
diff --git a/api/src/gfapi.map b/api/src/gfapi.map
index 3f7d2bb56a6..5e0c877077d 100644
--- a/api/src/gfapi.map
+++ b/api/src/gfapi.map
@@ -199,7 +199,14 @@ GFAPI_3.10.0 {
glfs_sysrq;
} GFAPI_3.7.17;
+GFAPI_3.11.0 {
+ glfs_xreaddirplus_r;
+ glfs_xreaddirplus_r_get_stat;
+ glfs_xreaddirplus_r_get_object;
+ glfs_object_copy;
+} GFAPI_3.10.0;
+
GFAPI_4.0.0 {
global:
glfs_ipc;
-} GFAPI_3.10.0;
+} GFAPI_3.11.0;
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index 0e5b206b98c..1bb958fc1b7 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -2792,7 +2792,7 @@ glfd_entry_next (struct glfs_fd *glfd, int plus)
}
-static struct dirent *
+struct dirent *
glfs_readdirbuf_get (struct glfs_fd *glfd)
{
struct dirent *buf = NULL;
@@ -4608,3 +4608,138 @@ out:
invalid_fs:
return ret;
}
+
+/*
+ * Given glfd of a directory, this function does readdirp and returns
+ * xstat along with dirents.
+ */
+int
+pub_glfs_xreaddirplus_r (struct glfs_fd *glfd, uint32_t flags,
+ struct glfs_xreaddirp_stat **xstat_p,
+ struct dirent *ext,
+ struct dirent **res)
+{
+ int ret = -1;
+ gf_dirent_t *entry = NULL;
+ struct dirent *buf = NULL;
+ struct glfs_xreaddirp_stat *xstat = NULL;
+
+ DECLARE_OLD_THIS;
+ __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
+
+ GF_REF_GET (glfd);
+
+ GF_VALIDATE_OR_GOTO (THIS->name, xstat_p, out);
+ GF_VALIDATE_OR_GOTO (THIS->name, res, out);
+
+ errno = 0;
+
+ if (ext)
+ buf = ext;
+ else
+ buf = glfs_readdirbuf_get (glfd);
+
+ if (!buf)
+ goto out;
+
+ xstat = GF_CALLOC(1, sizeof(struct glfs_xreaddirp_stat),
+ glfs_mt_xreaddirp_stat_t);
+
+ if (!xstat)
+ goto out;
+
+ /* this is readdirplus operation */
+ entry = glfd_entry_next (glfd, 1);
+
+ /* XXX: Ideally when we reach EOD, errno should have been
+ * set to ENOENT. But that doesn't seem to be the case.
+ *
+ * The only way to confirm if its EOD at this point is that
+ * errno == 0 and entry == NULL
+ */
+ if (errno)
+ goto out;
+
+ if (!entry) {
+ /* reached EOD, ret = 0 */
+ ret = 0;
+ *res = NULL;
+ goto out;
+ }
+
+ *res = buf;
+ gf_dirent_to_dirent (entry, buf);
+
+ if (flags & GFAPI_XREADDIRP_STAT) {
+ glfs_iatt_to_stat (glfd->fs, &entry->d_stat, &xstat->st);
+ xstat->flags_handled |= GFAPI_XREADDIRP_STAT;
+ }
+
+ if ((flags & GFAPI_XREADDIRP_HANDLE) &&
+ /* skip . and .. */
+ strcmp(buf->d_name, ".")
+ && strcmp(buf->d_name, "..")) {
+
+ /* Now create object.
+ * We can use "glfs_h_find_handle" as well as inodes would have
+ * already got linked as part of 'gf_link_inodes_from_dirent' */
+ xstat->object = glfs_h_create_from_handle (glfd->fs,
+ entry->d_stat.ia_gfid,
+ GFAPI_HANDLE_LENGTH,
+ NULL);
+
+ if (xstat->object) { /* success */
+ /* note: xstat->object->inode->ref is taken
+ * This shall be unref'ed when application does
+ * glfs_free(xstat) */
+ xstat->flags_handled |= GFAPI_XREADDIRP_HANDLE;
+ }
+ }
+
+ ret = xstat->flags_handled;
+ *xstat_p = xstat;
+
+out:
+ gf_msg_debug (THIS->name, 0,
+ "xreaddirp- requested_flags (%x) , processed_flags (%x)",
+ flags, xstat->flags_handled);
+
+ GF_REF_PUT (glfd);
+
+ if (ret < 0) {
+ gf_msg (THIS->name, GF_LOG_WARNING, errno,
+ API_MSG_XREADDIRP_R_FAILED,
+ "glfs_x_readdirp_r failed - reason (%s)",
+ strerror(errno));
+
+ if (xstat)
+ glfs_free (xstat);
+ }
+
+ __GLFS_EXIT_FS;
+
+ return ret;
+
+invalid_fs:
+ return -1;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_r, 3.11.0);
+
+struct stat*
+pub_glfs_xreaddirplus_get_stat (struct glfs_xreaddirp_stat *xstat)
+{
+ GF_VALIDATE_OR_GOTO ("glfs_xreaddirplus_get_stat", xstat, out);
+
+ if (!xstat->flags_handled & GFAPI_XREADDIRP_STAT)
+ gf_msg (THIS->name, GF_LOG_ERROR, errno,
+ LG_MSG_INVALID_ARG,
+ "GFAPI_XREADDIRP_STAT is not set. Flags"
+ "handled for xstat(%p) are (%x)",
+ xstat, xstat->flags_handled);
+ return &xstat->st;
+
+out:
+ return NULL;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_get_stat, 3.11.0);
+
diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c
index 69c542e5886..de0a6deb87f 100644
--- a/api/src/glfs-handleops.c
+++ b/api/src/glfs-handleops.c
@@ -2379,3 +2379,48 @@ pub_glfs_h_anonymous_write (struct glfs *fs, struct glfs_object *object,
}
GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_h_anonymous_write, 3.7.0);
+
+struct glfs_object*
+pub_glfs_object_copy (struct glfs_object *src)
+{
+ struct glfs_object *object = NULL;
+
+ GF_VALIDATE_OR_GOTO ("glfs_dup_object", src, out);
+
+ object = GF_CALLOC (1, sizeof(struct glfs_object),
+ glfs_mt_glfs_object_t);
+ if (object == NULL) {
+ errno = ENOMEM;
+ gf_msg (THIS->name, GF_LOG_WARNING, errno,
+ API_MSG_CREATE_HANDLE_FAILED,
+ "glfs_dup_object for gfid-%s failed",
+ uuid_utoa (src->inode->gfid));
+ return NULL;
+ }
+
+ object->inode = inode_ref (src->inode);
+ gf_uuid_copy (object->gfid, src->inode->gfid);
+
+out:
+ return object;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_object_copy, 3.11.0);
+
+struct glfs_object*
+pub_glfs_xreaddirplus_get_object (struct glfs_xreaddirp_stat *xstat)
+{
+ GF_VALIDATE_OR_GOTO ("glfs_xreaddirplus_get_object", xstat, out);
+
+ if (!(xstat->flags_handled & GFAPI_XREADDIRP_HANDLE))
+ gf_msg (THIS->name, GF_LOG_ERROR, errno,
+ LG_MSG_INVALID_ARG,
+ "GFAPI_XREADDIRP_HANDLE is not set. Flags"
+ "handled for xstat(%p) are (%x)",
+ xstat, xstat->flags_handled);
+
+ return xstat->object;
+
+out:
+ return NULL;
+}
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_get_object, 3.11.0);
diff --git a/api/src/glfs-handles.h b/api/src/glfs-handles.h
index ef994aaf88c..9583fab069a 100644
--- a/api/src/glfs-handles.h
+++ b/api/src/glfs-handles.h
@@ -355,6 +355,22 @@ glfs_h_anonymous_read (struct glfs *fs, struct glfs_object *object,
const void *buf, size_t count, off_t offset) __THROW
GFAPI_PUBLIC(glfs_h_anonymous_read, 3.7.0);
+/*
+ * Caution: The object returned by this object gets freed as part
+ * of 'glfs_free(xstat)'. Make sure to have a copy using 'glfs_object_copy()'
+ * to use post that.
+ */
+struct glfs_object*
+glfs_xreaddirplus_get_object (struct glfs_xreaddirp_stat *xstat) __THROW
+ GFAPI_PUBLIC(glfs_xreaddirplus_get_object, 3.11.0);
+
+/* Applications should close the object returned by this routine
+ * explicitly using 'glfs_h_close()'
+ */
+struct glfs_object*
+glfs_object_copy (struct glfs_object *src);
+ GFAPI_PUBLIC(glfs_object_copy, 3.11.0);
+
__END_DECLS
#endif /* !_GLFS_HANDLES_H */
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h
index a42822420ea..6b964b57304 100644
--- a/api/src/glfs-internal.h
+++ b/api/src/glfs-internal.h
@@ -245,6 +245,12 @@ struct glfs_upcall_inode {
struct stat oldp_buf; /* Latest stat of old parent dir handle */
};
+struct glfs_xreaddirp_stat {
+ struct stat st; /* Stat for that dirent - corresponds to GFAPI_XREADDIRP_STAT */
+ struct glfs_object *object; /* handled for GFAPI_XREADDIRP_HANDLE */
+ uint32_t flags_handled; /* final set of flags successfulyy handled */
+};
+
#define DEFAULT_EVENT_POOL_SIZE 16384
#define GF_MEMPOOL_COUNT_OF_DICT_T 4096
#define GF_MEMPOOL_COUNT_OF_DATA_T (GF_MEMPOOL_COUNT_OF_DICT_T * 4)
@@ -445,7 +451,6 @@ glfs_anonymous_pwritev (struct glfs *fs, struct glfs_object *object,
struct glfs_object *
glfs_h_resolve_symlink (struct glfs *fs, struct glfs_object *object);
-
/* Deprecated structures that were passed to client applications, replaced by
* accessor functions. Do not use these in new applications, and update older
* usage.
@@ -475,5 +480,13 @@ struct glfs_callback_inode_arg {
struct stat oldp_buf; /* Latest stat of old parent
* dir handle */
};
+struct dirent *
+glfs_readdirbuf_get (struct glfs_fd *glfd);
+
+gf_dirent_t *
+glfd_entry_next (struct glfs_fd *glfd, int plus);
+
+void
+gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent);
#endif /* !_GLFS_INTERNAL_H */
diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h
index 52033360853..4179138e65e 100644
--- a/api/src/glfs-mem-types.h
+++ b/api/src/glfs-mem-types.h
@@ -29,6 +29,7 @@ enum glfs_mem_types_ {
glfs_mt_acl_t,
glfs_mt_upcall_inode_t,
glfs_mt_realpath_t,
+ glfs_mt_xreaddirp_stat_t,
glfs_mt_end
};
#endif
diff --git a/api/src/glfs.c b/api/src/glfs.c
index 10af6c78e17..d9f07603b0f 100644
--- a/api/src/glfs.c
+++ b/api/src/glfs.c
@@ -1375,6 +1375,16 @@ pub_glfs_free (void *ptr)
GF_FREE (ptr);
break;
}
+ case glfs_mt_xreaddirp_stat_t:
+ {
+ struct glfs_xreaddirp_stat *to_free = ptr;
+
+ if (to_free->object)
+ glfs_h_close (to_free->object);
+
+ GF_FREE (ptr);
+ break;
+ }
default:
GF_FREE (ptr);
}
diff --git a/api/src/glfs.h b/api/src/glfs.h
index 68fcf4ddcd9..4e535bda168 100644
--- a/api/src/glfs.h
+++ b/api/src/glfs.h
@@ -41,6 +41,7 @@
#include <sys/cdefs.h>
#include <dirent.h>
#include <sys/statvfs.h>
+#include <inttypes.h>
#if defined(HAVE_SYS_ACL_H) || (defined(USE_POSIX_ACLS) && USE_POSIX_ACLS)
#include <sys/acl.h>
@@ -790,6 +791,71 @@ int glfs_sysrq (glfs_t *fs, char sysrq) __THROW
/*
+ * Structure returned as part of xreaddirplus
+ */
+struct glfs_xreaddirp_stat;
+
+/* Request flags to be used in XREADDIRP operation */
+#define GFAPI_XREADDIRP_NULL 0x00000000 /* by default, no stat will be fetched */
+#define GFAPI_XREADDIRP_STAT 0x00000001 /* Get stat */
+#define GFAPI_XREADDIRP_HANDLE 0x00000002 /* Get object handle */
+
+/*
+ * This stat structure returned gets freed as part of glfs_free(xstat)
+ */
+struct stat*
+glfs_xreaddirplus_get_stat (struct glfs_xreaddirp_stat *xstat) __THROW
+ GFAPI_PUBLIC(glfs_xreaddirplus_get_stat, 3.11.0);
+
+/*
+ * SYNOPSIS
+ *
+ * glfs_xreaddirplus_r: Extended Readirplus operation
+ *
+ * DESCRIPTION
+ *
+ * This API does readdirplus operation, but along with stat it can fetch other
+ * extra information like object handles etc for each of the dirents returned
+ * based on requested flags. On success it returns the set of flags successfully
+ * processed.
+ *
+ * Note that there are chances that some of the requested information may not be
+ * available or returned (for example if reached EOD). Ensure to validate the
+ * returned value to determine what flags have been successfully processed
+ * & set.
+ *
+ * PARAMETERS
+ *
+ * INPUT:
+ * @glfd: GFAPI file descriptor of the directory
+ * @flags: Flags determining xreaddirp_stat requested
+ * Current available values are:
+ * GFAPI_XREADDIRP_NULL
+ * GFAPI_XREADDIRP_STAT
+ * GFAPI_XREADDIRP_HANDLE
+ * @ext: Dirent struture to copy the values to
+ * (though optional recommended to be allocated by application
+ * esp., in multi-threaded environement)
+ *
+ * OUTPUT:
+ * @res: to store the next dirent value. If NULL and return value is '0',
+ * it means it reached end of the directory.
+ * @xstat_p: Pointer to contain all the requested data returned
+ * for that dirent. Application should make use of glfs_free() API
+ * to free this pointer and the variables returned by
+ * glfs_xreaddirplus_get_*() APIs.
+ *
+ * RETURN VALUE:
+ * >=0: SUCCESS (value contains the flags successfully processed)
+ * -1: FAILURE
+ */
+int
+glfs_xreaddirplus_r (struct glfs_fd *glfd, uint32_t flags,
+ struct glfs_xreaddirp_stat **xstat_p,
+ struct dirent *ext, struct dirent **res);
+ GFAPI_PUBLIC(glfs_xreaddirplus_r, 3.11.0);
+
+/*
* Nobody needs this call at all yet except for the test script.
*/
int glfs_ipc (glfs_fd_t *fd, int cmd, void *xd_in, void **xd_out) __THROW
diff --git a/tests/basic/gfapi/glfs_xreaddirplus_r.c b/tests/basic/gfapi/glfs_xreaddirplus_r.c
new file mode 100644
index 00000000000..eed80686d70
--- /dev/null
+++ b/tests/basic/gfapi/glfs_xreaddirplus_r.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glusterfs/api/glfs.h>
+#include <glusterfs/api/glfs-handles.h>
+
+#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) do { \
+ if (ret < 0) { \
+ fprintf (stderr, "%s : returned error %d (%s)\n", \
+ func, ret, strerror (errno)); \
+ goto label; \
+ } \
+ } while (0)
+
+#define MAX_FILES_CREATE 10
+#define MAXPATHNAME 512
+
+int
+main (int argc, char *argv[])
+{
+ int ret = -1;
+ glfs_t *fs = NULL;
+ char *volname = NULL;
+ char *logfile = NULL;
+ char *hostname = NULL;
+ char *my_file = "file_";
+ char my_file_name[MAXPATHNAME];
+ struct dirent de;
+ struct dirent *pde = NULL;
+ struct glfs_xreaddirp_stat *xstat = NULL;
+ uint32_t rflags = (GFAPI_XREADDIRP_STAT |
+ GFAPI_XREADDIRP_HANDLE);
+ uint32_t flags = O_RDWR|O_SYNC;
+ struct glfs_fd *fd = NULL;
+ int i = 0;
+
+ if (argc != 4) {
+ fprintf (stderr, "Invalid argument\n");
+ return 1;
+ }
+
+ hostname = argv[1];
+ volname = argv[2];
+ logfile = argv[3];
+
+ fs = glfs_new (volname);
+ if (!fs)
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_new", ret, out);
+
+ ret = glfs_set_volfile_server (fs, "tcp", hostname, 24007);
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_set_volfile_server", ret, out);
+
+ ret = glfs_set_logging (fs, logfile, 7);
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_set_logging", ret, out);
+
+ ret = glfs_init (fs);
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_init", ret, out);
+
+ for (i = 0; i < MAX_FILES_CREATE; i++) {
+ sprintf (my_file_name, "%s%d", my_file, i);
+
+ fd = glfs_creat(fs, my_file_name, flags, 0644);
+ if (fd == NULL) {
+ ret = -1;
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_creat", ret,
+ out);
+ }
+
+
+ glfs_close (fd);
+ }
+
+ /* XXX: measure performance and memory usage of this readdirp call */
+ fd = glfs_opendir (fs, "/");
+
+ ret = glfs_xreaddirplus_r(fd, rflags, &xstat, &de, &pde);
+ while (ret > 0 && pde != NULL) {
+ fprintf (stderr, "%s: %lu\n", de.d_name, glfs_telldir (fd));
+
+ if (xstat)
+ glfs_free(xstat);
+
+ ret = glfs_xreaddirplus_r(fd, rflags, &xstat, &de, &pde);
+
+ /* XXX: Use other APIs to fetch stat and handles */
+ }
+
+ if (xstat)
+ glfs_free(xstat);
+
+ VALIDATE_AND_GOTO_LABEL_ON_ERROR ("glfs_xreaddirp_r", ret, out);
+
+out:
+ if (fd != NULL)
+ glfs_close(fd);
+
+ if (fs) {
+ ret = glfs_fini(fs);
+ if (ret)
+ fprintf (stderr, "glfs_fini(fs) returned %d\n", ret);
+ }
+
+ return ret;
+}
+
+
diff --git a/tests/basic/gfapi/glfs_xreaddirplus_r.t b/tests/basic/gfapi/glfs_xreaddirplus_r.t
new file mode 100755
index 00000000000..fa882f1849f
--- /dev/null
+++ b/tests/basic/gfapi/glfs_xreaddirplus_r.t
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+
+cleanup;
+
+TEST glusterd
+
+TEST $CLI volume create $V0 $H0:$B0/brick1;
+EXPECT 'Created' volinfo_field $V0 'Status';
+
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+logdir=`gluster --print-logdir`
+
+TEST build_tester $(dirname $0)/glfs_xreaddirplus_r.c -lgfapi
+
+TEST $(dirname $0)/glfs_xreaddirplus_r $H0 $V0 $logdir/glfs_xreaddirplus_r.log
+
+cleanup_tester $(dirname $0)/glfs_xreaddirplus_r
+
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0
+
+cleanup;