diff options
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  | 
