blob: 691b883647fd9deeb8f5c7dd0cf82d3ae87f2bd8 [file] [log] [blame]
/*
* vim:noexpandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) Red Hat Inc., 2013
* Author: Anand Subramanian anands@redhat.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* -------------
*/
#include "config.h"
#ifdef LINUX
#include <sys/sysmacros.h> /* for makedev(3) */
#endif
#include <fcntl.h>
#include "fsal.h"
#include "gluster_internal.h"
#include "FSAL/fsal_commonlib.h"
#include "fsal_convert.h"
#include "pnfs_utils.h"
#include "nfs_exports.h"
#include "sal_data.h"
/* fsal_obj_handle common methods
*/
/**
* @brief Implements GLUSTER FSAL objectoperation handle_release
*
* Free up the GLUSTER handle and associated data if any
* Typically free up any members of the struct glusterfs_handle
*/
static void handle_release(struct fsal_obj_handle *obj_hdl)
{
int rc = 0;
struct glusterfs_handle *objhandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
fsal_obj_handle_fini(&objhandle->handle);
if (objhandle->globalfd.glfd) {
rc = glfs_close(objhandle->globalfd.glfd);
if (rc) {
LogCrit(COMPONENT_FSAL,
"glfs_close returned %s(%d)",
strerror(errno), errno);
/* cleanup as much as possible */
}
}
if (objhandle->glhandle) {
rc = glfs_h_close(objhandle->glhandle);
if (rc) {
LogCrit(COMPONENT_FSAL,
"glfs_h_close returned error %s(%d)",
strerror(errno), errno);
}
objhandle->glhandle = NULL;
}
gsh_free(objhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_handle_release);
#endif
}
/**
* @brief Implements GLUSTER FSAL objectoperation lookup
*/
static fsal_status_t lookup(struct fsal_obj_handle *parent,
const char *path, struct fsal_obj_handle **handle,
struct attrlist *attrs_out)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct stat sb;
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
struct glusterfs_handle *objhandle = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(parent, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
glhandle = glfs_h_lookupat(glfs_export->gl_fs,
parenthandle->glhandle, path, &sb, 0);
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid, GLAPI_UUID_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(rc);
goto out;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &objhandle, vol_uuid);
if (attrs_out != NULL) {
posix2fsal_attributes(&sb, attrs_out);
}
*handle = &objhandle->handle;
out:
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_lookup);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation readdir
*/
static fsal_status_t read_dirents(struct fsal_obj_handle *dir_hdl,
fsal_cookie_t *whence, void *dir_state,
fsal_readdir_cb cb, attrmask_t attrmask,
bool *eof)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glfs_fd *glfd = NULL;
long offset = 0;
struct dirent *pde = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *objhandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
/** @todo : Can we use globalfd instead */
glfd = glfs_h_opendir(glfs_export->gl_fs, objhandle->glhandle);
if (glfd == NULL)
return gluster2fsal_error(errno);
if (whence != NULL)
offset = *whence;
glfs_seekdir(glfd, offset);
while (!(*eof)) {
struct dirent de;
struct fsal_obj_handle *obj;
rc = glfs_readdir_r(glfd, &de, &pde);
if (rc == 0 && pde != NULL) {
struct attrlist attrs;
bool cb_rc;
/* skip . and .. */
if ((strcmp(de.d_name, ".") == 0)
|| (strcmp(de.d_name, "..") == 0)) {
continue;
}
fsal_prepare_attrs(&attrs, attrmask);
status = lookup(dir_hdl, de.d_name, &obj, &attrs);
if (FSAL_IS_ERROR(status))
goto out;
cb_rc = cb(de.d_name, obj, &attrs,
dir_state, glfs_telldir(glfd));
fsal_release_attrs(&attrs);
if (!cb_rc)
goto out;
} else if (rc == 0 && pde == NULL) {
*eof = true;
} else {
status = gluster2fsal_error(errno);
goto out;
}
}
out:
rc = glfs_closedir(glfd);
if (rc < 0)
status = gluster2fsal_error(errno);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_read_dirents);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation create
*/
static fsal_status_t create(struct fsal_obj_handle *dir_hdl,
const char *name, struct attrlist *attrib,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct stat sb;
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
struct glusterfs_handle *objhandle = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
rc = setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
/* FIXME: what else from attrib should we use? */
glhandle =
glfs_h_creat(glfs_export->gl_fs, parenthandle->glhandle, name,
O_CREAT | O_EXCL, fsal2unix_mode(attrib->mode), &sb);
rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid, GLAPI_UUID_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(rc);
goto out;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &objhandle, vol_uuid);
if (attrs_out != NULL) {
posix2fsal_attributes(&sb, attrs_out);
}
*handle = &objhandle->handle;
out:
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_create);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation mkdir
*/
static fsal_status_t makedir(struct fsal_obj_handle *dir_hdl,
const char *name, struct attrlist *attrib,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct stat sb;
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
struct glusterfs_handle *objhandle = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
rc = setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
glhandle =
glfs_h_mkdir(glfs_export->gl_fs, parenthandle->glhandle, name,
fsal2unix_mode(attrib->mode), &sb);
rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid, GLAPI_UUID_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(rc);
goto out;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &objhandle, vol_uuid);
if (attrs_out != NULL) {
posix2fsal_attributes(&sb, attrs_out);
}
*handle = &objhandle->handle;
/* We handled the mode above. */
FSAL_UNSET_MASK(attrib->valid_mask, ATTR_MODE);
if (attrib->valid_mask) {
/* Now per support_ex API, if there are any other attributes
* set, go ahead and get them set now.
*/
status = (*handle)->obj_ops.setattr2(*handle, false, NULL,
attrib);
if (FSAL_IS_ERROR(status)) {
/* Release the handle we just allocated. */
LogFullDebug(COMPONENT_FSAL,
"setattr2 status=%s",
fsal_err_txt(status));
(*handle)->obj_ops.release(*handle);
/* We released handle at this point */
glhandle = NULL;
*handle = NULL;
}
} else {
status.major = ERR_FSAL_NO_ERROR;
status.minor = 0;
}
FSAL_SET_MASK(attrib->valid_mask, ATTR_MODE);
out:
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_makedir);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation mknode
*/
static fsal_status_t makenode(struct fsal_obj_handle *dir_hdl,
const char *name, object_file_type_t nodetype,
fsal_dev_t *dev, struct attrlist *attrib,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct stat sb;
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
struct glusterfs_handle *objhandle = NULL;
dev_t ndev = { 0, };
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
mode_t create_mode;
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
switch (nodetype) {
case BLOCK_FILE:
if (!dev)
return fsalstat(ERR_FSAL_INVAL, 0);
/* FIXME: This needs a feature flag test? */
ndev = makedev(dev->major, dev->minor);
create_mode = S_IFBLK;
break;
case CHARACTER_FILE:
if (!dev)
return fsalstat(ERR_FSAL_INVAL, 0);
ndev = makedev(dev->major, dev->minor);
create_mode = S_IFCHR;
break;
case FIFO_FILE:
create_mode = S_IFIFO;
break;
case SOCKET_FILE:
create_mode = S_IFSOCK;
break;
default:
LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d",
nodetype);
return fsalstat(ERR_FSAL_INVAL, 0);
}
rc = setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
glhandle =
glfs_h_mknod(glfs_export->gl_fs, parenthandle->glhandle, name,
create_mode | fsal2unix_mode(attrib->mode), ndev, &sb);
rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid, GLAPI_UUID_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(rc);
goto out;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &objhandle, vol_uuid);
if (attrs_out != NULL) {
posix2fsal_attributes(&sb, attrs_out);
}
*handle = &objhandle->handle;
/* We handled the mode above. */
FSAL_UNSET_MASK(attrib->valid_mask, ATTR_MODE);
if (attrib->valid_mask) {
/* Now per support_ex API, if there are any other attributes
* set, go ahead and get them set now.
*/
status = (*handle)->obj_ops.setattr2(*handle, false, NULL,
attrib);
if (FSAL_IS_ERROR(status)) {
/* Release the handle we just allocated. */
LogFullDebug(COMPONENT_FSAL,
"setattr2 status=%s",
fsal_err_txt(status));
(*handle)->obj_ops.release(*handle);
/* We released handle at this point */
glhandle = NULL;
*handle = NULL;
}
} else {
status.major = ERR_FSAL_NO_ERROR;
status.minor = 0;
}
FSAL_SET_MASK(attrib->valid_mask, ATTR_MODE);
out:
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_makenode);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation symlink
*/
static fsal_status_t makesymlink(struct fsal_obj_handle *dir_hdl,
const char *name, const char *link_path,
struct attrlist *attrib,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct stat sb;
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
struct glusterfs_handle *objhandle = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
rc = setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
glhandle =
glfs_h_symlink(glfs_export->gl_fs, parenthandle->glhandle, name,
link_path, &sb);
rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (rc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
rc = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid, GLAPI_UUID_LENGTH);
if (rc < 0) {
status = gluster2fsal_error(rc);
goto out;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &objhandle, vol_uuid);
if (attrs_out != NULL) {
posix2fsal_attributes(&sb, attrs_out);
}
*handle = &objhandle->handle;
if (attrib->valid_mask) {
/* Now per support_ex API, if there are any other attributes
* set, go ahead and get them set now.
*/
status = (*handle)->obj_ops.setattr2(*handle, false, NULL,
attrib);
if (FSAL_IS_ERROR(status)) {
/* Release the handle we just allocated. */
LogFullDebug(COMPONENT_FSAL,
"setattr2 status=%s",
fsal_err_txt(status));
(*handle)->obj_ops.release(*handle);
/* We released handle at this point */
glhandle = NULL;
*handle = NULL;
}
} else {
status.major = ERR_FSAL_NO_ERROR;
status.minor = 0;
}
out:
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_makesymlink);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation readlink
*/
static fsal_status_t readsymlink(struct fsal_obj_handle *obj_hdl,
struct gsh_buffdesc *link_content,
bool refresh)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *objhandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
link_content->len = MAXPATHLEN; /* Max link path */
link_content->addr = gsh_malloc(link_content->len);
rc = glfs_h_readlink(glfs_export->gl_fs, objhandle->glhandle,
link_content->addr, link_content->len);
if (rc < 0) {
status = gluster2fsal_error(errno);
goto out;
}
if (rc >= MAXPATHLEN) {
status = gluster2fsal_error(EINVAL);
goto out;
}
/* rc is the number of bytes copied into link_content->addr
* without including '\0' character. */
*(char *)(link_content->addr + rc) = '\0';
link_content->len = rc + 1;
out:
if (status.major != ERR_FSAL_NO_ERROR) {
gsh_free(link_content->addr);
link_content->addr = NULL;
link_content->len = 0;
}
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_readsymlink);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation getattrs
*/
static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl,
struct attrlist *attrs)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
glusterfs_fsal_xstat_t buffxstat;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *objhandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
/*
* There is a kind of race here when the glfd part of the
* FSAL GLUSTER object handle is destroyed during a close
* coming in from another NFSv3 WRITE thread which does
* cache_inode_open(). Since the context/fd is destroyed
* we cannot depend on glfs_fstat assuming glfd is valid.
* Fixing the issue by removing the glfs_fstat call here.
* So default to glfs_h_stat and re-optimize if a better
* way is found - that may involve introducing locks in
* the gfapi's for close and getattrs etc.
*/
/** @todo: With support_ex() above may no longer be valid.
* This needs to be revisited */
rc = glfs_h_stat(glfs_export->gl_fs,
objhandle->glhandle, &buffxstat.buffstat);
if (rc != 0) {
if (errno == ENOENT)
status = gluster2fsal_error(ESTALE);
else
status = gluster2fsal_error(errno);
if (attrs->request_mask & ATTR_RDATTR_ERR) {
/* Caller asked for error to be visible. */
attrs->valid_mask = ATTR_RDATTR_ERR;
}
goto out;
}
stat2fsal_attributes(&buffxstat.buffstat, attrs);
if (obj_hdl->type == DIRECTORY)
buffxstat.is_dir = true;
else
buffxstat.is_dir = false;
if (attrs->request_mask & ATTR_ACL) {
/* Fetch the ACL */
status = glusterfs_get_acl(glfs_export, objhandle->glhandle,
&buffxstat, attrs);
if (!FSAL_IS_ERROR(status)) {
/* Success, so mark ACL as valid. */
attrs->valid_mask |= ATTR_ACL;
}
}
/* *
* The error ENOENT is not an expected error for GETATTRS
* Due to this, operations such as RENAME will fail when
* it calls GETATTRS on removed file. But for dead links
* we should not return error
* */
if (status.major == ERR_FSAL_NOENT) {
if (obj_hdl->type == SYMBOLIC_LINK)
status = fsalstat(ERR_FSAL_NO_ERROR, 0);
else
status = gluster2fsal_error(ESTALE);
}
if (FSAL_IS_ERROR(status)) {
if (attrs->request_mask & ATTR_RDATTR_ERR) {
/* Caller asked for error to be visible. */
attrs->valid_mask = ATTR_RDATTR_ERR;
}
}
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_getattrs);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation link
*/
static fsal_status_t linkfile(struct fsal_obj_handle *obj_hdl,
struct fsal_obj_handle *destdir_hdl,
const char *name)
{
int rc = 0, credrc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *objhandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
struct glusterfs_handle *dstparenthandle =
container_of(destdir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
credrc =
setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
rc = glfs_h_link(glfs_export->gl_fs, objhandle->glhandle,
dstparenthandle->glhandle, name);
credrc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (rc != 0) {
status = gluster2fsal_error(errno);
goto out;
}
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_linkfile);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation rename
*/
static fsal_status_t renamefile(struct fsal_obj_handle *obj_hdl,
struct fsal_obj_handle *olddir_hdl,
const char *old_name,
struct fsal_obj_handle *newdir_hdl,
const char *new_name)
{
int rc = 0, credrc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export,
export);
struct glusterfs_handle *srcparenthandle =
container_of(olddir_hdl, struct glusterfs_handle, handle);
struct glusterfs_handle *dstparenthandle =
container_of(newdir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
credrc =
setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
rc = glfs_h_rename(glfs_export->gl_fs, srcparenthandle->glhandle,
old_name, dstparenthandle->glhandle, new_name);
credrc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (rc != 0) {
status = gluster2fsal_error(errno);
goto out;
}
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_renamefile);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation unlink
*/
static fsal_status_t file_unlink(struct fsal_obj_handle *dir_hdl,
struct fsal_obj_handle *obj_hdl,
const char *name)
{
int rc = 0, credrc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *parenthandle =
container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
credrc =
setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
rc = glfs_h_unlink(glfs_export->gl_fs, parenthandle->glhandle, name);
credrc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (credrc != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
if (rc != 0)
status = gluster2fsal_error(errno);
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_file_unlink);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation share_op
*/
/*
static fsal_status_t share_op(struct fsal_obj_handle *obj_hdl,
void *p_owner,
fsal_share_param_t request_share)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
fsal_status_t glusterfs_open_my_fd(struct glusterfs_handle *objhandle,
fsal_openflags_t openflags,
int posix_flags,
struct glusterfs_fd *my_fd)
{
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glfs_fd *glfd = NULL;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
LogFullDebug(COMPONENT_FSAL,
"my_fd->fd = %p openflags = %x, posix_flags = %x",
my_fd->glfd, openflags, posix_flags);
assert(my_fd->glfd == NULL
&& my_fd->openflags == FSAL_O_CLOSED && openflags != 0);
LogFullDebug(COMPONENT_FSAL,
"openflags = %x, posix_flags = %x",
openflags, posix_flags);
glfd = glfs_h_open(glfs_export->gl_fs, objhandle->glhandle,
posix_flags);
if (glfd == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
my_fd->glfd = glfd;
my_fd->openflags = openflags;
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_file_open);
#endif
return status;
}
fsal_status_t glusterfs_close_my_fd(struct glusterfs_fd *my_fd)
{
int rc = 0;
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
if (my_fd->glfd && my_fd->openflags != FSAL_O_CLOSED) {
rc = glfs_close(my_fd->glfd);
if (rc != 0) {
status = gluster2fsal_error(errno);
LogCrit(COMPONENT_FSAL,
"Error : close returns with %s",
strerror(errno));
}
}
my_fd->glfd = NULL;
my_fd->openflags = FSAL_O_CLOSED;
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_file_close);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation close
@todo: close2() could be used to close globalfd as well.
*/
static fsal_status_t file_close(struct fsal_obj_handle *obj_hdl)
{
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
struct glusterfs_handle *objhandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
assert(obj_hdl->type == REGULAR_FILE);
/* Take write lock on object to protect file descriptor.
* This can block over an I/O operation.
*/
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
status = glusterfs_close_my_fd(&objhandle->globalfd);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_file_close);
#endif
return status;
}
/**
* @brief Function to open an fsal_obj_handle's global file descriptor.
*
* @param[in] obj_hdl File on which to operate
* @param[in] openflags Mode for open
* @param[out] fd File descriptor that is to be used
*
* @return FSAL status.
*/
fsal_status_t glusterfs_open_func(struct fsal_obj_handle *obj_hdl,
fsal_openflags_t openflags,
struct fsal_fd *fd)
{
struct glusterfs_handle *myself;
int posix_flags = 0;
myself = container_of(obj_hdl, struct glusterfs_handle, handle);
fsal2posix_openflags(openflags, &posix_flags);
return glusterfs_open_my_fd(myself, openflags, posix_flags,
(struct glusterfs_fd *)fd);
}
/**
* @brief Function to close an fsal_obj_handle's global file descriptor.
*
* @param[in] obj_hdl File on which to operate
* @param[in] fd File handle to close
*
* @return FSAL status.
*/
fsal_status_t glusterfs_close_func(struct fsal_obj_handle *obj_hdl,
struct fsal_fd *fd)
{
return glusterfs_close_my_fd((struct glusterfs_fd *)fd);
}
/**
* @brief Find a file descriptor for a read, write, setattr2 operation.
*
* We do not need file descriptors for non-regular files, so this never has to
* handle them.
*/
fsal_status_t find_fd(struct glusterfs_fd *my_fd,
struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
fsal_openflags_t openflags,
bool *has_lock,
bool *need_fsync,
bool *closefd,
bool open_for_locks)
{
struct glusterfs_handle *myself;
fsal_status_t status = {ERR_FSAL_NO_ERROR, 0};
struct glusterfs_fd tmp_fd = {0}, *tmp2_fd = &tmp_fd;
myself = container_of(obj_hdl, struct glusterfs_handle, handle);
/* Handle only regular files */
if (obj_hdl->type != REGULAR_FILE)
return fsalstat(posix2fsal_error(EINVAL), EINVAL);
status = fsal_find_fd((struct fsal_fd **)&tmp2_fd, obj_hdl,
(struct fsal_fd *)&myself->globalfd,
&myself->share, bypass, state,
openflags, glusterfs_open_func,
glusterfs_close_func,
has_lock, need_fsync,
closefd, open_for_locks);
my_fd->glfd = tmp2_fd->glfd;
my_fd->openflags = tmp2_fd->openflags;
return status;
}
/**
* @brief Merge a duplicate handle with an original handle
*
* This function is used if an upper layer detects that a duplicate
* object handle has been created. It allows the FSAL to merge anything
* from the duplicate back into the original.
*
* The caller must release the object (the caller may have to close
* files if the merge is unsuccessful).
*
* @param[in] orig_hdl Original handle
* @param[in] dupe_hdl Handle to merge into original
*
* @return FSAL status.
*
*/
fsal_status_t glusterfs_merge(struct fsal_obj_handle *orig_hdl,
struct fsal_obj_handle *dupe_hdl)
{
fsal_status_t status = {ERR_FSAL_NO_ERROR, 0};
if (orig_hdl->type == REGULAR_FILE &&
dupe_hdl->type == REGULAR_FILE) {
/* We need to merge the share reservations on this file.
* This could result in ERR_FSAL_SHARE_DENIED.
*/
struct glusterfs_handle *orig, *dupe;
orig = container_of(orig_hdl, struct glusterfs_handle, handle);
dupe = container_of(dupe_hdl, struct glusterfs_handle, handle);
/* This can block over an I/O operation. */
PTHREAD_RWLOCK_wrlock(&orig_hdl->lock);
status = merge_share(&orig->share, &dupe->share);
PTHREAD_RWLOCK_unlock(&orig_hdl->lock);
}
return status;
}
/* open2
*/
static fsal_status_t glusterfs_open2(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
fsal_openflags_t openflags,
enum fsal_create_mode createmode,
const char *name,
struct attrlist *attrib_set,
fsal_verifier_t verifier,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out,
bool *caller_perm_check)
{
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
int p_flags = 0;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
struct glusterfs_handle *myself, *parenthandle = NULL;
struct glusterfs_fd *my_fd = NULL, tmp_fd = {0};
struct stat sb = {0};
struct glfs_object *glhandle = NULL;
unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
char vol_uuid[GLAPI_UUID_LENGTH] = {'\0'};
bool truncated;
bool created = false;
int retval = 0;
mode_t unix_mode;
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
if (state != NULL)
my_fd = (struct glusterfs_fd *)(state + 1);
fsal2posix_openflags(openflags, &p_flags);
truncated = (p_flags & O_TRUNC) != 0;
if (createmode >= FSAL_EXCLUSIVE) {
/* Now fixup attrs for verifier if exclusive create */
set_common_verifier(attrib_set, verifier);
}
if (name == NULL) {
/* This is an open by handle */
struct glusterfs_handle *myself;
myself = container_of(obj_hdl,
struct glusterfs_handle,
handle);
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
if (state != NULL) {
/* Prepare to take the share reservation, but only if we
* are called with a valid state (if state is NULL the
* caller is a stateless create such as NFS v3 CREATE).
*/
/* This can block over an I/O operation. */
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
/* Check share reservation conflicts. */
status = check_share_conflict(&myself->share,
openflags,
false);
if (FSAL_IS_ERROR(status)) {
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* Take the share reservation now by updating the
* counters.
*/
update_share_counters(&myself->share,
FSAL_O_CLOSED,
openflags);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
} else {
/* We need to use the global fd to continue, and take
* the lock to protect it.
*/
my_fd = &myself->globalfd;
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
}
/* truncate is set in p_flags */
status = glusterfs_open_my_fd(myself, openflags, p_flags,
&tmp_fd);
if (FSAL_IS_ERROR(status)) {
status = gluster2fsal_error(errno);
if (state == NULL) {
/* Release the lock taken above, and return
* since there is nothing to undo.
*/
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
goto out;
} else {
/* Error - need to release the share */
goto undo_share;
}
}
my_fd->glfd = tmp_fd.glfd;
my_fd->openflags = tmp_fd.openflags;
if (createmode >= FSAL_EXCLUSIVE || truncated) {
/* Fetch the attributes to check against the
* verifier in case of exclusive open/create.
*/
struct stat stat;
retval = glfs_fstat(my_fd->glfd, &stat);
if (retval == 0) {
LogFullDebug(COMPONENT_FSAL,
"New size = %" PRIx64,
stat.st_size);
} else {
if (errno == EBADF)
errno = ESTALE;
status = fsalstat(posix2fsal_error(errno),
errno);
}
/* Now check verifier for exclusive, but not for
* FSAL_EXCLUSIVE_9P.
*/
if (!FSAL_IS_ERROR(status) &&
createmode >= FSAL_EXCLUSIVE &&
createmode != FSAL_EXCLUSIVE_9P &&
!check_verifier_stat(&stat,
verifier)) {
/* Verifier didn't match, return EEXIST */
status =
fsalstat(posix2fsal_error(EEXIST), EEXIST);
}
}
if (state == NULL) {
/* If no state, release the lock taken above and return
* status. If success, we haven't done any permission
* check so ask the caller to do so.
*/
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
*caller_perm_check = !FSAL_IS_ERROR(status);
return status;
}
if (!FSAL_IS_ERROR(status)) {
/* Return success. We haven't done any permission
* check so ask the caller to do so.
*/
*caller_perm_check = true;
return status;
}
(void) glusterfs_close_my_fd(my_fd);
undo_share:
/* Can only get here with state not NULL and an error */
/* On error we need to release our share reservation
* and undo the update of the share counters.
* This can block over an I/O operation.
*/
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
update_share_counters(&myself->share,
openflags,
FSAL_O_CLOSED);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* case name_not_null */
/* In this path where we are opening by name, we can't check share
* reservation yet since we don't have an object_handle yet. If we
* indeed create the object handle (there is no race with another
* open by name), then there CAN NOT be a share conflict, otherwise
* the share conflict will be resolved when the object handles are
* merged.
*/
if (createmode != FSAL_NO_CREATE) {
/* Now add in O_CREAT and O_EXCL. */
p_flags |= O_CREAT;
/* And if we are at least FSAL_GUARDED, do an O_EXCL create. */
if (createmode >= FSAL_GUARDED)
p_flags |= O_EXCL;
/* Fetch the mode attribute to use. */
unix_mode = fsal2unix_mode(attrib_set->mode) &
~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
/* Don't set the mode if we later set the attributes */
FSAL_UNSET_MASK(attrib_set->valid_mask, ATTR_MODE);
}
if (createmode == FSAL_UNCHECKED && (attrib_set->valid_mask != 0)) {
/* If we have FSAL_UNCHECKED and want to set more attributes
* than the mode, we attempt an O_EXCL create first, if that
* succeeds, then we will be allowed to set the additional
* attributes, otherwise, we don't know we created the file
* and this can NOT set the attributes.
*/
p_flags |= O_EXCL;
}
/** @todo: we do not have openat implemented yet..meanwhile
* use 'glfs_h_creat'
*/
/* obtain parent directory handle */
parenthandle =
container_of(obj_hdl, struct glusterfs_handle, handle);
if (createmode == FSAL_NO_CREATE) {
/* lookup if the object exists */
status = (obj_hdl)->obj_ops.lookup(obj_hdl,
name,
new_obj,
attrs_out);
if (FSAL_IS_ERROR(status)) {
*new_obj = NULL;
goto direrr;
}
myself = container_of(*new_obj,
struct glusterfs_handle,
handle);
/* The open is not done with the caller's credentials so ask
* the caller to perform a permission check.
*/
*caller_perm_check = true;
goto open;
}
/* Become the user because we are creating an object in this dir.
*/
/* set proper credentials */
retval = setglustercreds(glfs_export,
&op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL,
"Could not set Ganesha credentials");
goto out;
}
/** @todo: glfs_h_creat doesn't honour NO_CREATE mode. Instead use
* glfs_h_open to verify if the file already exists.
*/
glhandle =
glfs_h_creat(glfs_export->gl_fs, parenthandle->glhandle, name,
p_flags, unix_mode, &sb);
if (glhandle == NULL && errno == EEXIST &&
createmode == FSAL_UNCHECKED) {
/* We tried to create O_EXCL to set attributes and failed.
* Remove O_EXCL and retry, also remember not to set attributes.
* We still try O_CREAT again just in case file disappears out
* from under us.
*
* Note that because we have dropped O_EXCL, later on we will
* not assume we created the file, and thus will not set
* additional attributes. We don't need to separately track
* the condition of not wanting to set attributes.
*/
p_flags &= ~O_EXCL;
glhandle =
glfs_h_creat(glfs_export->gl_fs, parenthandle->glhandle,
name, p_flags, unix_mode, &sb);
}
/* preserve errno */
retval = errno;
/* restore credentials */
retval = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL,
"Could not set Ganesha credentials");
goto out;
}
if (glhandle == NULL) {
status = gluster2fsal_error(errno);
goto out;
}
/* Remember if we were responsible for creating the file.
* Note that in an UNCHECKED retry we MIGHT have re-created the
* file and won't remember that. Oh well, so in that rare case we
* leak a partially created file if we have a subsequent error in here.
* Also notify caller to do permission check if we DID NOT create the
* file. Note it IS possible in the case of a race between an UNCHECKED
* open and an external unlink, we did create the file, but we will
* still force a permission check. That permission check might fail
* if the file created after the unlink has a mode that doesn't allow
* the caller/creator to open the file (on the other hand, one hopes
* a non-exclusive open doesn't set a mode that doesn't allow read/write
* since the application clearly expects that another process may have
* created the file). This failure case really isn't too awful since
* it would just look to the caller like someone else had created the
* file with a mode that prevented the open this caller was attempting.
*/
created = (p_flags & O_EXCL) != 0;
*caller_perm_check = !created;
/* Since the file is created, remove O_CREAT/O_EXCL flags */
p_flags &= ~(O_EXCL | O_CREAT);
retval = glfs_h_extract_handle(glhandle, globjhdl, GFAPI_HANDLE_LENGTH);
if (retval < 0) {
status = gluster2fsal_error(errno);
goto direrr;
}
retval = glfs_get_volumeid(glfs_export->gl_fs, vol_uuid,
GLAPI_UUID_LENGTH);
if (retval < 0) {
status = gluster2fsal_error(retval);
goto direrr;
}
construct_handle(glfs_export, &sb, glhandle, globjhdl,
GLAPI_HANDLE_LENGTH, &myself, vol_uuid);
/* If we didn't have a state above, use the global fd. At this point,
* since we just created the global fd, no one else can have a
* reference to it, and thus we can mamnipulate unlocked which is
* handy since we can then call setattr2 which WILL take the lock
* without a double locking deadlock.
*/
if (my_fd == NULL)
my_fd = &myself->globalfd;
open:
/* now open it */
status = glusterfs_open_my_fd(myself, openflags, p_flags, my_fd);
if (FSAL_IS_ERROR(status))
goto direrr;
*new_obj = &myself->handle;
if (created && attrib_set->valid_mask != 0) {
/* Set attributes using our newly opened file descriptor as the
* share_fd if there are any left to set (mode and truncate
* have already been handled).
*
* Note that we only set the attributes if we were responsible
* for creating the file and we have attributes to set.
*/
status = (*new_obj)->obj_ops.setattr2(*new_obj,
false,
state,
attrib_set);
if (FSAL_IS_ERROR(status)) {
/* Release the handle we just allocated. */
(*new_obj)->obj_ops.release(*new_obj);
/* We released handle at this point */
glhandle = NULL;
*new_obj = NULL;
goto fileerr;
}
if (attrs_out != NULL) {
status = (*new_obj)->obj_ops.getattrs(*new_obj,
attrs_out);
if (FSAL_IS_ERROR(status) &&
(attrs_out->request_mask & ATTR_RDATTR_ERR) == 0) {
/* Get attributes failed and caller expected
* to get the attributes. Otherwise continue
* with attrs_out indicating ATTR_RDATTR_ERR.
*/
goto fileerr;
}
}
} else if (attrs_out != NULL) {
/* Since we haven't set any attributes other than what was set
* on create (if we even created), just use the stat results
* we used to create the fsal_obj_handle.
*/
posix2fsal_attributes(&sb, attrs_out);
}
if (state != NULL) {
/* Prepare to take the share reservation, but only if we are
* called with a valid state (if state is NULL the caller is
* a stateless create such as NFS v3 CREATE).
*/
/* This can block over an I/O operation. */
PTHREAD_RWLOCK_wrlock(&(*new_obj)->lock);
/* Take the share reservation now by updating the counters. */
update_share_counters(&myself->share,
FSAL_O_CLOSED,
openflags);
PTHREAD_RWLOCK_unlock(&(*new_obj)->lock);
}
return fsalstat(ERR_FSAL_NO_ERROR, 0);
fileerr:
glusterfs_close_my_fd(my_fd);
direrr:
/* Delete the file if we actually created it. */
if (created)
glfs_h_unlink(glfs_export->gl_fs, parenthandle->glhandle, name);
if (status.major != ERR_FSAL_NO_ERROR)
gluster_cleanup_vars(glhandle);
return fsalstat(posix2fsal_error(retval), retval);
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_file_open);
#endif
return status;
}
/* reopen2
*/
static fsal_status_t glusterfs_reopen2(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
fsal_openflags_t openflags)
{
struct glusterfs_fd fd = {0}, *my_fd = &fd, *my_share_fd = NULL;
struct glusterfs_handle *myself;
fsal_status_t status = {0, 0};
int posix_flags = 0;
fsal_openflags_t old_openflags;
my_share_fd = (struct glusterfs_fd *)(state + 1);
fsal2posix_openflags(openflags, &posix_flags);
memset(my_fd, 0, sizeof(*my_fd));
myself = container_of(obj_hdl,
struct glusterfs_handle,
handle);
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
/* This can block over an I/O operation. */
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
old_openflags = my_share_fd->openflags;
/* We can conflict with old share, so go ahead and check now. */
status = check_share_conflict(&myself->share, openflags, false);
if (FSAL_IS_ERROR(status)) {
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* Set up the new share so we can drop the lock and not have a
* conflicting share be asserted, updating the share counters.
*/
update_share_counters(&myself->share, old_openflags, openflags);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
status = glusterfs_open_my_fd(myself, openflags, posix_flags, my_fd);
if (!FSAL_IS_ERROR(status)) {
/* Close the existing file descriptor and copy the new
* one over.
*/
glusterfs_close_my_fd(my_share_fd);
*my_share_fd = fd;
} else {
/* We had a failure on open - we need to revert the share.
* This can block over an I/O operation.
*/
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
update_share_counters(&myself->share,
openflags,
old_openflags);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
}
return status;
}
/* read2
*/
static fsal_status_t glusterfs_read2(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
uint64_t seek_descriptor,
size_t buffer_size,
void *buffer, size_t *read_amount,
bool *end_of_file,
struct io_info *info)
{
struct glusterfs_fd my_fd = {0};
ssize_t nb_read;
fsal_status_t status;
int retval = 0;
bool has_lock = false;
bool need_fsync = false;
bool closefd = false;
if (info != NULL) {
/* Currently we don't support READ_PLUS */
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
/* Get a usable file descriptor */
status = find_fd(&my_fd, obj_hdl, bypass, state, FSAL_O_READ,
&has_lock, &need_fsync, &closefd, false);
if (FSAL_IS_ERROR(status))
goto out;
nb_read = glfs_pread(my_fd.glfd, buffer, buffer_size,
seek_descriptor, 0);
if (seek_descriptor == -1 || nb_read == -1) {
retval = errno;
status = fsalstat(posix2fsal_error(retval), retval);
goto out;
}
*read_amount = nb_read;
if (nb_read < buffer_size)
*end_of_file = true;
#if 0
/** @todo
*
* Is this all we really need to do to support READ_PLUS? Will anyone
* ever get upset that we don't return holes, even for blocks of all
* zeroes?
*
*/
if (info != NULL) {
info->io_content.what = NFS4_CONTENT_DATA;
info->io_content.data.d_offset = offset + nb_read;
info->io_content.data.d_data.data_len = nb_read;
info->io_content.data.d_data.data_val = buffer;
}
#endif
out:
if (closefd)
glusterfs_close_my_fd(&my_fd);
if (has_lock)
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* write2
*/
static fsal_status_t glusterfs_write2(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
uint64_t seek_descriptor,
size_t buffer_size,
void *buffer,
size_t *write_amount,
bool *fsal_stable,
struct io_info *info)
{
ssize_t nb_written;
fsal_status_t status;
int retval = 0;
struct glusterfs_fd my_fd = {0};
bool has_lock = false;
bool need_fsync = false;
bool closefd = false;
fsal_openflags_t openflags = FSAL_O_WRITE;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
if (info != NULL) {
/* Currently we don't support WRITE_PLUS */
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
/* Get a usable file descriptor */
status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
&has_lock, &need_fsync, &closefd, false);
if (FSAL_IS_ERROR(status))
goto out;
retval = setglustercreds(glfs_export, &op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
nb_written = glfs_pwrite(my_fd.glfd, buffer, buffer_size,
seek_descriptor, ((*fsal_stable) ? O_SYNC : 0));
if (nb_written == -1) {
retval = errno;
status = fsalstat(posix2fsal_error(retval), retval);
goto out;
}
*write_amount = nb_written;
/* restore credentials */
retval = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
goto out;
}
out:
if (closefd)
glusterfs_close_my_fd(&my_fd);
if (has_lock)
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* commit2
*/
static fsal_status_t glusterfs_commit2(struct fsal_obj_handle *obj_hdl,
off_t offset,
size_t len)
{
fsal_status_t status;
int retval;
struct glusterfs_fd tmp_fd = {0, NULL}, *out_fd = &tmp_fd;
struct glusterfs_handle *myself = NULL;
bool has_lock = false;
bool closefd = false;
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export,
struct glusterfs_export, export);
myself = container_of(obj_hdl, struct glusterfs_handle, handle);
/* Make sure file is open in appropriate mode.
* Do not check share reservation.
*/
status = fsal_reopen_obj(obj_hdl, false, false, FSAL_O_WRITE,
(struct fsal_fd *)&myself->globalfd,
&myself->share, glusterfs_open_func,
glusterfs_close_func,
(struct fsal_fd **)&out_fd,
&has_lock, &closefd);
if (!FSAL_IS_ERROR(status)) {
retval = setglustercreds(glfs_export,
&op_ctx->creds->caller_uid,
&op_ctx->creds->caller_gid,
op_ctx->creds->caller_glen,
op_ctx->creds->caller_garray);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL,
"Could not set Ganesha credentials");
goto out;
}
retval = glfs_fsync(out_fd->glfd);
if (retval == -1) {
retval = errno;
status = fsalstat(posix2fsal_error(retval), retval);
}
/* restore credentials */
retval = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
if (retval != 0) {
status = gluster2fsal_error(EPERM);
LogFatal(COMPONENT_FSAL,
"Could not set Ganesha credentials");
goto out;
}
}
out:
if (closefd)
glusterfs_close_my_fd(out_fd);
if (has_lock)
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* lock_op2
*/
static fsal_status_t glusterfs_lock_op2(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
void *p_owner,
fsal_lock_op_t lock_op,
fsal_lock_param_t *request_lock,
fsal_lock_param_t *conflicting_lock)
{
struct flock lock_args;
int fcntl_comm;
fsal_status_t status = {0, 0};
int retval = 0;
struct glusterfs_fd my_fd = {0};
bool has_lock = false;
bool need_fsync = false;
bool closefd = false;
bool bypass = false;
fsal_openflags_t openflags = FSAL_O_RDWR;
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
LogFullDebug(COMPONENT_FSAL,
"Locking: op(%d) type(%d) start(%" PRIu64
") length(%" PRIu64 ")",
lock_op, request_lock->lock_type, request_lock->lock_start,
request_lock->lock_length);
if (lock_op == FSAL_OP_LOCKT) {
/* We may end up using global fd, don't fail on a deny mode */
bypass = true;
fcntl_comm = F_GETLK;
openflags = FSAL_O_ANY;
} else if (lock_op == FSAL_OP_LOCK) {
fcntl_comm = F_SETLK;
if (request_lock->lock_type == FSAL_LOCK_R)
openflags = FSAL_O_READ;
else if (request_lock->lock_type == FSAL_LOCK_W)
openflags = FSAL_O_WRITE;
} else if (lock_op == FSAL_OP_UNLOCK) {
fcntl_comm = F_SETLK;
openflags = FSAL_O_ANY;
} else {
LogDebug(COMPONENT_FSAL,
"ERROR: Lock operation requested was not TEST, READ, or WRITE.");
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
if (lock_op != FSAL_OP_LOCKT && state == NULL) {
LogCrit(COMPONENT_FSAL, "Non TEST operation with NULL state");
return fsalstat(posix2fsal_error(EINVAL), EINVAL);
}
if (request_lock->lock_type == FSAL_LOCK_R) {
lock_args.l_type = F_RDLCK;
} else if (request_lock->lock_type == FSAL_LOCK_W) {
lock_args.l_type = F_WRLCK;
} else {
LogDebug(COMPONENT_FSAL,
"ERROR: The requested lock type was not read or write.");
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
if (lock_op == FSAL_OP_UNLOCK)
lock_args.l_type = F_UNLCK;
lock_args.l_pid = 0;
lock_args.l_len = request_lock->lock_length;
lock_args.l_start = request_lock->lock_start;
lock_args.l_whence = SEEK_SET;
/* flock.l_len being signed long integer, larger lock ranges may
* get mapped to negative values. As per 'man 3 fcntl', posix
* locks can accept negative l_len values which may lead to
* unlocking an unintended range. Better bail out to prevent that.
*/
if (lock_args.l_len < 0) {
LogCrit(COMPONENT_FSAL,
"The requested lock length is out of range: lock_args.l_len(%"
PRId64 "), request_lock_length(%" PRIu64 ")",
lock_args.l_len, request_lock->lock_length);
return fsalstat(ERR_FSAL_BAD_RANGE, 0);
}
/* Get a usable file descriptor */
status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
&has_lock, &need_fsync, &closefd, true);
if (FSAL_IS_ERROR(status)) {
LogCrit(COMPONENT_FSAL, "Unable to find fd for lock operation");
return status;
}
/** @todo: setlkowner as well */
errno = 0;
retval = glfs_posix_lock(my_fd.glfd, fcntl_comm, &lock_args);
if (retval /* && lock_op == FSAL_OP_LOCK */) {
retval = errno;
int rc = 0;
LogDebug(COMPONENT_FSAL,
"fcntl returned %d %s",
retval, strerror(retval));
if (conflicting_lock != NULL) {
/* Get the conflicting lock */
rc = glfs_posix_lock(my_fd.glfd, F_GETLK,
&lock_args);
if (rc) {
retval = errno; /* we lose the initial error */
LogCrit(COMPONENT_FSAL,
"After failing a lock request, I couldn't even get the details of who owns the lock.");
goto err;
}
conflicting_lock->lock_length = lock_args.l_len;
conflicting_lock->lock_start = lock_args.l_start;
conflicting_lock->lock_type = lock_args.l_type;
}
goto err;
}
/* F_UNLCK is returned then the tested operation would be possible. */
if (conflicting_lock != NULL) {
if (lock_op == FSAL_OP_LOCKT && lock_args.l_type != F_UNLCK) {
conflicting_lock->lock_length = lock_args.l_len;
conflicting_lock->lock_start = lock_args.l_start;
conflicting_lock->lock_type = lock_args.l_type;
} else {
conflicting_lock->lock_length = 0;
conflicting_lock->lock_start = 0;
conflicting_lock->lock_type = FSAL_NO_LOCK;
}
}
/* Fall through (retval == 0) */
err:
if (closefd)
glusterfs_close_my_fd(&my_fd);
if (has_lock)
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return fsalstat(posix2fsal_error(retval), retval);
}
/**
* @brief Set attributes on an object
*
* This function sets attributes on an object. Which attributes are
* set is determined by attrib_set->valid_mask. The FSAL must manage bypass
* or not of share reservations, and a state may be passed.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in] attrib_set Attributes to set
*
* @return FSAL status.
*/
static fsal_status_t glusterfs_setattr2(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
struct attrlist *attrib_set)
{
struct glusterfs_handle *myself;
fsal_status_t status = {0, 0};
int retval = 0;
fsal_openflags_t openflags = FSAL_O_ANY;
bool has_lock = false;
bool need_fsync = false;
bool closefd = false;
struct glusterfs_fd my_fd = {0};
struct glusterfs_export *glfs_export =
container_of(op_ctx->fsal_export, struct glusterfs_export, export);
glusterfs_fsal_xstat_t buffxstat;
int attr_valid = 0;
int mask = 0;
/** @todo: Handle special file symblic links etc */
/* apply umask, if mode attribute is to be changed */
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MODE))
attrib_set->mode &=
~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
myself = container_of(obj_hdl, struct glusterfs_handle, handle);
#if 0
/** @todo: fsid work */
if (obj_hdl->fsal != obj_hdl->fs->fsal) {
LogDebug(COMPONENT_FSAL,
"FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
return fsalstat(posix2fsal_error(EXDEV), EXDEV);
}
#endif
/* Test if size is being set, make sure file is regular and if so,
* require a read/write file descriptor.
*/
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_SIZE)) {
if (obj_hdl->type != REGULAR_FILE)
return fsalstat(ERR_FSAL_INVAL, EINVAL);
openflags = FSAL_O_RDWR;
}
/** TRUNCATE **/
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_SIZE) &&
(obj_hdl->type == REGULAR_FILE)) {
/* Get a usable file descriptor. Share conflict is only
* possible if size is being set. For special files,
* handle via handle.
*/
status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
&has_lock, &need_fsync, &closefd, false);
if (FSAL_IS_ERROR(status))
goto out;
retval = glfs_ftruncate(my_fd.glfd, attrib_set->filesize);
if (retval != 0) {
if (retval != 0) {
status = gluster2fsal_error(errno);
goto out;
}
}
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MODE)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_MODE);
buffxstat.buffstat.st_mode = fsal2unix_mode(attrib_set->mode);
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_OWNER)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_UID);
buffxstat.buffstat.st_uid = attrib_set->owner;
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_GROUP)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_GID);
buffxstat.buffstat.st_gid = attrib_set->group;
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ATIME)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_ATIME);
buffxstat.buffstat.st_atim = attrib_set->atime;
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ATIME_SERVER)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_ATIME);
struct timespec timestamp;
retval = clock_gettime(CLOCK_REALTIME, &timestamp);
if (retval != 0) {
status = gluster2fsal_error(errno);
goto out;
}
buffxstat.buffstat.st_atim = timestamp;
}
/* try to look at glfs_futimens() instead as done in vfs */
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MTIME)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_MTIME);
buffxstat.buffstat.st_mtim = attrib_set->mtime;
}
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MTIME_SERVER)) {
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_MTIME);
struct timespec timestamp;
retval = clock_gettime(CLOCK_REALTIME, &timestamp);
if (retval != 0) {
status = gluster2fsal_error(retval);
goto out;
}
buffxstat.buffstat.st_mtim = timestamp;
}
/** @todo: Check for attributes not supported and return */
/* EATTRNOTSUPP error. */
if (NFSv4_ACL_SUPPORT) {
if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ACL)) {
if (obj_hdl->type == DIRECTORY)
buffxstat.is_dir = true;
else
buffxstat.is_dir = false;
FSAL_SET_MASK(attr_valid, XATTR_ACL);
status =
glusterfs_process_acl(glfs_export->gl_fs,
myself->glhandle,
attrib_set, &buffxstat);
if (FSAL_IS_ERROR(status))
goto out;
/* setting the ACL will set the */
/* mode-bits too if not already passed */
FSAL_SET_MASK(mask, GLAPI_SET_ATTR_MODE);
}
} else if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ACL)) {
status = fsalstat(ERR_FSAL_ATTRNOTSUPP, 0);
goto out;
}
/* If any stat changed, indicate that */
if (mask != 0)
FSAL_SET_MASK(attr_valid, XATTR_STAT);
if (FSAL_TEST_MASK(attr_valid, XATTR_STAT)) {
/* Only if there is any change in attrs send them down to fs */
/** @todo: instead use glfs_fsetattr().... looks like there is
* fix needed in there..it doesn't convert the mask flags
* to corresponding gluster flags.
*/
retval = glfs_h_setattrs(glfs_export->gl_fs,
myself->glhandle,
&buffxstat.buffstat,
mask);
if (retval != 0) {
status = gluster2fsal_error(errno);
goto out;
}
}
if (FSAL_TEST_MASK(attr_valid, XATTR_ACL))
status = glusterfs_set_acl(glfs_export, myself, &buffxstat);
if (FSAL_IS_ERROR(status)) {
LogDebug(COMPONENT_FSAL,
"setting ACL failed");
goto out;
}
out:
if (FSAL_IS_ERROR(status)) {
LogCrit(COMPONENT_FSAL,
"setattrs failed with error %s",
strerror(status.minor));
}
if (closefd)
glusterfs_close_my_fd(&my_fd);
if (has_lock)
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
return status;
}
/* close2
*/
static fsal_status_t glusterfs_close2(struct fsal_obj_handle *obj_hdl,
struct state_t *state)
{
struct glusterfs_fd *my_fd = (struct glusterfs_fd *)(state + 1);
struct glusterfs_handle *myself = NULL;
myself = container_of(obj_hdl,
struct glusterfs_handle,
handle);
if (state->state_type == STATE_TYPE_SHARE ||
state->state_type == STATE_TYPE_NLM_SHARE ||
state->state_type == STATE_TYPE_9P_FID) {
/* This is a share state, we must update the share counters */
/* This can block over an I/O operation. */
PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
update_share_counters(&myself->share,
my_fd->openflags,
FSAL_O_CLOSED);
PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
}
return glusterfs_close_my_fd(my_fd);
}
/**
* @brief Implements GLUSTER FSAL objectoperation list_ext_attrs
*/
/*
static fsal_status_t list_ext_attrs(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
unsigned int cookie,
fsal_xattrent_t * xattrs_tab,
unsigned int xattrs_tabsize,
unsigned int *p_nb_returned,
int *end_of_list)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation getextattr_id_by_name
*/
/*
static fsal_status_t getextattr_id_by_name(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
const char *xattr_name,
unsigned int *pxattr_id)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation getextattr_value_by_name
*/
/*
static fsal_status_t getextattr_value_by_name(struct fsal_obj_handle *obj_hdl,
const struct
req_op_context *opctx,
const char *xattr_name,
caddr_t buffer_addr,
size_t buffer_size,
size_t * p_output_size)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation getextattr_value_by_id
*/
/*
static fsal_status_t getextattr_value_by_id(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
unsigned int xattr_id,
caddr_t buffer_addr,
size_t buffer_size,
size_t *p_output_size)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation setextattr_value
*/
/*
static fsal_status_t setextattr_value(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
const char *xattr_name,
caddr_t buffer_addr,
size_t buffer_size,
int create)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation setextattr_value_by_id
*/
/*
static fsal_status_t setextattr_value_by_id(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
unsigned int xattr_id,
caddr_t buffer_addr,
size_t buffer_size)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation getextattr_attrs
*/
/*
static fsal_status_t getextattr_attrs(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
unsigned int xattr_id,
struct attrlist* p_attrs)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation remove_extattr_by_id
*/
/*
static fsal_status_t remove_extattr_by_id(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
unsigned int xattr_id)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation remove_extattr_by_name
*/
/*
static fsal_status_t remove_extattr_by_name(struct fsal_obj_handle *obj_hdl,
const struct req_op_context *opctx,
const char *xattr_name)
{
return fsalstat(ERR_FSAL_NOTSUPP, 0);
}
*/
/**
* @brief Implements GLUSTER FSAL objectoperation handle_digest
*/
static fsal_status_t handle_digest(const struct fsal_obj_handle *obj_hdl,
fsal_digesttype_t output_type,
struct gsh_buffdesc *fh_desc)
{
fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
size_t fh_size;
struct glusterfs_handle *objhandle;
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
if (!fh_desc)
return fsalstat(ERR_FSAL_FAULT, 0);
objhandle = container_of(obj_hdl, struct glusterfs_handle, handle);
switch (output_type) {
case FSAL_DIGEST_NFSV3:
case FSAL_DIGEST_NFSV4:
fh_size = GLAPI_HANDLE_LENGTH;
if (fh_desc->len < fh_size) {
LogMajor(COMPONENT_FSAL,
"Space too small for handle. need %zu, have %zu",
fh_size, fh_desc->len);
status.major = ERR_FSAL_TOOSMALL;
goto out;
}
memcpy(fh_desc->addr, objhandle->globjhdl, fh_size);
break;
default:
status.major = ERR_FSAL_SERVERFAULT;
goto out;
}
fh_desc->len = fh_size;
out:
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_handle_digest);
#endif
return status;
}
/**
* @brief Implements GLUSTER FSAL objectoperation handle_to_key
*/
static void handle_to_key(struct fsal_obj_handle *obj_hdl,
struct gsh_buffdesc *fh_desc)
{
struct glusterfs_handle *objhandle;
#ifdef GLTIMING
struct timespec s_time, e_time;
now(&s_time);
#endif
objhandle = container_of(obj_hdl, struct glusterfs_handle, handle);
fh_desc->addr = objhandle->globjhdl;
fh_desc->len = GLAPI_HANDLE_LENGTH;
#ifdef GLTIMING
now(&e_time);
latency_update(&s_time, &e_time, lat_handle_to_key);
#endif
}
/**
* @brief Registers GLUSTER FSAL objectoperation vector
*/
void handle_ops_init(struct fsal_obj_ops *ops)
{
ops->release = handle_release;
ops->merge = glusterfs_merge;
ops->lookup = lookup;
ops->create = create;
ops->mkdir = makedir;
ops->mknode = makenode;
ops->readdir = read_dirents;
ops->symlink = makesymlink;
ops->readlink = readsymlink;
ops->getattrs = getattrs;
ops->link = linkfile;
ops->rename = renamefile;
ops->unlink = file_unlink;
ops->handle_digest = handle_digest;
ops->handle_to_key = handle_to_key;
ops->close = file_close;
/* fops with OpenTracking (multi-fd) enabled */
ops->open2 = glusterfs_open2;
ops->reopen2 = glusterfs_reopen2;
ops->read2 = glusterfs_read2;
ops->write2 = glusterfs_write2;
ops->commit2 = glusterfs_commit2;
ops->lock_op2 = glusterfs_lock_op2;
ops->setattr2 = glusterfs_setattr2;
ops->close2 = glusterfs_close2;
/* pNFS related ops */
handle_ops_pnfs(ops);
}