From c1109ed6c6c7bff0df22c304158e9f392f83cf59 Mon Sep 17 00:00:00 2001 From: Anand Avati Date: Wed, 30 Oct 2013 14:30:26 -0700 Subject: gfapi: introduce glfs_readdir() and glfs_readdirplus() APIs Change-Id: I6b233bf647585675f233898351bf593f251716cc BUG: 839950 Signed-off-by: Anand Avati Reviewed-on: http://review.gluster.org/6201 Tested-by: Gluster Build System Reviewed-by: Raghavendra Talur --- api/src/glfs-fops.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-- api/src/glfs-internal.h | 1 + api/src/glfs-mem-types.h | 1 + api/src/glfs.c | 3 ++ api/src/glfs.h | 19 +++++++++++++ 5 files changed, 96 insertions(+), 2 deletions(-) diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 7572a94f2..10bb7d38b 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -13,7 +13,15 @@ #include "glfs-mem-types.h" #include "syncop.h" #include "glfs.h" +#include +#ifdef NAME_MAX +#define GF_NAME_MAX NAME_MAX +#else +#define GF_NAME_MAX 255 +#endif + +#define READDIRBUF_SIZE (sizeof(struct dirent) + GF_NAME_MAX + 1) int glfs_loc_link (loc_t *loc, struct iatt *iatt) @@ -1918,7 +1926,7 @@ gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent) dirent->d_namlen = strlen (gf_dirent->d_name); #endif - strncpy (dirent->d_name, gf_dirent->d_name, 256); + strncpy (dirent->d_name, gf_dirent->d_name, GF_NAME_MAX + 1); } @@ -2012,16 +2020,56 @@ glfd_entry_next (struct glfs_fd *glfd, int plus) } +static struct dirent * +glfs_readdirbuf_get (struct glfs_fd *glfd) +{ + struct dirent *buf = NULL; + + LOCK (&glfd->fd->lock); + { + buf = glfd->readdirbuf; + if (buf) { + memset (buf, 0, READDIRBUF_SIZE); + goto unlock; + } + + buf = GF_CALLOC (1, READDIRBUF_SIZE, glfs_mt_readdirbuf_t); + if (!buf) { + errno = ENOMEM; + goto unlock; + } + + glfd->readdirbuf = buf; + } +unlock: + UNLOCK (&glfd->fd->lock); + + return buf; +} + + int -glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat, struct dirent *buf, +glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat, struct dirent *ext, struct dirent **res) { int ret = 0; gf_dirent_t *entry = NULL; + struct dirent *buf = NULL; __glfs_entry_fd (glfd); errno = 0; + + if (ext) + buf = ext; + else + buf = glfs_readdirbuf_get (glfd); + + if (!buf) { + errno = ENOMEM; + return -1; + } + entry = glfd_entry_next (glfd, !!stat); if (errno) ret = -1; @@ -2050,6 +2098,28 @@ glfs_readdir_r (struct glfs_fd *glfd, struct dirent *buf, struct dirent **res) } +struct dirent * +glfs_readdirplus (struct glfs_fd *glfd, struct stat *stat) +{ + struct dirent *res = NULL; + int ret = -1; + + ret = glfs_readdirplus_r (glfd, stat, NULL, &res); + if (ret) + return NULL; + + return res; +} + + + +struct dirent * +glfs_readdir (struct glfs_fd *glfd) +{ + return glfs_readdirplus (glfd, NULL); +} + + int glfs_statvfs (struct glfs *fs, const char *path, struct statvfs *buf) { diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 1b1c1c7f6..ec1d5579d 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -95,6 +95,7 @@ struct glfs_fd { fd_t *fd; /* Currently guared by @fs->mutex. TODO: per-glfd lock */ struct list_head entries; gf_dirent_t *next; + struct dirent *readdirbuf; }; /* glfs object handle introduced for the alternate gfapi implementation based diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h index 25b155b9c..3301b3da5 100644 --- a/api/src/glfs-mem-types.h +++ b/api/src/glfs-mem-types.h @@ -24,6 +24,7 @@ enum glfs_mem_types_ { glfs_mt_volfile_t, glfs_mt_xlator_cmdline_option_t, glfs_mt_glfs_object_t, + glfs_mt_readdirbuf_t, glfs_mt_end }; diff --git a/api/src/glfs.c b/api/src/glfs.c index ed731eae9..e94419c2d 100644 --- a/api/src/glfs.c +++ b/api/src/glfs.c @@ -384,6 +384,9 @@ glfs_fd_destroy (struct glfs_fd *glfd) if (glfd->fd) fd_unref (glfd->fd); + + GF_FREE (glfd->readdirbuf); + GF_FREE (glfd); } diff --git a/api/src/glfs.h b/api/src/glfs.h index d179b87ba..18fda496e 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -468,12 +468,31 @@ int glfs_link (glfs_t *fs, const char *oldpath, const char *newpath); glfs_fd_t *glfs_opendir (glfs_t *fs, const char *path); +/* + * @glfs_readdir_r and @glfs_readdirplus_r ARE thread safe AND re-entrant, + * but the interface has ambiguity about the size of @dirent to be allocated + * before calling the APIs. 512 byte buffer (for @dirent) is sufficient for + * all known systems which are tested againt glusterfs/gfapi, but may be + * insufficient in the future. + */ + int glfs_readdir_r (glfs_fd_t *fd, struct dirent *dirent, struct dirent **result); int glfs_readdirplus_r (glfs_fd_t *fd, struct stat *stat, struct dirent *dirent, struct dirent **result); +/* + * @glfs_readdir and @glfs_readdirplus are NEITHER thread safe NOR re-entrant + * when called on the same directory handle. However they ARE thread safe + * AND re-entrant when called on different directory handles (which may be + * referring to the same directory too.) + */ + +struct dirent *glfs_readdir (glfs_fd_t *fd); + +struct dirent *glfs_readdirplus (glfs_fd_t *fd, struct stat *stat); + long glfs_telldir (glfs_fd_t *fd); void glfs_seekdir (glfs_fd_t *fd, long offset); -- cgit