acl.c 3.1 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
J
Josef Bacik 已提交
2 3 4 5 6 7 8 9
/*
 * Copyright (C) 2007 Red Hat.  All rights reserved.
 */

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
J
Josef Bacik 已提交
10
#include <linux/posix_acl.h>
11
#include <linux/sched.h>
12
#include <linux/sched/mm.h>
13
#include <linux/slab.h>
J
Josef Bacik 已提交
14

J
Josef Bacik 已提交
15
#include "ctree.h"
J
Josef Bacik 已提交
16
#include "btrfs_inode.h"
J
Josef Bacik 已提交
17
#include "xattr.h"
J
Josef Bacik 已提交
18

19
struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
J
Josef Bacik 已提交
20
{
21 22
	int size;
	const char *name;
J
Josef Bacik 已提交
23
	char *value = NULL;
24 25
	struct posix_acl *acl;

J
Josef Bacik 已提交
26 27
	switch (type) {
	case ACL_TYPE_ACCESS:
28
		name = XATTR_NAME_POSIX_ACL_ACCESS;
J
Josef Bacik 已提交
29 30
		break;
	case ACL_TYPE_DEFAULT:
31
		name = XATTR_NAME_POSIX_ACL_DEFAULT;
J
Josef Bacik 已提交
32 33
		break;
	default:
34
		return ERR_PTR(-EINVAL);
J
Josef Bacik 已提交
35 36
	}

37
	size = btrfs_getxattr(inode, name, NULL, 0);
J
Josef Bacik 已提交
38
	if (size > 0) {
39
		value = kzalloc(size, GFP_KERNEL);
J
Josef Bacik 已提交
40 41
		if (!value)
			return ERR_PTR(-ENOMEM);
42
		size = btrfs_getxattr(inode, name, value, size);
43
	}
44
	if (size > 0)
45
		acl = posix_acl_from_xattr(&init_user_ns, value, size);
46
	else if (size == -ENODATA || size == 0)
J
Josef Bacik 已提交
47
		acl = NULL;
48
	else
49
		acl = ERR_PTR(size);
50 51
	kfree(value);

J
Josef Bacik 已提交
52 53 54
	return acl;
}

55
static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
56
			 struct inode *inode, struct posix_acl *acl, int type)
J
Josef Bacik 已提交
57
{
58 59
	int ret, size = 0;
	const char *name;
J
Josef Bacik 已提交
60 61 62 63
	char *value = NULL;

	switch (type) {
	case ACL_TYPE_ACCESS:
64
		name = XATTR_NAME_POSIX_ACL_ACCESS;
J
Josef Bacik 已提交
65 66 67 68
		break;
	case ACL_TYPE_DEFAULT:
		if (!S_ISDIR(inode->i_mode))
			return acl ? -EINVAL : 0;
69
		name = XATTR_NAME_POSIX_ACL_DEFAULT;
J
Josef Bacik 已提交
70 71 72 73 74 75
		break;
	default:
		return -EINVAL;
	}

	if (acl) {
76 77
		unsigned int nofs_flag;

J
Josef Bacik 已提交
78
		size = posix_acl_xattr_size(acl->a_count);
79 80 81 82 83
		/*
		 * We're holding a transaction handle, so use a NOFS memory
		 * allocation context to avoid deadlock if reclaim happens.
		 */
		nofs_flag = memalloc_nofs_save();
84
		value = kmalloc(size, GFP_KERNEL);
85
		memalloc_nofs_restore(nofs_flag);
J
Josef Bacik 已提交
86 87 88 89 90
		if (!value) {
			ret = -ENOMEM;
			goto out;
		}

91
		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
J
Josef Bacik 已提交
92 93 94 95
		if (ret < 0)
			goto out;
	}

96 97 98
	if (trans)
		ret = btrfs_setxattr(trans, inode, name, value, size, 0);
	else
99
		ret = btrfs_setxattr_trans(inode, name, value, size, 0);
100

J
Josef Bacik 已提交
101
out:
C
Chris Mason 已提交
102
	kfree(value);
J
Josef Bacik 已提交
103 104

	if (!ret)
105
		set_cached_acl(inode, type, acl);
J
Josef Bacik 已提交
106 107 108

	return ret;
}
Y
Yan 已提交
109

110
int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
Y
Yan 已提交
111
{
112
	int ret;
113
	umode_t old_mode = inode->i_mode;
114 115 116 117 118 119

	if (type == ACL_TYPE_ACCESS && acl) {
		ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
		if (ret)
			return ret;
	}
120 121 122 123
	ret = __btrfs_set_acl(NULL, inode, acl, type);
	if (ret)
		inode->i_mode = old_mode;
	return ret;
Y
Yan 已提交
124
}
J
Josef Bacik 已提交
125

126 127
int btrfs_init_acl(struct btrfs_trans_handle *trans,
		   struct inode *inode, struct inode *dir)
J
Josef Bacik 已提交
128
{
129
	struct posix_acl *default_acl, *acl;
J
Josef Bacik 已提交
130 131 132 133 134 135
	int ret = 0;

	/* this happens with subvols */
	if (!dir)
		return 0;

136 137 138
	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (ret)
		return ret;
J
Josef Bacik 已提交
139

140 141 142 143
	if (default_acl) {
		ret = __btrfs_set_acl(trans, inode, default_acl,
				      ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
J
Josef Bacik 已提交
144 145
	}

146 147 148 149 150
	if (acl) {
		if (!ret)
			ret = __btrfs_set_acl(trans, inode, acl,
					      ACL_TYPE_ACCESS);
		posix_acl_release(acl);
J
Josef Bacik 已提交
151 152
	}

153 154
	if (!default_acl && !acl)
		cache_no_acl(inode);
J
Josef Bacik 已提交
155
	return ret;
J
Josef Bacik 已提交
156
}