diff options
author | R.Shyamsundar <srangana@redhat.com> | 2013-09-16 16:39:24 +0530 |
---|---|---|
committer | Anand Avati <avati@redhat.com> | 2013-10-11 12:16:46 -0700 |
commit | d573f170cf3305c066f8b191f872d2d2f22f2025 (patch) | |
tree | 51debc2bc323f4347482c0bfcda919cff5182b1f /api/src | |
parent | d3558ae5c4b1cf6909e27e8fabd6ec44fe6aa971 (diff) |
gfapi: object handle based API extensions
There is an ongoing effort to integrate NFS Ganesha (
https://github.com/nfs-ganesha/nfs-ganesha/wiki ) with GlusterFS as one of
the file system back ends.
Towards this we need extensions to gfapi that can handle object based
operations. Meaning, instead of using full paths or relative paths from
cwd, it is required that we can work with APIs, like the *at POSIX
variants, to be able to create, lookup, open etc. files and directories.
Hence the objects are the files or directories themselves and we give out
handles to these objects that can be used for further operations.
This code drop is an initial implementation of the proposed APIs.
The new APIs are implemented as glfs_h_XXX variants in the file
glfs-handleops.c to mirror glfs-fops.c style. The code leverages holding
onto inode references and doling these out as opaque/cookie type objects to
the callers, to enable them to be used as handles in other operations.
An fd based approach was considered, but due to the extra footprint that
the fd structure and its counterparts would incur, this was dropped to take
the approach of holding inode references themselves.
Tested by extending glfsxmp.c to invoke and exercise the added APIs, and
further tested with a reference integration of the same as an FSAL with NFS
Ganesha.
Change-Id: I23629c99e905b54070fa2e6565147812e5f3fa5d
BUG: 1016000
Signed-off-by: R.Shyamsundar <srangana@redhat.com>
Reviewed-on: http://review.gluster.org/5936
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'api/src')
-rw-r--r-- | api/src/Makefile.am | 5 | ||||
-rw-r--r-- | api/src/glfs-fops.c | 18 | ||||
-rw-r--r-- | api/src/glfs-handleops.c | 1278 | ||||
-rw-r--r-- | api/src/glfs-handles.h | 143 | ||||
-rw-r--r-- | api/src/glfs-internal.h | 59 | ||||
-rw-r--r-- | api/src/glfs-mem-types.h | 3 | ||||
-rw-r--r-- | api/src/glfs-resolve.c | 67 | ||||
-rw-r--r-- | api/src/glfs.c | 14 | ||||
-rw-r--r-- | api/src/glfs.h | 26 |
9 files changed, 1593 insertions, 20 deletions
diff --git a/api/src/Makefile.am b/api/src/Makefile.am index 0782435e065..7c5df3e2029 100644 --- a/api/src/Makefile.am +++ b/api/src/Makefile.am @@ -1,9 +1,10 @@ lib_LTLIBRARIES = libgfapi.la noinst_HEADERS = glfs-mem-types.h glfs-internal.h -libgfapi_HEADERS = glfs.h +libgfapi_HEADERS = glfs.h glfs-handles.h libgfapidir = $(includedir)/glusterfs/api -libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c +libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c \ + glfs-handleops.c libgfapi_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ $(top_builddir)/rpc/xdr/src/libgfxdr.la \ diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 8119cc4f693..9070661b99e 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -14,20 +14,8 @@ #include "syncop.h" #include "glfs.h" -#define DEFAULT_REVAL_COUNT 1 -#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \ - if (ret == -1 && errno == ESTALE) { \ - if (reval < DEFAULT_REVAL_COUNT) { \ - reval++; \ - loc_wipe (loc); \ - goto label; \ - } \ - } \ - } while (0) - - -static int +int glfs_loc_link (loc_t *loc, struct iatt *iatt) { int ret = -1; @@ -52,7 +40,7 @@ glfs_loc_link (loc_t *loc, struct iatt *iatt) } -static void +void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat) { iatt_to_stat (iatt, stat); @@ -60,7 +48,7 @@ glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat) } -static int +int glfs_loc_unlink (loc_t *loc) { inode_unlink (loc->inode, loc->parent, loc->name); diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c new file mode 100644 index 00000000000..9c707a619a5 --- /dev/null +++ b/api/src/glfs-handleops.c @@ -0,0 +1,1278 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + * 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" +#include "glfs-handles.h" + +static void +glfs_iatt_from_stat (struct stat *stat, int valid, struct iatt *iatt, + int *glvalid) +{ + /* validate in args */ + if ((stat == NULL) || (iatt == NULL) || (glvalid == NULL)) { + errno = EINVAL; + return; + } + + *glvalid = 0; + + if (valid & GFAPI_SET_ATTR_MODE) { + iatt->ia_prot = ia_prot_from_st_mode (stat->st_mode); + *glvalid |= GF_SET_ATTR_MODE; + } + + if (valid & GFAPI_SET_ATTR_UID) { + iatt->ia_uid = stat->st_uid; + *glvalid |= GF_SET_ATTR_UID; + } + + if (valid & GFAPI_SET_ATTR_GID) { + iatt->ia_gid = stat->st_gid; + *glvalid |= GF_SET_ATTR_GID; + } + + if (valid & GFAPI_SET_ATTR_ATIME) { + iatt->ia_atime = stat->st_atime; + iatt->ia_atime_nsec = ST_ATIM_NSEC (stat); + *glvalid |= GF_SET_ATTR_ATIME; + } + + if (valid & GFAPI_SET_ATTR_MTIME) { + iatt->ia_mtime = stat->st_mtime; + iatt->ia_mtime_nsec = ST_MTIM_NSEC (stat); + *glvalid |= GF_SET_ATTR_MTIME; + } + + return; +} + +struct glfs_object * +glfs_h_lookupat (struct glfs *fs, struct glfs_object *parent, + const char *path, struct stat *stat) +{ + int ret = 0; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + struct iatt iatt = {0, }; + struct glfs_object *object = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + if (parent) { + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + } + + /* fop/op */ + ret = glfs_resolve_at (fs, subvol, inode, path, &loc, &iatt, + 0 /*TODO: links? */, 0); + + /* populate out args */ + if (!ret) { + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_stat (struct glfs *fs, struct glfs_object *object, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_stat (subvol, &loc, &iatt); + + /* populate out args */ + if (!ret && stat) { + glfs_iatt_to_stat (fs, &iatt, stat); + } +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_getattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat) +{ + int ret = 0; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + struct iatt iatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* fop/op */ + ret = glfs_resolve_base (fs, subvol, inode, &iatt); + + /* populate out args */ + if (!ret && stat) { + glfs_iatt_to_stat (fs, &iatt, stat); + } + +out: + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_setattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat, + int valid) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + int glvalid = 0; + + /* validate in args */ + if ((fs == NULL) || (object == NULL) || (stat == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* map valid masks from in args */ + glfs_iatt_from_stat (stat, valid, &iatt, &glvalid); + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_setattr (subvol, &loc, &iatt, glvalid, 0, 0); +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_fd * +glfs_h_open (struct glfs *fs, struct glfs_object *object, int flags) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* check types to open */ + if (IA_ISDIR (inode->ia_type)) { + ret = -1; + errno = EISDIR; + goto out; + } + + if (!IA_ISREG (inode->ia_type)) { + ret = -1; + errno = EINVAL; + goto out; + } + + glfd = glfs_fd_new (fs); + if (!glfd) { + errno = ENOMEM; + goto out; + } + + glfd->fd = fd_create (inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_open (subvol, &loc, flags, glfd->fd); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } else { + glfd->fd->flags = flags; + fd_bind (glfd->fd); + glfs_fd_bind (glfd); + } + + glfs_subvol_done (fs, subvol); + + return glfd; +} + +struct glfs_object * +glfs_h_creat (struct glfs *fs, struct glfs_object *parent, const char *path, + int flags, mode_t mode, struct stat *stat) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + 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; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + glfd = glfs_fd_new (fs); + if (!glfd) + goto out; + + glfd->fd = fd_create (loc.inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + /* fop/op */ + ret = syncop_create (subvol, &loc, flags, mode, glfd->fd, + xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + /* TODO: If the inode existed in the cache (say file already + exists), then the glfs_loc_link will not update the + loc.inode, as a result we will have a 0000 GFID that we + would copy out to the object, this needs to be fixed. + */ + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + if (glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } + + glfs_subvol_done (fs, subvol); + + return object; +} + +struct glfs_object * +glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent, const char *path, + mode_t mode, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + 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; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + /* fop/op */ + ret = syncop_mkdir (subvol, &loc, mode, xattr_req, &iatt); + + /* populate out args */ + if ( ret == 0 ) { + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +struct glfs_object * +glfs_h_mknod (struct glfs *fs, struct glfs_object *parent, const char *path, + mode_t mode, dev_t dev, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + 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; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + /* fop/op */ + ret = syncop_mknod (subvol, &loc, mode, dev, xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_unlink (struct glfs *fs, struct glfs_object *parent, const char *path) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if ( !subvol ) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, inode, path, &loc, NULL, 0 , 0); + if (ret != 0) { + goto out; + } + + if (!IA_ISDIR(loc.inode->ia_type)) { + ret = syncop_unlink (subvol, &loc); + if (ret != 0) { + goto out; + } + } else { + ret = syncop_rmdir (subvol, &loc); + if (ret != 0) { + goto out; + } + } + + if (ret == 0) + ret = glfs_loc_unlink (&loc); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_fd * +glfs_h_opendir (struct glfs *fs, struct glfs_object *object) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + if (!IA_ISDIR (inode->ia_type)) { + ret = -1; + errno = ENOTDIR; + goto out; + } + + glfd = glfs_fd_new (fs); + if (!glfd) + goto out; + + INIT_LIST_HEAD (&glfd->entries); + + glfd->fd = fd_create (inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_opendir (subvol, &loc, glfd->fd); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } else { + fd_bind (glfd->fd); + glfs_fd_bind (glfd); + } + + glfs_subvol_done (fs, subvol); + + return glfd; +} + +ssize_t +glfs_h_extract_handle (struct glfs_object *object, unsigned char *handle, + int len) +{ + ssize_t ret = -1; + + /* validate in args */ + if (object == NULL) { + errno = EINVAL; + goto out; + } + + if (!handle || !len) { + ret = GFAPI_HANDLE_LENGTH; + goto out; + } + + if (len < GFAPI_HANDLE_LENGTH) + { + errno = ERANGE; + goto out; + } + + memcpy (handle, object->gfid, GFAPI_HANDLE_LENGTH); + + ret = GFAPI_HANDLE_LENGTH; + +out: + return ret; +} + +struct glfs_object * +glfs_h_create_from_handle (struct glfs *fs, unsigned char *handle, int len, + struct stat *stat) +{ + loc_t loc = {0, }; + int ret = -1; + struct iatt iatt = {0, }; + inode_t *newinode = NULL; + xlator_t *subvol = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (handle == NULL) || (len != GFAPI_HANDLE_LENGTH)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + memcpy (loc.gfid, handle, GFAPI_HANDLE_LENGTH); + + newinode = inode_find (subvol->itable, loc.gfid); + if (newinode) + loc.inode = newinode; + else { + loc.inode = inode_new (subvol->itable); + if (!loc.inode) { + errno = ENOMEM; + goto out; + } + } + + ret = syncop_lookup (subvol, &loc, 0, &iatt, 0, 0); + if (ret) { + gf_log (subvol->name, GF_LOG_WARNING, + "inode refresh of %s failed: %s", + uuid_utoa (loc.gfid), strerror (errno)); + goto out; + } + + newinode = inode_link (loc.inode, 0, 0, &iatt); + if (newinode) + inode_lookup (newinode); + else { + gf_log (subvol->name, GF_LOG_WARNING, + "inode linking of %s failed: %s", + uuid_utoa (loc.gfid), strerror (errno)); + errno = EINVAL; + goto out; + } + + /* populate stat */ + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + object = GF_CALLOC (1, sizeof(struct glfs_object), + glfs_mt_glfs_object_t); + if (object == NULL) { + errno = ENOMEM; + ret = -1; + goto out; + } + + /* populate the return object */ + object->inode = newinode; + uuid_copy (object->gfid, object->inode->gfid); + +out: + /* TODO: Check where the inode ref is being held? */ + loc_wipe (&loc); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_close (struct glfs_object *object) +{ + /* Release the held reference */ + inode_unref (object->inode); + GF_FREE (object); + + return 0; +} + +int +glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset) +{ + loc_t loc = {0, }; + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_truncate (subvol, &loc, (off_t)offset); + + /* populate out args */ + if (ret == 0) + ret = glfs_loc_unlink (&loc); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_object * +glfs_h_symlink (struct glfs *fs, struct glfs_object *parent, const char *name, + const char *data, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (name == NULL) || + (data == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + 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; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, name); + + /* fop/op */ + ret = syncop_symlink (subvol, &loc, data, xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + /* TODO: If the inode existed in the cache (say file already + * exists), then the glfs_loc_link will not update the + * loc.inode, as a result we will have a 0000 GFID that we + * would copy out to the object, this needs to be fixed. + */ + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf, + size_t bufsiz) +{ + loc_t loc = {0, }; + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + char *linkval = NULL; + + /* validate in args */ + if ((fs == NULL) || (object == NULL) || (buf == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_readlink (subvol, &loc, &linkval, bufsiz); + + /* populate out args */ + if (ret > 0) + memcpy (buf, linkval, ret); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (linkval) + GF_FREE (linkval); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_link (struct glfs *fs, struct glfs_object *linksrc, + struct glfs_object *parent, const char *name) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + inode_t *pinode = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (linksrc == NULL) || (parent == NULL) || + (name == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, linksrc); + if (!inode) { + errno = ESTALE; + goto out; + } + + if (inode->ia_type == IA_IFDIR) { + ret = -1; + errno = EISDIR; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, oldloc, out); + + /* get/refresh the in arg objects inode in correlation to the xlator */ + pinode = glfs_resolve_inode (fs, subvol, parent); + if (!pinode) { + errno = ESTALE; + goto out; + } + + /* setup newloc based on parent */ + newloc.parent = inode_ref (pinode); + newloc.name = name; + ret = glfs_loc_touchup (&newloc); + if (ret != 0) { + errno = EINVAL; + goto out; + } + + /* Filling the inode of the hard link to be same as that of the + * original file + */ + newloc.inode = inode_ref (inode); + + /* fop/op */ + ret = syncop_link (subvol, &oldloc, &newloc); + + if (ret == 0) + /* TODO: No iatt to pass as there has been no lookup */ + ret = glfs_loc_link (&newloc, NULL); +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + if (inode) + inode_unref (inode); + + if (pinode) + inode_unref (pinode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_rename (struct glfs *fs, struct glfs_object *olddir, const char *oldname, + struct glfs_object *newdir, const char *newname) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *oldpinode = NULL; + inode_t *newpinode = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + struct iatt oldiatt = {0, }; + struct iatt newiatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (olddir == NULL) || (oldname == NULL) || + (newdir == NULL) || (newname == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if ( !subvol ) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + oldpinode = glfs_resolve_inode (fs, subvol, olddir); + if (!oldpinode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, oldpinode, oldname, &oldloc, + &oldiatt, 0 , 0); + if (ret != 0) { + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + newpinode = glfs_resolve_inode (fs, subvol, newdir); + if (!newpinode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, newpinode, newname, &newloc, + &newiatt, 0, 0); + + if (ret && errno != ENOENT && newloc.parent) + goto out; + + if (newiatt.ia_type != IA_INVAL) { + if ((oldiatt.ia_type == IA_IFDIR) != + (newiatt.ia_type == IA_IFDIR)) { + /* Either both old and new must be dirs, + * or both must be non-dirs. Else, fail. + */ + ret = -1; + errno = EISDIR; + goto out; + } + } + + /* TODO: check if new or old is a prefix of the other, and fail EINVAL */ + + ret = syncop_rename (subvol, &oldloc, &newloc); + + if (ret == 0) + inode_rename (oldloc.parent->table, oldloc.parent, oldloc.name, + newloc.parent, newloc.name, oldloc.inode, + &oldiatt); + +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + if (oldpinode) + inode_unref (oldpinode); + + if (newpinode) + inode_unref (newpinode); + + glfs_subvol_done (fs, subvol); + + return ret; +} diff --git a/api/src/glfs-handles.h b/api/src/glfs-handles.h new file mode 100644 index 00000000000..437f2cbc8a5 --- /dev/null +++ b/api/src/glfs-handles.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + 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_HANDLES_H +#define _GLFS_HANDLES_H + +#include "glfs.h" + +/* GLFS OBJECT BASED OPERATIONS + * + * The following APIs are introduced to provide an API framework that can work + * with gluster objects (files and directories), instead of absolute paths. + * + * The following API set can be related to the POSIX *at interfaces (like + * openat (2)). The intention of these APIs is to be able to operate based + * on parent object and looking up or creating child objects within, OR to be + * used on the actual object thus looked up or created, and retrieve information + * regarding the same. + * + * The APIs also provide for generating an opaque invariant handle to the + * object, that can later be used to lookup the object, instead of the regular + * glfs_h_* variants. The APIs that provide this behaviour are, + * glfs_h_extract_handle and glfs_h_create_from_handle. + * + * The object handles can be transitioned to fd based operations as supported + * by glfs.h calls, using the glfs_h_open call. This provides a way to move + * from objects to fd's akin to moving from path to fd for required operations. + * + * NOTE: The opaque invariant handle is the GFID of the object in reality, but + * maintained as an opaque data value, for potential internal changes to the + * same without impacting the caller. + * + * NOTE: Currently looking up an object can create multiple object handles to + * the same, i.e distinct glfs_object *. Hence each such looked up or received + * handle from other calls, would need to be closed. In the future, for a given + * object these pointers would be the same, and an ease of use API to forget all + * instances of this bject would be provided (instead of a per lookup close). + * This should not change the APIs in their current form. + * + */ + +/* Values for valid falgs to be used when using XXXsetattr, to set multiple + attribute values passed via the related stat structure. + */ +#define GFAPI_SET_ATTR_MODE 0x1 +#define GFAPI_SET_ATTR_UID 0x2 +#define GFAPI_SET_ATTR_GID 0x4 +#define GFAPI_SET_ATTR_SIZE 0x8 +#define GFAPI_SET_ATTR_ATIME 0x10 +#define GFAPI_SET_ATTR_MTIME 0x20 + +/* Handle length for object handles returned from glfs_h_extract_handle or + * glfs_h_create_from_handle */ +#define GFAPI_HANDLE_LENGTH 16 + +__BEGIN_DECLS + +/* + * Notes: + * + * The file object handle. One per looked up, created file/directory + * + * This had been introduced to facilitate gfid/inode based gfapi + * - a requirement introduced by nfs-ganesha + */ +struct glfs_object; +typedef struct glfs_object glfs_object_t; + +/* Handle based operations */ +/* Operations that generate handles */ +struct glfs_object *glfs_h_lookupat (struct glfs *fs, + struct glfs_object *parent, + const char *path, struct stat *stat); + +struct glfs_object *glfs_h_creat (struct glfs *fs, struct glfs_object *parent, + const char *path, int flags, mode_t mode, + struct stat *sb); + +struct glfs_object *glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent, + const char *path, mode_t flags, + struct stat *sb); + +struct glfs_object *glfs_h_mknod (struct glfs *fs, struct glfs_object *parent, + const char *path, mode_t mode, dev_t dev, + struct stat *sb); + +struct glfs_object *glfs_h_symlink (struct glfs *fs, struct glfs_object *parent, + const char *name, const char *data, + struct stat *stat); + +/* Operations on the actual objects */ +int glfs_h_unlink (struct glfs *fs, struct glfs_object *parent, + const char *path); + +int glfs_h_close (struct glfs_object *object); + +int glfs_caller_specific_init (void *uid_caller_key, void *gid_caller_key, + void *future); + +int glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset); + +int glfs_h_stat(struct glfs *fs, struct glfs_object *object, struct stat *stat); + +int glfs_h_getattrs (struct glfs *fs, struct glfs_object *object, + struct stat *stat); + +int glfs_h_setattrs (struct glfs *fs, struct glfs_object *object, + struct stat *sb, int valid); + +int glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf, + size_t bufsiz); + +int glfs_h_link (struct glfs *fs, struct glfs_object *linktgt, + struct glfs_object *parent, const char *name); + +int glfs_h_rename (struct glfs *fs, struct glfs_object *olddir, + const char *oldname, struct glfs_object *newdir, + const char *newname); + +/* Operations enabling opaque invariant handle to object transitions */ +ssize_t glfs_h_extract_handle (struct glfs_object *object, + unsigned char *handle, int len); + +struct glfs_object *glfs_h_create_from_handle (struct glfs *fs, + unsigned char *handle, int len, + struct stat *stat); + +/* Operations enabling object handles to fd transitions */ +struct glfs_fd *glfs_h_opendir (struct glfs *fs, struct glfs_object *object); + +struct glfs_fd *glfs_h_open (struct glfs *fs, struct glfs_object *object, + int flags); + +__END_DECLS + +#endif /* !_GLFS_HANDLES_H */
\ No newline at end of file diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index c7fdf75f541..1b1c1c7f624 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -16,6 +16,44 @@ #define GLFS_SYMLINK_MAX_FOLLOW 2048 +#define DEFAULT_REVAL_COUNT 1 + +#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \ + if (ret == -1 && errno == ESTALE) { \ + if (reval < DEFAULT_REVAL_COUNT) { \ + reval++; \ + loc_wipe (loc); \ + goto label; \ + } \ + } \ + } while (0) + +#define GLFS_LOC_FILL_INODE(oinode, loc, label) do { \ + loc.inode = inode_ref (oinode); \ + uuid_copy (loc.gfid, oinode->gfid); \ + ret = glfs_loc_touchup (&loc); \ + if (ret != 0) { \ + errno = EINVAL; \ + goto label; \ + } \ + } while (0) + +#define GLFS_LOC_FILL_PINODE(pinode, loc, ret, errno, label, path) do { \ + loc.inode = inode_new (pinode->table); \ + if (!loc.inode) { \ + ret = -1; \ + errno = ENOMEM; \ + goto label; \ + } \ + loc.parent = inode_ref (pinode); \ + loc.name = path; \ + ret = glfs_loc_touchup (&loc); \ + if (ret != 0) { \ + errno = EINVAL; \ + goto label; \ + } \ + } while (0) + struct glfs; typedef int (*glfs_init_cbk) (struct glfs *fs, int ret); @@ -59,6 +97,14 @@ struct glfs_fd { gf_dirent_t *next; }; +/* glfs object handle introduced for the alternate gfapi implementation based + on glfs handles/gfid/inode +*/ +struct glfs_object { + inode_t *inode; + uuid_t gfid; +}; + #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) @@ -135,6 +181,19 @@ inode_t * glfs_refresh_inode (xlator_t *subvol, inode_t *inode); inode_t *glfs_cwd_get (struct glfs *fs); int glfs_cwd_set (struct glfs *fs, inode_t *inode); +inode_t *glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object); +int glfs_create_object (loc_t *loc, struct glfs_object **retobject); int __glfs_cwd_set (struct glfs *fs, inode_t *inode); +int glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, + struct iatt *iatt); +int glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at, + const char *origpath, loc_t *loc, struct iatt *iatt, + int follow, int reval); +int glfs_loc_touchup (loc_t *loc); +void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat); +int glfs_loc_link (loc_t *loc, struct iatt *iatt); +int glfs_loc_unlink (loc_t *loc); + #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h index 590acd03f11..ae47915111d 100644 --- a/api/src/glfs-mem-types.h +++ b/api/src/glfs-mem-types.h @@ -23,7 +23,8 @@ enum glfs_mem_types_ { glfs_mt_glfs_io_t, glfs_mt_volfile_t, glfs_mt_xlator_cmdline_option_t, - glfs_mt_end + glfs_mt_glfs_object_t, + glfs_mt_end }; #endif diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c index 3179af22c2d..98ef6a946f8 100644 --- a/api/src/glfs-resolve.c +++ b/api/src/glfs-resolve.c @@ -191,7 +191,7 @@ out: } -void +int glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, struct iatt *iatt) { @@ -210,6 +210,8 @@ glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, ret = syncop_lookup (subvol, &loc, NULL, iatt, NULL, NULL); out: loc_wipe (&loc); + + return ret; } @@ -356,7 +358,8 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at, component, as the caller wants proper iatt filled */ - (reval || !next_component)); + (reval || (!next_component && + iatt))); if (!inode) break; @@ -900,3 +903,63 @@ glfs_cwd_get (struct glfs *fs) return cwd; } + +inode_t * +__glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object) +{ + inode_t *inode = NULL; + + if (object->inode->table->xl == subvol) + return inode_ref (object->inode); + + inode = __glfs_refresh_inode (fs, fs->active_subvol, + object->inode); + if (!inode) + return NULL; + + if (subvol == fs->active_subvol) { + inode_unref (object->inode); + object->inode = inode_ref (inode); + } + + return inode; +} + +inode_t * +glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object) +{ + inode_t *inode = NULL; + + glfs_lock (fs); + { + inode = __glfs_resolve_inode(fs, subvol, object); + } + glfs_unlock (fs); + + return inode; +} + +int +glfs_create_object (loc_t *loc, struct glfs_object **retobject) +{ + struct glfs_object *object = NULL; + + object = GF_CALLOC (1, sizeof(struct glfs_object), + glfs_mt_glfs_object_t); + if (object == NULL) { + errno = ENOMEM; + return -1; + } + + object->inode = loc->inode; + uuid_copy (object->gfid, object->inode->gfid); + + /* we hold the reference */ + loc->inode = NULL; + + *retobject = object; + + return 0; +} diff --git a/api/src/glfs.c b/api/src/glfs.c index 7b056b5167b..2f58b61852e 100644 --- a/api/src/glfs.c +++ b/api/src/glfs.c @@ -317,6 +317,20 @@ enomem: return -1; } +int glfs_setfsuid (uid_t fsuid) +{ + return syncopctx_setfsuid (&fsuid); +} + +int glfs_setfsgid (gid_t fsgid) +{ + return syncopctx_setfsgid (&fsgid); +} + +int glfs_setfsgroups (size_t size, const gid_t *list) +{ + return syncopctx_setfsgroups(size, list); +} struct glfs * glfs_from_glfd (struct glfs_fd *glfd) diff --git a/api/src/glfs.h b/api/src/glfs.h index fd44c2fc885..c2fb26505d5 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -271,6 +271,32 @@ int glfs_fini (glfs_t *fs); struct glfs_fd; typedef struct glfs_fd glfs_fd_t; +/* + * PER THREAD IDENTITY MODIFIERS + * + * The following operations enable to set a per thread identity context + * for the glfs APIs to perform operations as. The calls here are kept as close + * to POSIX equivalents as possible. + * + * NOTES: + * + * - setgroups is a per thread setting, hence this is named as fsgroups to be + * close in naming to the fs(u/g)id APIs + * - Typical mode of operation is to set the IDs as required, with the + * supplementary groups being optionally set, make the glfs call and post the + * glfs operation set them back to eu/gid or uid/gid as appropriate to the + * caller + * - The groups once set, need to be unset by setting the size to 0 (in which + * case the list argument is a do not care) + * - Once a process for a thread of operation choses to set the IDs, all glfs + * calls made from that thread would default to the IDs set for the thread. + * As a result use these APIs with care and ensure that the set IDs are + * reverted to global process defaults as required. + * + */ +int glfs_setfsuid (uid_t fsuid); +int glfs_setfsgid (gid_t fsgid); +int glfs_setfsgroups (size_t size, const gid_t *list); /* SYNOPSIS |