Commit 5db11c21 authored by Mike Marshall's avatar Mike Marshall

Orangefs: kernel client part 2

Signed-off-by: default avatarMike Marshall <hubcap@omnibond.com>
parent f7ab093f
/*
* (C) 2001 Clemson University and The University of Chicago
*
* See COPYING in top-level directory.
*/
#include "protocol.h"
#include "pvfs2-kernel.h"
#include "pvfs2-bufmap.h"
#include <linux/posix_acl_xattr.h>
#include <linux/fs_struct.h>
struct posix_acl *pvfs2_get_acl(struct inode *inode, int type)
{
struct posix_acl *acl;
int ret;
char *key = NULL, *value = NULL;
switch (type) {
case ACL_TYPE_ACCESS:
key = PVFS2_XATTR_NAME_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
key = PVFS2_XATTR_NAME_ACL_DEFAULT;
break;
default:
gossip_err("pvfs2_get_acl: bogus value of type %d\n", type);
return ERR_PTR(-EINVAL);
}
/*
* Rather than incurring a network call just to determine the exact
* length of the attribute, I just allocate a max length to save on
* the network call. Conceivably, we could pass NULL to
* pvfs2_inode_getxattr() to probe the length of the value, but
* I don't do that for now.
*/
value = kmalloc(PVFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
if (value == NULL)
return ERR_PTR(-ENOMEM);
gossip_debug(GOSSIP_ACL_DEBUG,
"inode %pU, key %s, type %d\n",
get_khandle_from_ino(inode),
key,
type);
ret = pvfs2_inode_getxattr(inode,
"",
key,
value,
PVFS_MAX_XATTR_VALUELEN);
/* if the key exists, convert it to an in-memory rep */
if (ret > 0) {
acl = posix_acl_from_xattr(&init_user_ns, value, ret);
} else if (ret == -ENODATA || ret == -ENOSYS) {
acl = NULL;
} else {
gossip_err("inode %pU retrieving acl's failed with error %d\n",
get_khandle_from_ino(inode),
ret);
acl = ERR_PTR(ret);
}
/* kfree(NULL) is safe, so don't worry if value ever got used */
kfree(value);
return acl;
}
int pvfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
int error = 0;
void *value = NULL;
size_t size = 0;
const char *name = NULL;
switch (type) {
case ACL_TYPE_ACCESS:
name = PVFS2_XATTR_NAME_ACL_ACCESS;
if (acl) {
umode_t mode = inode->i_mode;
/*
* can we represent this with the traditional file
* mode permission bits?
*/
error = posix_acl_equiv_mode(acl, &mode);
if (error < 0) {
gossip_err("%s: posix_acl_equiv_mode err: %d\n",
__func__,
error);
return error;
}
if (inode->i_mode != mode)
SetModeFlag(pvfs2_inode);
inode->i_mode = mode;
mark_inode_dirty_sync(inode);
if (error == 0)
acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
name = PVFS2_XATTR_NAME_ACL_DEFAULT;
break;
default:
gossip_err("%s: invalid type %d!\n", __func__, type);
return -EINVAL;
}
gossip_debug(GOSSIP_ACL_DEBUG,
"%s: inode %pU, key %s type %d\n",
__func__, get_khandle_from_ino(inode),
name,
type);
if (acl) {
size = posix_acl_xattr_size(acl->a_count);
value = kmalloc(size, GFP_KERNEL);
if (!value)
return -ENOMEM;
error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
if (error < 0)
goto out;
}
gossip_debug(GOSSIP_ACL_DEBUG,
"%s: name %s, value %p, size %zd, acl %p\n",
__func__, name, value, size, acl);
/*
* Go ahead and set the extended attribute now. NOTE: Suppose acl
* was NULL, then value will be NULL and size will be 0 and that
* will xlate to a removexattr. However, we don't want removexattr
* complain if attributes does not exist.
*/
error = pvfs2_inode_setxattr(inode, "", name, value, size, 0);
out:
kfree(value);
if (!error)
set_cached_acl(inode, type, acl);
return error;
}
int pvfs2_init_acl(struct inode *inode, struct inode *dir)
{
struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
struct posix_acl *default_acl, *acl;
umode_t mode = inode->i_mode;
int error = 0;
ClearModeFlag(pvfs2_inode);
error = posix_acl_create(dir, &mode, &default_acl, &acl);
if (error)
return error;
if (default_acl) {
error = pvfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
posix_acl_release(default_acl);
}
if (acl) {
if (!error)
error = pvfs2_set_acl(inode, acl, ACL_TYPE_ACCESS);
posix_acl_release(acl);
}
/* If mode of the inode was changed, then do a forcible ->setattr */
if (mode != inode->i_mode) {
SetModeFlag(pvfs2_inode);
inode->i_mode = mode;
pvfs2_flush_inode(inode);
}
return error;
}
/*
* (C) 2001 Clemson University and The University of Chicago
*
* See COPYING in top-level directory.
*/
/*
* Implementation of dentry (directory cache) functions.
*/
#include "protocol.h"
#include "pvfs2-kernel.h"
/* Returns 1 if dentry can still be trusted, else 0. */
static int pvfs2_revalidate_lookup(struct dentry *dentry)
{
struct dentry *parent_dentry = dget_parent(dentry);
struct inode *parent_inode = parent_dentry->d_inode;
struct pvfs2_inode_s *parent = PVFS2_I(parent_inode);
struct inode *inode = dentry->d_inode;
struct pvfs2_kernel_op_s *new_op;
int ret = 0;
int err = 0;
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
new_op = op_alloc(PVFS2_VFS_OP_LOOKUP);
if (!new_op)
goto out_put_parent;
new_op->upcall.req.lookup.sym_follow = PVFS2_LOOKUP_LINK_NO_FOLLOW;
new_op->upcall.req.lookup.parent_refn = parent->refn;
strncpy(new_op->upcall.req.lookup.d_name,
dentry->d_name.name,
PVFS2_NAME_LEN);
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s:%s:%d interrupt flag [%d]\n",
__FILE__,
__func__,
__LINE__,
get_interruptible_flag(parent_inode));
err = service_operation(new_op, "pvfs2_lookup",
get_interruptible_flag(parent_inode));
if (err)
goto out_drop;
if (new_op->downcall.status != 0 ||
!match_handle(new_op->downcall.resp.lookup.refn.khandle, inode)) {
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s:%s:%d "
"lookup failure |%s| or no match |%s|.\n",
__FILE__,
__func__,
__LINE__,
new_op->downcall.status ? "true" : "false",
match_handle(new_op->downcall.resp.lookup.refn.khandle,
inode) ? "false" : "true");
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s:%s:%d revalidate failed\n",
__FILE__, __func__, __LINE__);
goto out_drop;
}
ret = 1;
out_release_op:
op_release(new_op);
out_put_parent:
dput(parent_dentry);
return ret;
out_drop:
d_drop(dentry);
goto out_release_op;
}
/*
* Verify that dentry is valid.
*
* Should return 1 if dentry can still be trusted, else 0
*/
static int pvfs2_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct inode *inode;
int ret = 0;
if (flags & LOOKUP_RCU)
return -ECHILD;
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
__func__, dentry);
/* find inode from dentry */
if (!dentry->d_inode) {
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
__func__);
goto invalid_exit;
}
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: inode valid.\n", __func__);
inode = dentry->d_inode;
/*
* first perform a lookup to make sure that the object not only
* exists, but is still in the expected place in the name space
*/
if (!is_root_handle(inode)) {
if (!pvfs2_revalidate_lookup(dentry))
goto invalid_exit;
} else {
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s: root handle, lookup skipped.\n",
__func__);
}
/* now perform getattr */
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s: doing getattr: inode: %p, handle: %pU\n",
__func__,
inode,
get_khandle_from_ino(inode));
ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT);
gossip_debug(GOSSIP_DCACHE_DEBUG,
"%s: getattr %s (ret = %d), returning %s for dentry i_count=%d\n",
__func__,
(ret == 0 ? "succeeded" : "failed"),
ret,
(ret == 0 ? "valid" : "INVALID"),
atomic_read(&inode->i_count));
if (ret != 0)
goto invalid_exit;
/* dentry is valid! */
return 1;
invalid_exit:
return 0;
}
const struct dentry_operations pvfs2_dentry_operations = {
.d_revalidate = pvfs2_d_revalidate,
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment