acl.c 4.3 KB
Newer Older
M
Mike Marshall 已提交
1 2 3 4 5 6 7
/*
 * (C) 2001 Clemson University and The University of Chicago
 *
 * See COPYING in top-level directory.
 */

#include "protocol.h"
8 9
#include "orangefs-kernel.h"
#include "orangefs-bufmap.h"
M
Mike Marshall 已提交
10 11 12
#include <linux/posix_acl_xattr.h>
#include <linux/fs_struct.h>

13
struct posix_acl *orangefs_get_acl(struct inode *inode, int type)
M
Mike Marshall 已提交
14 15 16 17 18 19 20
{
	struct posix_acl *acl;
	int ret;
	char *key = NULL, *value = NULL;

	switch (type) {
	case ACL_TYPE_ACCESS:
21
		key = ORANGEFS_XATTR_NAME_ACL_ACCESS;
M
Mike Marshall 已提交
22 23
		break;
	case ACL_TYPE_DEFAULT:
24
		key = ORANGEFS_XATTR_NAME_ACL_DEFAULT;
M
Mike Marshall 已提交
25 26
		break;
	default:
27
		gossip_err("orangefs_get_acl: bogus value of type %d\n", type);
M
Mike Marshall 已提交
28 29 30 31 32 33
		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
34
	 * orangefs_inode_getxattr() to probe the length of the value, but
M
Mike Marshall 已提交
35 36
	 * I don't do that for now.
	 */
37
	value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
M
Mike Marshall 已提交
38 39 40 41 42 43 44 45
	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);
46
	ret = orangefs_inode_getxattr(inode,
M
Mike Marshall 已提交
47 48 49
				   "",
				   key,
				   value,
50
				   ORANGEFS_MAX_XATTR_VALUELEN);
M
Mike Marshall 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
	/* 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;
}

67
int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
M
Mike Marshall 已提交
68
{
69
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
M
Mike Marshall 已提交
70 71 72 73 74 75 76
	int error = 0;
	void *value = NULL;
	size_t size = 0;
	const char *name = NULL;

	switch (type) {
	case ACL_TYPE_ACCESS:
77
		name = ORANGEFS_XATTR_NAME_ACL_ACCESS;
M
Mike Marshall 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
		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)
93
				SetModeFlag(orangefs_inode);
M
Mike Marshall 已提交
94 95 96 97 98 99 100
			inode->i_mode = mode;
			mark_inode_dirty_sync(inode);
			if (error == 0)
				acl = NULL;
		}
		break;
	case ACL_TYPE_DEFAULT:
101
		name = ORANGEFS_XATTR_NAME_ACL_DEFAULT;
M
Mike Marshall 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
		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.
	 */
134
	error = orangefs_inode_setxattr(inode, "", name, value, size, 0);
M
Mike Marshall 已提交
135 136 137 138 139 140 141 142

out:
	kfree(value);
	if (!error)
		set_cached_acl(inode, type, acl);
	return error;
}

143
int orangefs_init_acl(struct inode *inode, struct inode *dir)
M
Mike Marshall 已提交
144
{
145
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
M
Mike Marshall 已提交
146 147 148 149
	struct posix_acl *default_acl, *acl;
	umode_t mode = inode->i_mode;
	int error = 0;

150
	ClearModeFlag(orangefs_inode);
M
Mike Marshall 已提交
151 152 153 154 155 156

	error = posix_acl_create(dir, &mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
157
		error = orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
M
Mike Marshall 已提交
158 159 160 161 162
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!error)
163
			error = orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
M
Mike Marshall 已提交
164 165 166 167 168
		posix_acl_release(acl);
	}

	/* If mode of the inode was changed, then do a forcible ->setattr */
	if (mode != inode->i_mode) {
169
		SetModeFlag(orangefs_inode);
M
Mike Marshall 已提交
170
		inode->i_mode = mode;
171
		orangefs_flush_inode(inode);
M
Mike Marshall 已提交
172 173 174 175
	}

	return error;
}