From 2475e0193c4b4a37028bd8168113d6cd6949fe0e Mon Sep 17 00:00:00 2001 From: Anand Avati Date: Thu, 12 Jul 2012 15:37:38 -0700 Subject: gfapi: API/library for accessing gluster volumes Change-Id: Ie4cbcf91b58218bebf23cf951c313aceeb29f311 BUG: 839950 Signed-off-by: Anand Avati Reviewed-on: http://review.gluster.com/3664 Tested-by: Gluster Build System Reviewed-by: Jeff Darcy Reviewed-by: Kaleb KEITHLEY Reviewed-by: Bharata B Rao --- Makefile.am | 3 +- api/Makefile.am | 1 + api/src/Makefile.am | 30 ++ api/src/glfs-fops.c | 829 +++++++++++++++++++++++++++++++++++++++++++++++ api/src/glfs-internal.h | 74 +++++ api/src/glfs-master.c | 113 +++++++ api/src/glfs-mem-types.h | 28 ++ api/src/glfs-mgmt.c | 629 +++++++++++++++++++++++++++++++++++ api/src/glfs-resolve.c | 244 ++++++++++++++ api/src/glfs.c | 546 +++++++++++++++++++++++++++++++ api/src/glfs.h | 366 +++++++++++++++++++++ configure.ac | 2 + 12 files changed, 2864 insertions(+), 1 deletion(-) create mode 100644 api/Makefile.am create mode 100644 api/src/Makefile.am create mode 100644 api/src/glfs-fops.c create mode 100644 api/src/glfs-internal.h create mode 100644 api/src/glfs-master.c create mode 100644 api/src/glfs-mem-types.h create mode 100644 api/src/glfs-mgmt.c create mode 100644 api/src/glfs-resolve.c create mode 100644 api/src/glfs.c create mode 100644 api/src/glfs.h diff --git a/Makefile.am b/Makefile.am index 6693bb87..3cdd4dfb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ EXTRA_DIST = autogen.sh COPYING-GPLV2 COPYING-LGPLV3 INSTALL README AUTHORS THANKS NEWS glusterfs.spec -SUBDIRS = argp-standalone libglusterfs rpc xlators glusterfsd $(FUSERMOUNT_SUBDIR) doc extras cli +SUBDIRS = argp-standalone libglusterfs rpc api xlators glusterfsd \ + $(FUSERMOUNT_SUBDIR) doc extras cli CLEANFILES = diff --git a/api/Makefile.am b/api/Makefile.am new file mode 100644 index 00000000..af437a64 --- /dev/null +++ b/api/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/api/src/Makefile.am b/api/src/Makefile.am new file mode 100644 index 00000000..f5fb9e70 --- /dev/null +++ b/api/src/Makefile.am @@ -0,0 +1,30 @@ +lib_LTLIBRARIES = libgfapi.la +noinst_HEADERS = glfs-mem-types.h glfs-internal.h +libgfapi_HEADERS = glfs.h +libgfapidir = $(includedir)/glusterfs/api + +libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c +libgfapi_la_CFLAGS = -fPIC -Wall +libgfapi_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ + $(top_builddir)/rpc/xdr/src/libgfxdr.la \ + $(GF_LDADD) + +libgfapi_la_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64 -D_GNU_SOURCE \ + -D$(GF_HOST_OS) $(GF_CFLAGS) \ + -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/rpc/rpc-lib/src \ + -I$(top_srcdir)/rpc/xdr/src +libgfapi_la_LDFLAGS = -shared -nostartfiles + + +xlator_LTLIBRARIES = api.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/mount + +api_la_SOURCES = glfs-master.c + +api_la_LDFLAGS = -module -avoidversion +api_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \ + -I$(top_srcdir)/libglusterfs/src $(GF_CFLAGS) diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c new file mode 100644 index 00000000..f3fba84e --- /dev/null +++ b/api/src/glfs-fops.c @@ -0,0 +1,829 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#include "glfs-internal.h" +#include "glfs-mem-types.h" +#include "syncop.h" +#include "glfs.h" + + +struct glfs_fd * +glfs_open (struct glfs *fs, const char *path, int flags) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + glfd = GF_CALLOC (1, sizeof (*glfd), glfs_mt_glfs_fd_t); + if (!glfd) + goto out; + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + if (IA_ISDIR (iatt.ia_type)) { + ret = -1; + errno = EISDIR; + goto out; + } + + if (!IA_ISREG (iatt.ia_type)) { + ret = -1; + errno = EINVAL; + goto out; + } + + glfd->fd = fd_create (loc.inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_open (subvol, &loc, flags, glfd->fd); +out: + loc_wipe (&loc); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } + + return glfd; +} + + +int +glfs_close (struct glfs_fd *glfd) +{ + xlator_t *subvol = NULL; + int ret = -1; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + + ret = syncop_flush (subvol, glfd->fd); + + glfs_fd_destroy (glfd); + + return ret; +} + + +int +glfs_lstat (struct glfs *fs, const char *path, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + + if (ret == 0 && stat) + iatt_to_stat (&iatt, stat); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_fstat (struct glfs_fd *glfd, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + struct iatt iatt = {0, }; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fstat (subvol, glfd->fd, &iatt); + + if (ret == 0 && stat) + iatt_to_stat (&iatt, stat); +out: + return ret; +} + + +struct glfs_fd * +glfs_creat (struct glfs *fs, const char *path, int flags, mode_t mode) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + glfd = GF_CALLOC (1, sizeof (*glfd), glfs_mt_glfs_fd_t); + if (!glfd) + goto out; + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + if (ret == -1 && errno != ENOENT) + /* Any other type of error is fatal */ + goto out; + + if (ret == -1 && errno == ENOENT && !loc.parent) + /* The parent directory or an ancestor even + higher does not exist + */ + goto out; + + if (loc.inode) { + if (flags & O_EXCL) { + ret = -1; + errno = EEXIST; + goto out; + } + + if (IA_ISDIR (iatt.ia_type)) { + ret = -1; + errno = EISDIR; + goto out; + } + + if (!IA_ISREG (iatt.ia_type)) { + ret = -1; + errno = EINVAL; + goto out; + } + } + + if (ret == -1 && errno == ENOENT) { + loc.inode = inode_new (loc.parent->table); + if (!loc.inode) { + ret = -1; + errno = ENOMEM; + goto out; + } + } + + glfd->fd = fd_create (loc.inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_create (subvol, &loc, flags, mode, glfd->fd, xattr_req); +out: + loc_wipe (&loc); + + if (xattr_req) + dict_destroy (xattr_req); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } + + return glfd; +} + + +off_t +glfs_lseek (struct glfs_fd *glfd, off_t offset, int whence) +{ + struct stat sb = {0, }; + int ret = -1; + + __glfs_entry_fd (glfd); + + switch (whence) { + case SEEK_SET: + glfd->offset = offset; + break; + case SEEK_CUR: + glfd->offset += offset; + break; + case SEEK_END: + ret = glfs_fstat (glfd, &sb); + if (ret) { + /* seek cannot fail :O */ + break; + } + glfd->offset = sb.st_size + offset; + break; + } + + return glfd->offset; +} + + +////////////// + +ssize_t +glfs_preadv (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt, + off_t offset, int flags) +{ + xlator_t *subvol = NULL; + int ret = -1; + size_t size = -1; + struct iovec *iov = NULL; + int cnt = 0; + struct iobref *iobref = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + + size = iov_length (iovec, iovcnt); + + ret = syncop_readv (subvol, glfd->fd, size, offset, + 0, &iov, &cnt, &iobref); + if (ret <= 0) + return ret; + + size = iov_copy (iovec, iovcnt, iov, cnt); /* FIXME!!! */ + + glfd->offset = (offset + size); + + if (iov) + GF_FREE (iov); + if (iobref) + iobref_unref (iobref); + + return size; +} + + +ssize_t +glfs_read (struct glfs_fd *glfd, void *buf, size_t count, int flags) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = buf; + iov.iov_len = count; + + ret = glfs_preadv (glfd, &iov, 1, glfd->offset, flags); + + return ret; +} + + +ssize_t +glfs_pread (struct glfs_fd *glfd, void *buf, size_t count, off_t offset, + int flags) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = buf; + iov.iov_len = count; + + ret = glfs_preadv (glfd, &iov, 1, offset, flags); + + return ret; +} + + +ssize_t +glfs_readv (struct glfs_fd *glfd, const struct iovec *iov, int count, + int flags) +{ + ssize_t ret = 0; + + ret = glfs_preadv (glfd, iov, count, glfd->offset, flags); + + return ret; +} + + +struct glfs_io { + struct glfs_fd *glfd; + int op; + off_t offset; + struct iovec *iov; + int count; + int flags; + glfs_io_cbk fn; + void *data; +}; + + +static int +glfs_io_async_cbk (int ret, call_frame_t *frame, void *data) +{ + struct glfs_io *gio = data; + + gio->fn (gio->glfd, ret, gio->data); + + GF_FREE (gio->iov); + GF_FREE (gio); + + return 0; +} + + +static int +glfs_io_async_task (void *data) +{ + struct glfs_io *gio = data; + ssize_t ret = 0; + + switch (gio->op) { + case GF_FOP_READ: + ret = glfs_preadv (gio->glfd, gio->iov, gio->count, + gio->offset, gio->flags); + break; + case GF_FOP_WRITE: + ret = glfs_pwritev (gio->glfd, gio->iov, gio->count, + gio->offset, gio->flags); + break; + case GF_FOP_FTRUNCATE: + ret = glfs_ftruncate (gio->glfd, gio->offset); + break; + case GF_FOP_FSYNC: + if (gio->flags) + ret = glfs_fdatasync (gio->glfd); + else + ret = glfs_fsync (gio->glfd); + break; + } + + return (int) ret; +} + + +int +glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec, int count, + off_t offset, int flags, glfs_io_cbk fn, void *data) +{ + struct glfs_io *gio = NULL; + int ret = 0; + + gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t); + if (!gio) { + errno = ENOMEM; + return -1; + } + + gio->iov = iov_dup (iovec, count); + if (!gio->iov) { + GF_FREE (gio); + errno = ENOMEM; + return -1; + } + + gio->op = GF_FOP_READ; + gio->glfd = glfd; + gio->count = count; + gio->offset = offset; + gio->flags = flags; + gio->fn = fn; + gio->data = data; + + ret = synctask_new (glfs_from_glfd (glfd)->ctx->env, + glfs_io_async_task, glfs_io_async_cbk, + NULL, gio); + + if (ret) { + GF_FREE (gio->iov); + GF_FREE (gio); + } + + return ret; +} + + +int +glfs_read_async (struct glfs_fd *glfd, void *buf, size_t count, int flags, + glfs_io_cbk fn, void *data) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = buf; + iov.iov_len = count; + + ret = glfs_preadv_async (glfd, &iov, 1, glfd->offset, flags, fn, data); + + return ret; +} + + +int +glfs_pread_async (struct glfs_fd *glfd, void *buf, size_t count, off_t offset, + int flags, glfs_io_cbk fn, void *data) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = buf; + iov.iov_len = count; + + ret = glfs_preadv_async (glfd, &iov, 1, offset, flags, fn, data); + + return ret; +} + + +int +glfs_readv_async (struct glfs_fd *glfd, const struct iovec *iov, int count, + int flags, glfs_io_cbk fn, void *data) +{ + ssize_t ret = 0; + + ret = glfs_preadv_async (glfd, iov, count, glfd->offset, flags, + fn, data); + return ret; +} + +///// writev ///// + +ssize_t +glfs_pwritev (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt, + off_t offset, int flags) +{ + xlator_t *subvol = NULL; + int ret = -1; + size_t size = -1; + struct iobref *iobref = NULL; + struct iobuf *iobuf = NULL; + struct iovec iov = {0, }; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + + size = iov_length (iovec, iovcnt); + + iobuf = iobuf_get2 (subvol->ctx->iobuf_pool, size); + if (!iobuf) { + errno = ENOMEM; + return -1; + } + + iobref = iobref_new (); + if (!iobref) { + iobuf_unref (iobuf); + errno = ENOMEM; + return -1; + } + + ret = iobref_add (iobref, iobuf); + if (ret) { + iobuf_unref (iobuf); + iobref_unref (iobref); + errno = ENOMEM; + return -1; + } + + iov_unload (iobuf_ptr (iobuf), iovec, iovcnt); /* FIXME!!! */ + + iov.iov_base = iobuf_ptr (iobuf); + iov.iov_len = size; + + ret = syncop_writev (subvol, glfd->fd, &iov, 1, offset, + iobref, flags); + + iobuf_unref (iobuf); + iobref_unref (iobref); + + if (ret <= 0) + return ret; + + glfd->offset = (offset + size); + + return ret; +} + + +ssize_t +glfs_write (struct glfs_fd *glfd, const void *buf, size_t count, int flags) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = (void *) buf; + iov.iov_len = count; + + ret = glfs_pwritev (glfd, &iov, 1, glfd->offset, flags); + + return ret; +} + + + +ssize_t +glfs_writev (struct glfs_fd *glfd, const struct iovec *iov, int count, + int flags) +{ + ssize_t ret = 0; + + ret = glfs_pwritev (glfd, iov, count, glfd->offset, flags); + + return ret; +} + + +ssize_t +glfs_pwrite (struct glfs_fd *glfd, const void *buf, size_t count, off_t offset, + int flags) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = (void *) buf; + iov.iov_len = count; + + ret = glfs_pwritev (glfd, &iov, 1, offset, flags); + + return ret; +} + + +int +glfs_pwritev_async (struct glfs_fd *glfd, const struct iovec *iovec, int count, + off_t offset, int flags, glfs_io_cbk fn, void *data) +{ + struct glfs_io *gio = NULL; + int ret = 0; + + gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t); + if (!gio) { + errno = ENOMEM; + return -1; + } + + gio->iov = iov_dup (iovec, count); + if (!gio->iov) { + GF_FREE (gio); + errno = ENOMEM; + return -1; + } + + gio->op = GF_FOP_WRITE; + gio->glfd = glfd; + gio->count = count; + gio->offset = offset; + gio->flags = flags; + gio->fn = fn; + gio->data = data; + + ret = synctask_new (glfs_from_glfd (glfd)->ctx->env, + glfs_io_async_task, glfs_io_async_cbk, + NULL, gio); + + if (ret) { + GF_FREE (gio->iov); + GF_FREE (gio); + } + + return ret; +} + + +int +glfs_write_async (struct glfs_fd *glfd, const void *buf, size_t count, int flags, + glfs_io_cbk fn, void *data) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = (void *) buf; + iov.iov_len = count; + + ret = glfs_pwritev_async (glfd, &iov, 1, glfd->offset, flags, fn, data); + + return ret; +} + + +int +glfs_pwrite_async (struct glfs_fd *glfd, const void *buf, int count, + off_t offset, int flags, glfs_io_cbk fn, void *data) +{ + struct iovec iov = {0, }; + ssize_t ret = 0; + + iov.iov_base = (void *) buf; + iov.iov_len = count; + + ret = glfs_pwritev_async (glfd, &iov, 1, offset, flags, fn, data); + + return ret; +} + + +int +glfs_writev_async (struct glfs_fd *glfd, const struct iovec *iov, int count, + int flags, glfs_io_cbk fn, void *data) +{ + ssize_t ret = 0; + + ret = glfs_pwritev_async (glfd, iov, count, glfd->offset, flags, + fn, data); + return ret; +} + + +int +glfs_fsync (struct glfs_fd *glfd) +{ + int ret = -1; + xlator_t *subvol = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fsync (subvol, glfd->fd); +// ret = syncop_fsync (subvol, glfd->fd, 0); +out: + return ret; +} + + +static int +glfs_fsync_async_common (struct glfs_fd *glfd, glfs_io_cbk fn, void *data, + int dataonly) +{ + struct glfs_io *gio = NULL; + int ret = 0; + + gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t); + if (!gio) { + errno = ENOMEM; + return -1; + } + + gio->op = GF_FOP_FSYNC; + gio->glfd = glfd; + gio->flags = dataonly; + gio->fn = fn; + gio->data = data; + + ret = synctask_new (glfs_from_glfd (glfd)->ctx->env, + glfs_io_async_task, glfs_io_async_cbk, + NULL, gio); + + if (ret) { + GF_FREE (gio->iov); + GF_FREE (gio); + } + + return ret; + +} + + +int +glfs_fsync_async (struct glfs_fd *glfd, glfs_io_cbk fn, void *data) +{ + return glfs_fsync_async_common (glfd, fn, data, 0); +} + + +int +glfs_fdatasync (struct glfs_fd *glfd) +{ + int ret = -1; + xlator_t *subvol = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fsync (subvol, glfd->fd); +// ret = syncop_fsync (subvol, glfd->fd, 1); +out: + return ret; +} + + +int +glfs_fdatasync_async (struct glfs_fd *glfd, glfs_io_cbk fn, void *data) +{ + return glfs_fsync_async_common (glfd, fn, data, 1); +} + + +int +glfs_ftruncate (struct glfs_fd *glfd, off_t offset) +{ + int ret = -1; + xlator_t *subvol = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_ftruncate (subvol, glfd->fd, offset); +out: + return ret; +} + + +int +glfs_ftruncate_async (struct glfs_fd *glfd, off_t offset, + glfs_io_cbk fn, void *data) +{ + struct glfs_io *gio = NULL; + int ret = 0; + + gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t); + if (!gio) { + errno = ENOMEM; + return -1; + } + + gio->op = GF_FOP_FTRUNCATE; + gio->glfd = glfd; + gio->offset = offset; + gio->fn = fn; + gio->data = data; + + ret = synctask_new (glfs_from_glfd (glfd)->ctx->env, + glfs_io_async_task, glfs_io_async_cbk, + NULL, gio); + + if (ret) { + GF_FREE (gio->iov); + GF_FREE (gio); + } + + return ret; +} + diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h new file mode 100644 index 00000000..967be475 --- /dev/null +++ b/api/src/glfs-internal.h @@ -0,0 +1,74 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#ifndef _GLFS_INTERNAL_H +#define _GLFS_INTERNAL_H + +#include "xlator.h" + +struct glfs; + +typedef int (*glfs_init_cbk) (struct glfs *fs, int ret); + +struct glfs { + char *volname; + + glusterfs_ctx_t *ctx; + + pthread_t poller; + + glfs_init_cbk init_cbk; + pthread_mutex_t mutex; + pthread_cond_t cond; + int init; + int ret; + + xlator_t *active_subvol; +}; + +struct glfs_fd { + off_t offset; + fd_t *fd; +}; + +#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) +#define GF_MEMPOOL_COUNT_OF_DATA_PAIR_T (GF_MEMPOOL_COUNT_OF_DICT_T * 4) + +int glfs_mgmt_init (struct glfs *fs); +void glfs_init_done (struct glfs *fs, int ret); +int glfs_process_volfp (struct glfs *fs, FILE *fp); +int glfs_resolve (struct glfs *fs, xlator_t *subvol, const char *path, loc_t *loc, + struct iatt *iatt); +void glfs_first_lookup (xlator_t *subvol); + +static inline void +__glfs_entry_fs (struct glfs *fs) +{ + THIS = fs->ctx->master; +} + + +static inline void +__glfs_entry_fd (struct glfs_fd *fd) +{ + THIS = fd->fd->inode->table->xl->ctx->master; +} + + +void glfs_fd_destroy (struct glfs_fd *glfd); + +xlator_t * glfs_fd_subvol (struct glfs_fd *glfd); + +xlator_t * glfs_active_subvol (struct glfs *fs); + +#endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs-master.c b/api/src/glfs-master.c new file mode 100644 index 00000000..0806c307 --- /dev/null +++ b/api/src/glfs-master.c @@ -0,0 +1,113 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "glusterfs.h" +#include "glfs-internal.h" + + +int +glfs_graph_setup (struct glfs *fs, glusterfs_graph_t *graph) +{ + if (fs->active_subvol == graph->top) + return 0; + + pthread_mutex_lock (&fs->mutex); + { + fs->active_subvol = graph->top; + pthread_cond_broadcast (&fs->cond); + } + pthread_mutex_unlock (&fs->mutex); + + gf_log ("glfs-master", GF_LOG_INFO, "switched to graph %s (%d)", + uuid_utoa ((unsigned char *)graph->graph_uuid), graph->id); + + return 0; +} + + +int +notify (xlator_t *this, int event, void *data, ...) +{ + glusterfs_graph_t *graph = NULL; + struct glfs *fs = NULL; + + graph = data; + fs = this->private; + + switch (event) { + case GF_EVENT_GRAPH_NEW: + gf_log (this->name, GF_LOG_INFO, "New graph %s (%d) coming up", + uuid_utoa ((unsigned char *)graph->graph_uuid), + graph->id); + break; + case GF_EVENT_CHILD_UP: + glfs_graph_setup (fs, graph); + glfs_init_done (fs, 0); + break; + case GF_EVENT_CHILD_DOWN: + glfs_graph_setup (fs, graph); + glfs_init_done (fs, 1); + break; + case GF_EVENT_CHILD_CONNECTING: + break; + default: + gf_log (this->name, GF_LOG_DEBUG, + "got notify event %d", event); + break; + } + + return 0; +} + + +int +mem_acct_init (xlator_t *this) +{ + return 0; +} + + +int +init (xlator_t *this) +{ + return 0; +} + + +void +fini (xlator_t *this) +{ + +} + + +struct xlator_dumpops dumpops = { +}; + + +struct xlator_fops fops = { +}; + + +struct xlator_cbks cbks = { +}; diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h new file mode 100644 index 00000000..dc5da305 --- /dev/null +++ b/api/src/glfs-mem-types.h @@ -0,0 +1,28 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _GLFS_MEM_TYPES_H +#define _GLFS_MEM_TYPES_H + +#include "mem-types.h" + +#define GF_MEM_TYPE_START (gf_common_mt_end + 1) + +enum glfs_mem_types_ { + glfs_mt_glfs_t, + glfs_mt_call_pool_t, + glfs_mt_xlator_t, + glfs_mt_glfs_fd_t, + glfs_mt_glfs_io_t, + glfs_mt_end + +}; +#endif + diff --git a/api/src/glfs-mgmt.c b/api/src/glfs-mgmt.c new file mode 100644 index 00000000..526d1ae4 --- /dev/null +++ b/api/src/glfs-mgmt.c @@ -0,0 +1,629 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#include +#include +#include +#include +#include +#include + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif /* _CONFIG_H */ + +#include "glusterfs.h" +#include "stack.h" +#include "dict.h" +#include "event.h" +#include "defaults.h" + +#include "rpc-clnt.h" +#include "protocol-common.h" +#include "glusterfs3.h" +#include "portmap-xdr.h" +#include "xdr-generic.h" + +#include "syncop.h" +#include "xlator.h" + +#include "glfs-internal.h" + + +int glfs_volfile_fetch (struct glfs *fs); + +int +glfs_process_volfp (struct glfs *fs, FILE *fp) +{ + glusterfs_graph_t *graph = NULL; + int ret = -1; + xlator_t *trav = NULL; + glusterfs_ctx_t *ctx = NULL; + + ctx = fs->ctx; + graph = glusterfs_graph_construct (fp); + if (!graph) { + gf_log ("glfs", GF_LOG_ERROR, "failed to construct the graph"); + goto out; + } + + for (trav = graph->first; trav; trav = trav->next) { + if (strcmp (trav->type, "mount/fuse") == 0) { + gf_log ("glfs", GF_LOG_ERROR, + "fuse xlator cannot be specified " + "in volume file"); + goto out; + } + } + + ret = glusterfs_graph_prepare (graph, ctx); + if (ret) { + glusterfs_graph_destroy (graph); + goto out; + } + + ret = glusterfs_graph_activate (graph, ctx); + + if (ret) { + glusterfs_graph_destroy (graph); + goto out; + } + + ret = 0; +out: + if (fp) + fclose (fp); + + if (!ctx->active) { + ret = -1; + } + + return ret; +} + + +int +mgmt_cbk_spec (struct rpc_clnt *rpc, void *mydata, void *data) +{ + struct glfs *fs = NULL; + xlator_t *this = NULL; + + this = mydata; + fs = this->private; + + glfs_volfile_fetch (fs); + + return 0; +} + + +int +mgmt_cbk_event (struct rpc_clnt *rpc, void *mydata, void *data) +{ + return 0; +} + + +rpcclnt_cb_actor_t gluster_cbk_actors[] = { + [GF_CBK_FETCHSPEC] = {"FETCHSPEC", GF_CBK_FETCHSPEC, mgmt_cbk_spec }, + [GF_CBK_EVENT_NOTIFY] = {"EVENTNOTIFY", GF_CBK_EVENT_NOTIFY, + mgmt_cbk_event}, +}; + + +struct rpcclnt_cb_program mgmt_cbk_prog = { + .progname = "GlusterFS Callback", + .prognum = GLUSTER_CBK_PROGRAM, + .progver = GLUSTER_CBK_VERSION, + .actors = gluster_cbk_actors, + .numactors = GF_CBK_MAXVALUE, +}; + +char *clnt_handshake_procs[GF_HNDSK_MAXVALUE] = { + [GF_HNDSK_NULL] = "NULL", + [GF_HNDSK_SETVOLUME] = "SETVOLUME", + [GF_HNDSK_GETSPEC] = "GETSPEC", + [GF_HNDSK_PING] = "PING", + [GF_HNDSK_EVENT_NOTIFY] = "EVENTNOTIFY", +}; + +rpc_clnt_prog_t clnt_handshake_prog = { + .progname = "GlusterFS Handshake", + .prognum = GLUSTER_HNDSK_PROGRAM, + .progver = GLUSTER_HNDSK_VERSION, + .procnames = clnt_handshake_procs, +}; + + +int +mgmt_submit_request (void *req, call_frame_t *frame, + glusterfs_ctx_t *ctx, + rpc_clnt_prog_t *prog, int procnum, + fop_cbk_fn_t cbkfn, xdrproc_t xdrproc) +{ + int ret = -1; + int count = 0; + struct iovec iov = {0, }; + struct iobuf *iobuf = NULL; + struct iobref *iobref = NULL; + ssize_t xdr_size = 0; + + iobref = iobref_new (); + if (!iobref) { + goto out; + } + + if (req) { + xdr_size = xdr_sizeof (xdrproc, req); + + iobuf = iobuf_get2 (ctx->iobuf_pool, xdr_size); + if (!iobuf) { + goto out; + }; + + iobref_add (iobref, iobuf); + + iov.iov_base = iobuf->ptr; + iov.iov_len = iobuf_pagesize (iobuf); + + /* Create the xdr payload */ + ret = xdr_serialize_generic (iov, req, xdrproc); + if (ret == -1) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to create XDR payload"); + goto out; + } + iov.iov_len = ret; + count = 1; + } + + /* Send the msg */ + ret = rpc_clnt_submit (ctx->mgmt, prog, procnum, cbkfn, + &iov, count, + NULL, 0, iobref, frame, NULL, 0, NULL, 0, NULL); + +out: + if (iobref) + iobref_unref (iobref); + + if (iobuf) + iobuf_unref (iobuf); + return ret; +} + + +/* XXX: move these into @ctx */ +static char oldvolfile[131072]; +static int oldvollen = 0; + +static int +xlator_equal_rec (xlator_t *xl1, xlator_t *xl2) +{ + xlator_list_t *trav1 = NULL; + xlator_list_t *trav2 = NULL; + int ret = 0; + + if (xl1 == NULL || xl2 == NULL) { + gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); + return -1; + } + + trav1 = xl1->children; + trav2 = xl2->children; + + while (trav1 && trav2) { + ret = xlator_equal_rec (trav1->xlator, trav2->xlator); + if (ret) { + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "xlators children not equal"); + goto out; + } + + trav1 = trav1->next; + trav2 = trav2->next; + } + + if (trav1 || trav2) { + ret = -1; + goto out; + } + + if (strcmp (xl1->name, xl2->name)) { + ret = -1; + goto out; + } +out : + return ret; +} + + +static gf_boolean_t +is_graph_topology_equal (glusterfs_graph_t *graph1, + glusterfs_graph_t *graph2) +{ + xlator_t *trav1 = NULL; + xlator_t *trav2 = NULL; + gf_boolean_t ret = _gf_true; + + trav1 = graph1->first; + trav2 = graph2->first; + + ret = xlator_equal_rec (trav1, trav2); + + if (ret) { + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "graphs are not equal"); + ret = _gf_false; + goto out; + } + + ret = _gf_true; + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "graphs are equal"); + +out: + return ret; +} + + +/* Function has 3types of return value 0, -ve , 1 + * return 0 =======> reconfiguration of options has succeeded + * return 1 =======> the graph has to be reconstructed and all the xlators should be inited + * return -1(or -ve) =======> Some Internal Error occurred during the operation + */ +static int +glusterfs_volfile_reconfigure (struct glfs *fs, FILE *newvolfile_fp) +{ + glusterfs_graph_t *oldvolfile_graph = NULL; + glusterfs_graph_t *newvolfile_graph = NULL; + FILE *oldvolfile_fp = NULL; + glusterfs_ctx_t *ctx = NULL; + + int ret = -1; + + oldvolfile_fp = tmpfile (); + if (!oldvolfile_fp) + goto out; + + if (!oldvollen) { + ret = 1; // Has to call INIT for the whole graph + goto out; + } + fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp); + fflush (oldvolfile_fp); + if (ferror (oldvolfile_fp)) { + goto out; + } + + oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp); + if (!oldvolfile_graph) { + goto out; + } + + newvolfile_graph = glusterfs_graph_construct (newvolfile_fp); + if (!newvolfile_graph) { + goto out; + } + + if (!is_graph_topology_equal (oldvolfile_graph, + newvolfile_graph)) { + + ret = 1; + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "Graph topology not equal(should call INIT)"); + goto out; + } + + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "Only options have changed in the new " + "graph"); + + ctx = fs->ctx; + + if (!ctx) { + gf_log ("glfs-mgmt", GF_LOG_ERROR, + "glusterfs_ctx_get() returned NULL"); + goto out; + } + + oldvolfile_graph = ctx->active; + + if (!oldvolfile_graph) { + gf_log ("glfs-mgmt", GF_LOG_ERROR, + "glusterfs_ctx->active is NULL"); + goto out; + } + + /* */ + ret = glusterfs_graph_reconfigure (oldvolfile_graph, + newvolfile_graph); + if (ret) { + gf_log ("glfs-mgmt", GF_LOG_DEBUG, + "Could not reconfigure new options in old graph"); + goto out; + } + + ret = 0; +out: + if (oldvolfile_fp) + fclose (oldvolfile_fp); + + return ret; +} + + +int +mgmt_getspec_cbk (struct rpc_req *req, struct iovec *iov, int count, + void *myframe) +{ + gf_getspec_rsp rsp = {0,}; + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + int ret = 0; + ssize_t size = 0; + FILE *tmpfp = NULL; + struct glfs *fs = NULL; + + frame = myframe; + ctx = frame->this->ctx; + fs = ((xlator_t *)ctx->master)->private; + + if (-1 == req->rpc_status) { + ret = -1; + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_getspec_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, "XDR decoding error"); + ret = -1; + goto out; + } + + if (-1 == rsp.op_ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "failed to get the 'volume file' from server"); + ret = -1; + goto out; + } + + ret = 0; + size = rsp.op_ret; + + if (size == oldvollen && (memcmp (oldvolfile, rsp.spec, size) == 0)) { + gf_log (frame->this->name, GF_LOG_INFO, + "No change in volfile, continuing"); + goto out; + } + + tmpfp = tmpfile (); + if (!tmpfp) { + ret = -1; + goto out; + } + + fwrite (rsp.spec, size, 1, tmpfp); + fflush (tmpfp); + if (ferror (tmpfp)) { + ret = -1; + goto out; + } + + /* Check if only options have changed. No need to reload the + * volfile if topology hasn't changed. + * glusterfs_volfile_reconfigure returns 3 possible return states + * return 0 =======> reconfiguration of options has succeeded + * return 1 =======> the graph has to be reconstructed and all the xlators should be inited + * return -1(or -ve) =======> Some Internal Error occurred during the operation + */ + + ret = glusterfs_volfile_reconfigure (fs, tmpfp); + if (ret == 0) { + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "No need to re-load volfile, reconfigure done"); + oldvollen = size; + memcpy (oldvolfile, rsp.spec, size); + goto out; + } + + if (ret < 0) { + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "Reconfigure failed !!"); + goto out; + } + + ret = glfs_process_volfp (fs, tmpfp); + /* tmpfp closed */ + tmpfp = NULL; + if (ret) + goto out; + + oldvollen = size; + memcpy (oldvolfile, rsp.spec, size); + +out: + STACK_DESTROY (frame->root); + + if (rsp.spec) + free (rsp.spec); + + if (ret && ctx && !ctx->active) { + /* Do it only for the first time */ + /* Failed to get the volume file, something wrong, + restart the process */ + gf_log ("glfs-mgmt", GF_LOG_ERROR, + "failed to fetch volume file (key:%s)", + ctx->cmd_args.volfile_id); + } + + if (tmpfp) + fclose (tmpfp); + + return 0; +} + + +int +glfs_volfile_fetch (struct glfs *fs) +{ + cmd_args_t *cmd_args = NULL; + gf_getspec_req req = {0, }; + int ret = 0; + call_frame_t *frame = NULL; + glusterfs_ctx_t *ctx = NULL; + + ctx = fs->ctx; + cmd_args = &ctx->cmd_args; + + frame = create_frame (THIS, ctx->pool); + + req.key = cmd_args->volfile_id; + req.flags = 0; + + ret = mgmt_submit_request (&req, frame, ctx, &clnt_handshake_prog, + GF_HNDSK_GETSPEC, mgmt_getspec_cbk, + (xdrproc_t)xdr_gf_getspec_req); + return ret; +} + + +static int +mgmt_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, + void *data) +{ + xlator_t *this = NULL; + cmd_args_t *cmd_args = NULL; + glusterfs_ctx_t *ctx = NULL; + struct glfs *fs = NULL; + int ret = 0; + + this = mydata; + ctx = this->ctx; + fs = ((xlator_t *)ctx->master)->private; + cmd_args = &ctx->cmd_args; + + switch (event) { + case RPC_CLNT_DISCONNECT: + if (!ctx->active) { + cmd_args->max_connect_attempts--; + gf_log ("glfs-mgmt", GF_LOG_ERROR, + "failed to connect with remote-host: %s", + strerror (errno)); + gf_log ("glfs-mgmt", GF_LOG_INFO, + "%d connect attempts left", + cmd_args->max_connect_attempts); + if (0 >= cmd_args->max_connect_attempts) + glfs_init_done (fs, -1); + break; + } + break; + case RPC_CLNT_CONNECT: + rpc_clnt_set_connected (&((struct rpc_clnt*)ctx->mgmt)->conn); + + ret = glfs_volfile_fetch (fs); + if (ret && ctx && (ctx->active == NULL)) { + /* Do it only for the first time */ + /* Exit the process.. there is some wrong options */ + gf_log ("glfs-mgmt", GF_LOG_ERROR, + "failed to fetch volume file (key:%s)", + ctx->cmd_args.volfile_id); + glfs_init_done (fs, -1); + } + + break; + default: + break; + } + + return 0; +} + + +int +glusterfs_mgmt_notify (int32_t op, void *data, ...) +{ + int ret = 0; + + switch (op) + { + case GF_EN_DEFRAG_STATUS: + break; + + default: + break; + } + + return ret; +} + + +int +glfs_mgmt_init (struct glfs *fs) +{ + cmd_args_t *cmd_args = NULL; + struct rpc_clnt *rpc = NULL; + dict_t *options = NULL; + int ret = -1; + int port = GF_DEFAULT_BASE_PORT; + char *host = NULL; + glusterfs_ctx_t *ctx = NULL; + + ctx = fs->ctx; + cmd_args = &ctx->cmd_args; + + if (ctx->mgmt) + return 0; + + if (cmd_args->volfile_server_port) + port = cmd_args->volfile_server_port; + + host = "localhost"; + if (cmd_args->volfile_server) + host = cmd_args->volfile_server; + + ret = rpc_transport_inet_options_build (&options, host, port); + if (ret) + goto out; + + rpc = rpc_clnt_new (options, THIS->ctx, THIS->name, 8); + if (!rpc) { + ret = -1; + gf_log (THIS->name, GF_LOG_WARNING, + "failed to create rpc clnt"); + goto out; + } + + ret = rpc_clnt_register_notify (rpc, mgmt_rpc_notify, THIS); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to register notify function"); + goto out; + } + + ret = rpcclnt_cbk_program_register (rpc, &mgmt_cbk_prog, THIS); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to register callback function"); + goto out; + } + + ctx->notify = glusterfs_mgmt_notify; + + /* This value should be set before doing the 'rpc_clnt_start()' as + the notify function uses this variable */ + ctx->mgmt = rpc; + + ret = rpc_clnt_start (rpc); +out: + return ret; +} + diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c new file mode 100644 index 00000000..c03c4154 --- /dev/null +++ b/api/src/glfs-resolve.c @@ -0,0 +1,244 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#include +#include +#include +#include +#include +#include + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "logging.h" +#include "stack.h" +#include "event.h" +#include "glfs-mem-types.h" +#include "common-utils.h" +#include "syncop.h" +#include "call-stub.h" + +#include "glfs-internal.h" + + +void +glfs_first_lookup (xlator_t *subvol) +{ + loc_t loc = {0, }; + int ret = -1; + + loc.inode = subvol->itable->root; + memset (loc.gfid, 0, 16); + loc.gfid[15] = 1; + loc.path = "/"; + loc.name = ""; + + ret = syncop_lookup (subvol, &loc, 0, 0, 0, 0); + + gf_log (subvol->name, GF_LOG_DEBUG, "first lookup complete %d", ret); + + return; +} + + +int +glfs_loc_touchup (loc_t *loc) +{ + char *path = NULL; + int ret = -1; + char *bn = NULL; + + ret = inode_path (loc->parent, loc->name, &path); + + loc->path = path; + + if (ret < 0 || !path) { + ret = -1; + errno = ENOMEM; + goto out; + } + + bn = strrchr (path, '/'); + if (bn) + bn++; + loc->name = bn; + ret = 0; +out: + return ret; +} + + +inode_t * +glfs_resolve_component (struct glfs *fs, xlator_t *subvol, inode_t *parent, + const char *component, struct iatt *iatt) +{ + loc_t loc = {0, }; + inode_t *inode = NULL; + int reval = 0; + int ret = -1; + int glret = -1; + struct iatt ciatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + + loc.name = component; + + loc.parent = inode_ref (parent); + uuid_copy (loc.pargfid, parent->gfid); + + xattr_req = dict_new (); + if (!xattr_req) { + errno = ENOMEM; + goto out; + } + + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + errno = ENOMEM; + goto out; + } + + loc.inode = inode_grep (parent->table, parent, component); + + if (loc.inode) { + uuid_copy (loc.gfid, loc.inode->gfid); + reval = 1; + } else { + uuid_generate (gfid); + loc.inode = inode_new (parent->table); + } + + if (!loc.inode) + goto out; + + + glret = glfs_loc_touchup (&loc); + if (glret < 0) { + ret = -1; + goto out; + } + + ret = syncop_lookup (subvol, &loc, xattr_req, &ciatt, NULL, NULL); + if (ret && reval) { + inode_unref (loc.inode); + loc.inode = inode_new (parent->table); + if (!loc.inode) + goto out; + uuid_generate (gfid); + ret = syncop_lookup (subvol, &loc, xattr_req, &ciatt, + NULL, NULL); + } + if (ret) + goto out; + + inode = inode_link (loc.inode, loc.parent, component, &ciatt); + if (inode) + inode_lookup (inode); + if (iatt) + *iatt = ciatt; +out: + if (xattr_req) + dict_destroy (xattr_req); + + loc_wipe (&loc); + + return inode; +} + + +int +glfs_resolve (struct glfs *fs, xlator_t *subvol, const char *origpath, + loc_t *loc, struct iatt *iatt) +{ + inode_t *inode = NULL; + inode_t *parent = NULL; + char *saveptr = NULL; + char *path = NULL; + char *component = NULL; + char *next_component = NULL; + int ret = -1; + struct iatt ciatt = {0, }; + + path = gf_strdup (origpath); + if (!path) { + errno = ENOMEM; + return -1; + } + + parent = NULL; + inode = inode_ref (subvol->itable->root); + + for (component = strtok_r (path, "/", &saveptr); + component; component = next_component) { + + next_component = strtok_r (NULL, "/", &saveptr); + + if (parent) + inode_unref (parent); + + parent = inode; + + inode = glfs_resolve_component (fs, subvol, parent, + component, &ciatt); + if (!inode) + break; + + if (!next_component) + break; + + if (!IA_ISDIR (ciatt.ia_type)) { + /* next_component exists and this component is + not a directory + */ + inode_unref (inode); + inode = NULL; + ret = -1; + errno = ENOTDIR; + break; + } + } + + if (parent && next_component) + /* resolution failed mid-way */ + goto out; + + /* At this point, all components up to the last parent directory + have been resolved successfully (@parent). Resolution of basename + might have failed (@inode) if at all. + */ + + loc->parent = parent; + if (parent) { + uuid_copy (loc->pargfid, parent->gfid); + loc->name = component; + } + + loc->inode = inode; + if (inode) { + uuid_copy (loc->gfid, inode->gfid); + if (iatt) + *iatt = ciatt; + ret = 0; + } + + glfs_loc_touchup (loc); +out: + GF_FREE (path); + + /* do NOT loc_wipe here as only last component might be missing */ + + return ret; +} + diff --git a/api/src/glfs.c b/api/src/glfs.c new file mode 100644 index 00000000..830efb23 --- /dev/null +++ b/api/src/glfs.c @@ -0,0 +1,546 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +/* + TODO: + - set proper pid/lk_owner to call frames (currently buried in syncop) + - fix logging.c/h to store logfp and loglevel in glusterfs_ctx_t and + reach it via THIS. + - fd migration on graph switch. + - update syncop functions to accept/return xdata. ??? + - syncop_readv to not touch params if args.op_ret < 0. + - protocol/client to reconnect immediately after portmap disconnect. + - handle SEEK_END failure in _lseek() + - handle umask (per filesystem?) + - implement glfs_set_xlator_option(), like --xlator-option + - make itables LRU based + - implement glfs_fini() + - modify syncop_fsync() to accept 'dataonly' flag + - 0-copy for readv/writev +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "logging.h" +#include "stack.h" +#include "event.h" +#include "glfs-mem-types.h" +#include "common-utils.h" +#include "syncop.h" +#include "call-stub.h" + +#include "glfs.h" +#include "glfs-internal.h" + + +static gf_boolean_t +vol_assigned (cmd_args_t *args) +{ + return args->volfile || args->volfile_server; +} + + +static int +glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) +{ + call_pool_t *pool = NULL; + int ret = -1; + cmd_args_t *cmd_args = NULL; + + xlator_mem_acct_init (THIS, glfs_mt_end); + + cmd_args = &ctx->cmd_args; + + ctx->process_uuid = generate_glusterfs_ctx_id (); + if (!ctx->process_uuid) { + goto err; + } + + ctx->page_size = 128 * GF_UNIT_KB; + + ctx->iobuf_pool = iobuf_pool_new (); + if (!ctx->iobuf_pool) { + goto err; + } + + ctx->event_pool = event_pool_new (DEFAULT_EVENT_POOL_SIZE); + if (!ctx->event_pool) { + goto err; + } + + ctx->env = syncenv_new (0); + if (!ctx->env) { + goto err; + } + + pool = GF_CALLOC (1, sizeof (call_pool_t), + glfs_mt_call_pool_t); + if (!pool) { + goto err; + } + + /* frame_mem_pool size 112 * 4k */ + pool->frame_mem_pool = mem_pool_new (call_frame_t, 4096); + if (!pool->frame_mem_pool) { + goto err; + } + /* stack_mem_pool size 256 * 1024 */ + pool->stack_mem_pool = mem_pool_new (call_stack_t, 1024); + if (!pool->stack_mem_pool) { + goto err; + } + + ctx->stub_mem_pool = mem_pool_new (call_stub_t, 1024); + if (!ctx->stub_mem_pool) { + goto err; + } + + ctx->dict_pool = mem_pool_new (dict_t, GF_MEMPOOL_COUNT_OF_DICT_T); + if (!ctx->dict_pool) + goto err; + + ctx->dict_pair_pool = mem_pool_new (data_pair_t, + GF_MEMPOOL_COUNT_OF_DATA_PAIR_T); + if (!ctx->dict_pair_pool) + goto err; + + ctx->dict_data_pool = mem_pool_new (data_t, GF_MEMPOOL_COUNT_OF_DATA_T); + if (!ctx->dict_data_pool) + goto err; + + INIT_LIST_HEAD (&pool->all_frames); + INIT_LIST_HEAD (&ctx->cmd_args.xlator_options); + LOCK_INIT (&pool->lock); + ctx->pool = pool; + + pthread_mutex_init (&(ctx->lock), NULL); + + ret = 0; +err: + if (ret && pool) { + if (pool->frame_mem_pool) + mem_pool_destroy (pool->frame_mem_pool); + if (pool->stack_mem_pool) + mem_pool_destroy (pool->stack_mem_pool); + GF_FREE (pool); + } + + if (ret && ctx) { + if (ctx->stub_mem_pool) + mem_pool_destroy (ctx->stub_mem_pool); + if (ctx->dict_pool) + mem_pool_destroy (ctx->dict_pool); + if (ctx->dict_data_pool) + mem_pool_destroy (ctx->dict_data_pool); + if (ctx->dict_pair_pool) + mem_pool_destroy (ctx->dict_pair_pool); + } + + return ret; +} + + +static int +create_master (struct glfs *fs) +{ + int ret = 0; + xlator_t *master = NULL; + + master = GF_CALLOC (1, sizeof (*master), + glfs_mt_xlator_t); + if (!master) + goto err; + + master->name = gf_strdup ("gfapi"); + if (!master->name) + goto err; + + if (xlator_set_type (master, "mount/api") == -1) { + gf_log ("glfs", GF_LOG_ERROR, + "master xlator for %s initialization failed", + fs->volname); + goto err; + } + + master->ctx = fs->ctx; + master->private = fs; + master->options = get_new_dict (); + if (!master->options) + goto err; + + + ret = xlator_init (master); + if (ret) { + gf_log ("glfs", GF_LOG_ERROR, + "failed to initialize gfapi translator"); + goto err; + } + + fs->ctx->master = master; + THIS = master; + + return 0; + +err: + if (master) { + xlator_destroy (master); + } + + return -1; +} + + +static FILE * +get_volfp (struct glfs *fs) +{ + int ret = 0; + cmd_args_t *cmd_args = NULL; + FILE *specfp = NULL; + struct stat statbuf; + + cmd_args = &fs->ctx->cmd_args; + + ret = lstat (cmd_args->volfile, &statbuf); + if (ret == -1) { + gf_log ("glfs", GF_LOG_ERROR, + "%s: %s", cmd_args->volfile, strerror (errno)); + return NULL; + } + + if ((specfp = fopen (cmd_args->volfile, "r")) == NULL) { + gf_log ("glfs", GF_LOG_ERROR, + "volume file %s: %s", + cmd_args->volfile, + strerror (errno)); + return NULL; + } + + gf_log ("glfs", GF_LOG_DEBUG, + "loading volume file %s", cmd_args->volfile); + + return specfp; +} + + +int +glfs_volumes_init (struct glfs *fs) +{ + FILE *fp = NULL; + cmd_args_t *cmd_args = NULL; + int ret = 0; + + cmd_args = &fs->ctx->cmd_args; + + if (!vol_assigned (cmd_args)) + return -1; + + if (cmd_args->volfile_server) { + ret = glfs_mgmt_init (fs); + goto out; + } + + fp = get_volfp (fs); + + if (!fp) { + gf_log ("glfs", GF_LOG_ERROR, + "Cannot reach volume specification file"); + ret = -1; + goto out; + } + + ret = glfs_process_volfp (fs, fp); + if (ret) + goto out; + +out: + return ret; +} + + +/////////////////////////////////////////////////////////////////////////////// + + +struct glfs * +glfs_from_glfd (struct glfs_fd *glfd) +{ + return ((xlator_t *)glfd->fd->inode->table->xl->ctx->master)->private; +} + + +void +glfs_fd_destroy (struct glfs_fd *glfd) +{ + if (!glfd) + return; + if (glfd->fd) + fd_unref (glfd->fd); + GF_FREE (glfd); +} + + +xlator_t * +glfs_fd_subvol (struct glfs_fd *glfd) +{ + xlator_t *subvol = NULL; + + if (!glfd) + return NULL; + + subvol = glfd->fd->inode->table->xl; + + return subvol; +} + + +xlator_t * +glfs_active_subvol (struct glfs *fs) +{ + xlator_t *subvol = NULL; + inode_table_t *itable = NULL; + + pthread_mutex_lock (&fs->mutex); + { + while (!fs->init) + pthread_cond_wait (&fs->cond, &fs->mutex); + + subvol = fs->active_subvol; + } + pthread_mutex_unlock (&fs->mutex); + + if (!subvol) + return NULL; + + if (!subvol->itable) { + itable = inode_table_new (0, subvol); + if (!itable) { + errno = ENOMEM; + return NULL; + } + + subvol->itable = itable; + + glfs_first_lookup (subvol); + } + + return subvol; +} + + +static void * +glfs_poller (void *data) +{ + struct glfs *fs = NULL; + + fs = data; + + event_dispatch (fs->ctx->event_pool); + + return NULL; +} + + +struct glfs * +glfs_new (const char *volname) +{ + struct glfs *fs = NULL; + int ret = -1; + glusterfs_ctx_t *ctx = NULL; + + /* first globals init, for gf_mem_acct_enable_set () */ + ret = glusterfs_globals_init (); + if (ret) + return NULL; + + ctx = glusterfs_ctx_new (); + if (!ctx) { + return NULL; + } + THIS->ctx = ctx; + + /* then ctx_defaults_init, for xlator_mem_acct_init(THIS) */ + ret = glusterfs_ctx_defaults_init (ctx); + if (ret) + return NULL; + + fs = GF_CALLOC (1, sizeof (*fs), glfs_mt_glfs_t); + if (!fs) + return NULL; + fs->ctx = ctx; + + glfs_set_logging (fs, "/dev/null", 0); + + fs->ctx->cmd_args.volfile_id = gf_strdup (volname); + + fs->volname = gf_strdup (volname); + + pthread_mutex_init (&fs->mutex, NULL); + pthread_cond_init (&fs->cond, NULL); + + return fs; +} + + +int +glfs_set_volfile (struct glfs *fs, const char *volfile) +{ + cmd_args_t *cmd_args = NULL; + + cmd_args = &fs->ctx->cmd_args; + + if (vol_assigned (cmd_args)) + return -1; + + cmd_args->volfile = gf_strdup (volfile); + + return 0; +} + + +int +glfs_set_volfile_server (struct glfs *fs, const char *transport, + const char *host, int port) +{ + cmd_args_t *cmd_args = NULL; + + cmd_args = &fs->ctx->cmd_args; + + if (vol_assigned (cmd_args)) + return -1; + + cmd_args->volfile_server = gf_strdup (host); + cmd_args->volfile_server_transport = gf_strdup (transport); + cmd_args->max_connect_attempts = 2; + + return 0; +} + + +int +glfs_set_logging (struct glfs *fs, const char *logfile, int loglevel) +{ + int ret = -1; + + ret = gf_log_init (logfile); + if (ret) + return ret; + + gf_log_set_loglevel (loglevel); + + return ret; +} + + +int +glfs_init_wait (struct glfs *fs) +{ + int ret = -1; + + pthread_mutex_lock (&fs->mutex); + { + while (!fs->init) + pthread_cond_wait (&fs->cond, + &fs->mutex); + ret = fs->ret; + } + pthread_mutex_unlock (&fs->mutex); + + return ret; +} + + +void +glfs_init_done (struct glfs *fs, int ret) +{ + if (fs->init_cbk) { + fs->init_cbk (fs, ret); + return; + } + + pthread_mutex_lock (&fs->mutex); + { + fs->init = 1; + fs->ret = ret; + + pthread_cond_broadcast (&fs->cond); + } + pthread_mutex_unlock (&fs->mutex); +} + + +int +glfs_init_common (struct glfs *fs) +{ + int ret = -1; + + ret = create_master (fs); + if (ret) + return ret; + + ret = pthread_create (&fs->poller, NULL, glfs_poller, fs); + if (ret) + return ret; + + ret = glfs_volumes_init (fs); + if (ret) + return ret; + + return ret; +} + + +int +glfs_init_async (struct glfs *fs, glfs_init_cbk cbk) +{ + int ret = -1; + + fs->init_cbk = cbk; + + ret = glfs_init_common (fs); + + return ret; +} + + +int +glfs_init (struct glfs *fs) +{ + int ret = -1; + + ret = glfs_init_common (fs); + if (ret) + return ret; + + ret = glfs_init_wait (fs); + + return ret; +} + + +int +glfs_fini (struct glfs *fs) +{ + int ret = -1; + + return ret; +} diff --git a/api/src/glfs.h b/api/src/glfs.h new file mode 100644 index 00000000..14d41356 --- /dev/null +++ b/api/src/glfs.h @@ -0,0 +1,366 @@ +/* + Copyright (c) 2012 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#ifndef _GLFS_H +#define _GLFS_H + +/* + Enforce the following flags as libgfapi is built + with them, and we want programs linking against them to also + be built with these flags. This is necessary as it affects + some of the structures defined in libc headers (like struct stat) + and those definitions need to be consistently compiled in + both the library and the application. +*/ + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#ifndef __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET64 +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +/* The filesystem object. One object per 'virtual mount' */ +struct glfs; +typedef struct glfs glfs_t; + + +/* + SYNOPSIS + + glfs_new: Create a new 'virtual mount' object. + + DESCRIPTION + + This is most likely the very first function you will use. This function + will create a new glfs_t (virtual mount) object in memory. + + On this newly created glfs_t, you need to be either set a volfile path + (glfs_set_volfile) or a volfile server (glfs_set_volfile_server). + + The glfs_t object needs to be initialized with glfs_init() before you + can start issuing file operations on it. + + PARAMETERS + + @volname: Name of the volume. This identifies the server-side volume and + the fetched volfile (equivalent of --volfile-id command line + parameter to glusterfsd). When used with glfs_set_volfile() the + @volname has no effect (except for appearing in log messages). + + RETURN VALUES + + NULL : Out of memory condition. + Others : Pointer to the newly created glfs_t virtual mount object. + +*/ + +glfs_t *glfs_new (const char *volname); + + +/* + SYNOPSIS + + glfs_set_volfile: Specify the path to the volume specification file. + + DESCRIPTION + + If you are using a static volume specification file (without dynamic + volume management abilities from the CLI), then specify the path to + the volume specification file. + + This is incompatible with glfs_set_volfile_server(). + + PARAMETERS + + @fs: The 'virtual mount' object to be configured with the volume + specification file. + + @volfile: Path to the locally available volume specification file. + + RETURN VALUES + + 0 : Success. + -1 : Failure. @errno will be set with the type of failure. + +*/ + +int glfs_set_volfile (glfs_t *fs, const char *volfile); + + +/* + SYNOPSIS + + glfs_set_volfile_server: Specify the address of management server. + + DESCRIPTION + + This function specifies the address of the management server (glusterd) + to connect, and establish the volume configuration. The @volname + parameter passed to glfs_new() is the volume which will be virtually + mounted as the glfs_t object. All operations performed by the CLI at + the management server will automatically be reflected in the 'virtual + mount' object as it maintains a connection to glusterd and polls on + configuration change notifications. + + This is incompatible with glfs_set_volfile(). + + PARAMETERS + + @fs: The 'virtual mount' object to be configured with the volume + specification file. + + @transport: String specifying the transport used to connect to the + management daemon. Specifying NULL will result in the usage + of the default (socket) transport type. Permitted values + are those what you specify as transport-type in a volume + specification file (e.g "socket", "rdma", "unix".) + + @host: String specifying the address of where to find the management + daemon. Depending on the transport type this would either be + an FQDN (e.g: "storage01.company.com"), ASCII encoded IP + address "192.168.22.1", or a UNIX domain socket path (e.g + "/tmp/glusterd.socket".) + + @port: The TCP port number where gluster management daemon is listening. + Specifying 0 uses the default port number GF_DEFAULT_BASE_PORT. + This parameter is unused if you are using a UNIX domain socket. + + RETURN VALUES + + 0 : Success. + -1 : Failure. @errno will be set with the type of failure. + +*/ + +int glfs_set_volfile_server (glfs_t *fs, const char *transport, + const char *host, int port); + + +/* + SYNOPSIS + + glfs_set_logging: Specify logging parameters. + + DESCRIPTION + + This function specifies logging parameters for the virtual mount. + Default log file is /dev/null. + + PARAMETERS + + @fs: The 'virtual mount' object to be configured with the logging parameters. + + @logfile: The logfile to be used for logging. Will be created if it does not + already exist (provided system permissions allow.) + + @loglevel: Numerical value specifying the degree of verbosity. Higher the + value, more verbose the logging. + + RETURN VALUES + + 0 : Success. + -1 : Failure. @errno will be set with the type of failure. + +*/ + +int glfs_set_logging (glfs_t *fs, const char *logfile, int loglevel); + + +/* + SYNOPSIS + + glfs_init: Initialize the 'virtual mount' + + DESCRIPTION + + This function initializes the glfs_t object. This consists of many steps: + - Spawn a poll-loop thread. + - Establish connection to management daemon and receive volume specification. + - Construct translator graph and initialize graph. + - Wait for initialization (connecting to all bricks) to complete. + + PARAMETERS + + @fs: The 'virtual mount' object to be initialized. + + RETURN VALUES + + 0 : Success. + -1 : Failure. @errno will be set with the type of failure. + +*/ + +int glfs_init (glfs_t *fs); + + +int glfs_fini (glfs_t *fs); + +/* + * FILE OPERATION + * + * What follows are filesystem operations performed on the + * 'virtual mount'. The calls here are kept as close to + * the POSIX system calls as possible. + * + * Notes: + * + * - All paths specified, even if absolute, are relative to the + * root of the virtual mount and not the system root (/). + * + */ + +/* The file descriptor object. One per open file/directory. */ + +struct glfs_fd; +typedef struct glfs_fd glfs_fd_t; + + +/* + SYNOPSIS + + glfs_open: Open a file. + + DESCRIPTION + + This function opens a file on a virtual mount. + + PARAMETERS + + @fs: The 'virtual mount' object to be initialized. + + @path: Path of the file within the virtual mount. + + @flags: Open flags. See open(2). O_CREAT is not supported. + Use glfs_creat() for creating files. + + RETURN VALUES + + NULL : Failure. @errno will be set with the type of failure. + Others : Pointer to the opened glfs_fd_t. + + */ + +glfs_fd_t *glfs_open (glfs_t *fs, const char *path, int flags); + + +/* + SYNOPSIS + + glfs_creat: Create a file. + + DESCRIPTION + + This function opens a file on a virtual mount. + + PARAMETERS + + @fs: The 'virtual mount' object to be initialized. + + @path: Path of the file within the virtual mount. + + @mode: Permission of the file to be created. + + @flags: Create flags. See open(2). O_EXCL is supported. + + RETURN VALUES + + NULL : Failure. @errno will be set with the type of failure. + Others : Pointer to the opened glfs_fd_t. + + */ + +glfs_fd_t *glfs_creat (glfs_t *fs, const char *path, int flags, + mode_t mode); + +int glfs_close (glfs_fd_t *fd); + +glfs_t *glfs_from_glfd (glfs_fd_t *fd); + +typedef void (*glfs_io_cbk) (glfs_fd_t *fd, ssize_t ret, void *data); + +// glfs_{read,write}[_async] + +ssize_t glfs_read (glfs_fd_t *fd, void *buf, size_t count, int flags); +ssize_t glfs_write (glfs_fd_t *fd, const void *buf, size_t count, int flags); +int glfs_read_async (glfs_fd_t *fd, void *buf, size_t count, int flags, + glfs_io_cbk fn, void *data); +int glfs_write_async (glfs_fd_t *fd, const void *buf, size_t count, int flags, + glfs_io_cbk fn, void *data); + +// glfs_{read,write}v[_async] + +ssize_t glfs_readv (glfs_fd_t *fd, const struct iovec *iov, int iovcnt, + int flags); +ssize_t glfs_writev (glfs_fd_t *fd, const struct iovec *iov, int iovcnt, + int flags); +int glfs_readv_async (glfs_fd_t *fd, const struct iovec *iov, int count, + int flags, glfs_io_cbk fn, void *data); +int glfs_writev_async (glfs_fd_t *fd, const struct iovec *iov, int count, + int flags, glfs_io_cbk fn, void *data); + +// glfs_p{read,write}[_async] + +ssize_t glfs_pread (glfs_fd_t *fd, void *buf, size_t count, off_t offset, + int flags); +ssize_t glfs_pwrite (glfs_fd_t *fd, const void *buf, size_t count, + off_t offset, int flags); +int glfs_pread_async (glfs_fd_t *fd, void *buf, size_t count, off_t offset, + int flags, glfs_io_cbk fn, void *data); +int glfs_pwrite_async (glfs_fd_t *fd, const void *buf, int count, off_t offset, + int flags, glfs_io_cbk fn, void *data); + +// glfs_p{read,write}v[_async] + +ssize_t glfs_preadv (glfs_fd_t *fd, const struct iovec *iov, int iovcnt, + off_t offset, int flags); +ssize_t glfs_pwritev (glfs_fd_t *fd, const struct iovec *iov, int iovcnt, + off_t offset, int flags); +int glfs_preadv_async (glfs_fd_t *fd, const struct iovec *iov, int count, + off_t offset, int flags, glfs_io_cbk fn, void *data); +int glfs_pwritev_async (glfs_fd_t *fd, const struct iovec *iov, int count, + off_t offset, int flags, glfs_io_cbk fn, void *data); + + +off_t glfs_lseek (glfs_fd_t *fd, off_t offset, int whence); + +int glfs_truncate (glfs_t *fs, const char *path, off_t length); + +int glfs_ftruncate (glfs_fd_t *fd, off_t length); +int glfs_ftruncate_async (glfs_fd_t *fd, off_t length, glfs_io_cbk fn, + void *data); + +int glfs_lstat (glfs_t *fs, const char *path, struct stat *buf); +int glfs_fstat (glfs_fd_t *fd, struct stat *buf); + +int glfs_fsync (glfs_fd_t *fd); +int glfs_fsync_async (glfs_fd_t *fd, glfs_io_cbk fn, void *data); + +int glfs_fdatasync (glfs_fd_t *fd); +int glfs_fdatasync_async (glfs_fd_t *fd, glfs_io_cbk fn, void *data); + +__END_DECLS + +#endif /* !_GLFS_H */ diff --git a/configure.ac b/configure.ac index 4214a078..0b07c6c1 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,8 @@ AC_CONFIG_FILES([Makefile xlators/mgmt/Makefile xlators/mgmt/glusterd/Makefile xlators/mgmt/glusterd/src/Makefile + api/Makefile + api/src/Makefile glusterfs.spec]) AC_CANONICAL_HOST -- cgit