Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/btrfs/acl.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2007 Red Hat. All rights reserved.
4
*/
5
6
#include <linux/fs.h>
7
#include <linux/string.h>
8
#include <linux/xattr.h>
9
#include <linux/posix_acl_xattr.h>
10
#include <linux/posix_acl.h>
11
#include <linux/sched.h>
12
#include <linux/sched/mm.h>
13
#include <linux/slab.h>
14
#include "ctree.h"
15
#include "xattr.h"
16
#include "acl.h"
17
18
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
19
{
20
int size;
21
const char *name;
22
char *value = NULL;
23
struct posix_acl *acl;
24
25
if (rcu)
26
return ERR_PTR(-ECHILD);
27
28
switch (type) {
29
case ACL_TYPE_ACCESS:
30
name = XATTR_NAME_POSIX_ACL_ACCESS;
31
break;
32
case ACL_TYPE_DEFAULT:
33
name = XATTR_NAME_POSIX_ACL_DEFAULT;
34
break;
35
default:
36
return ERR_PTR(-EINVAL);
37
}
38
39
size = btrfs_getxattr(inode, name, NULL, 0);
40
if (size > 0) {
41
value = kzalloc(size, GFP_KERNEL);
42
if (!value)
43
return ERR_PTR(-ENOMEM);
44
size = btrfs_getxattr(inode, name, value, size);
45
}
46
if (size > 0)
47
acl = posix_acl_from_xattr(&init_user_ns, value, size);
48
else if (size == -ENODATA || size == 0)
49
acl = NULL;
50
else
51
acl = ERR_PTR(size);
52
kfree(value);
53
54
return acl;
55
}
56
57
int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
58
struct posix_acl *acl, int type)
59
{
60
int ret, size = 0;
61
const char *name;
62
char *value = NULL;
63
64
switch (type) {
65
case ACL_TYPE_ACCESS:
66
name = XATTR_NAME_POSIX_ACL_ACCESS;
67
break;
68
case ACL_TYPE_DEFAULT:
69
if (!S_ISDIR(inode->i_mode))
70
return acl ? -EINVAL : 0;
71
name = XATTR_NAME_POSIX_ACL_DEFAULT;
72
break;
73
default:
74
return -EINVAL;
75
}
76
77
if (acl) {
78
unsigned int nofs_flag;
79
80
size = posix_acl_xattr_size(acl->a_count);
81
/*
82
* We're holding a transaction handle, so use a NOFS memory
83
* allocation context to avoid deadlock if reclaim happens.
84
*/
85
nofs_flag = memalloc_nofs_save();
86
value = kmalloc(size, GFP_KERNEL);
87
memalloc_nofs_restore(nofs_flag);
88
if (!value) {
89
ret = -ENOMEM;
90
goto out;
91
}
92
93
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
94
if (ret < 0)
95
goto out;
96
}
97
98
if (trans)
99
ret = btrfs_setxattr(trans, inode, name, value, size, 0);
100
else
101
ret = btrfs_setxattr_trans(inode, name, value, size, 0);
102
103
out:
104
kfree(value);
105
106
if (!ret)
107
set_cached_acl(inode, type, acl);
108
109
return ret;
110
}
111
112
int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
113
struct posix_acl *acl, int type)
114
{
115
int ret;
116
struct inode *inode = d_inode(dentry);
117
umode_t old_mode = inode->i_mode;
118
119
if (type == ACL_TYPE_ACCESS && acl) {
120
ret = posix_acl_update_mode(idmap, inode,
121
&inode->i_mode, &acl);
122
if (ret)
123
return ret;
124
}
125
ret = __btrfs_set_acl(NULL, inode, acl, type);
126
if (ret)
127
inode->i_mode = old_mode;
128
return ret;
129
}
130
131