Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/btrfs/acl.c
49628 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
#include "misc.h"
18
19
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
20
{
21
int size;
22
const char *name;
23
char AUTO_KFREE(value);
24
struct posix_acl *acl;
25
26
if (rcu)
27
return ERR_PTR(-ECHILD);
28
29
switch (type) {
30
case ACL_TYPE_ACCESS:
31
name = XATTR_NAME_POSIX_ACL_ACCESS;
32
break;
33
case ACL_TYPE_DEFAULT:
34
name = XATTR_NAME_POSIX_ACL_DEFAULT;
35
break;
36
default:
37
return ERR_PTR(-EINVAL);
38
}
39
40
size = btrfs_getxattr(inode, name, NULL, 0);
41
if (size > 0) {
42
value = kzalloc(size, GFP_KERNEL);
43
if (!value)
44
return ERR_PTR(-ENOMEM);
45
size = btrfs_getxattr(inode, name, value, size);
46
}
47
if (size > 0)
48
acl = posix_acl_from_xattr(&init_user_ns, value, size);
49
else if (size == -ENODATA || size == 0)
50
acl = NULL;
51
else
52
acl = ERR_PTR(size);
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 AUTO_KFREE(value);
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
return -ENOMEM;
90
91
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
92
if (ret < 0)
93
return ret;
94
}
95
96
if (trans)
97
ret = btrfs_setxattr(trans, inode, name, value, size, 0);
98
else
99
ret = btrfs_setxattr_trans(inode, name, value, size, 0);
100
if (ret < 0)
101
return ret;
102
103
set_cached_acl(inode, type, acl);
104
return 0;
105
}
106
107
int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
108
struct posix_acl *acl, int type)
109
{
110
int ret;
111
struct inode *inode = d_inode(dentry);
112
umode_t old_mode = inode->i_mode;
113
114
if (type == ACL_TYPE_ACCESS && acl) {
115
ret = posix_acl_update_mode(idmap, inode,
116
&inode->i_mode, &acl);
117
if (ret)
118
return ret;
119
}
120
ret = __btrfs_set_acl(NULL, inode, acl, type);
121
if (ret)
122
inode->i_mode = old_mode;
123
return ret;
124
}
125
126