1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2007 Red Hat. All rights reserved.
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>
16 #include "btrfs_inode.h"
19 struct posix_acl
*btrfs_get_acl(struct inode
*inode
, int type
)
24 struct posix_acl
*acl
;
28 name
= XATTR_NAME_POSIX_ACL_ACCESS
;
30 case ACL_TYPE_DEFAULT
:
31 name
= XATTR_NAME_POSIX_ACL_DEFAULT
;
34 return ERR_PTR(-EINVAL
);
37 size
= btrfs_getxattr(inode
, name
, NULL
, 0);
39 value
= kzalloc(size
, GFP_KERNEL
);
41 return ERR_PTR(-ENOMEM
);
42 size
= btrfs_getxattr(inode
, name
, value
, size
);
45 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
46 else if (size
== -ENODATA
|| size
== 0)
55 static int __btrfs_set_acl(struct btrfs_trans_handle
*trans
,
56 struct inode
*inode
, struct posix_acl
*acl
, int type
)
64 name
= XATTR_NAME_POSIX_ACL_ACCESS
;
66 case ACL_TYPE_DEFAULT
:
67 if (!S_ISDIR(inode
->i_mode
))
68 return acl
? -EINVAL
: 0;
69 name
= XATTR_NAME_POSIX_ACL_DEFAULT
;
76 unsigned int nofs_flag
;
78 size
= posix_acl_xattr_size(acl
->a_count
);
80 * We're holding a transaction handle, so use a NOFS memory
81 * allocation context to avoid deadlock if reclaim happens.
83 nofs_flag
= memalloc_nofs_save();
84 value
= kmalloc(size
, GFP_KERNEL
);
85 memalloc_nofs_restore(nofs_flag
);
91 ret
= posix_acl_to_xattr(&init_user_ns
, acl
, value
, size
);
96 ret
= btrfs_setxattr(trans
, inode
, name
, value
, size
, 0);
101 set_cached_acl(inode
, type
, acl
);
106 int btrfs_set_acl(struct inode
*inode
, struct posix_acl
*acl
, int type
)
109 umode_t old_mode
= inode
->i_mode
;
111 if (type
== ACL_TYPE_ACCESS
&& acl
) {
112 ret
= posix_acl_update_mode(inode
, &inode
->i_mode
, &acl
);
116 ret
= __btrfs_set_acl(NULL
, inode
, acl
, type
);
118 inode
->i_mode
= old_mode
;
122 int btrfs_init_acl(struct btrfs_trans_handle
*trans
,
123 struct inode
*inode
, struct inode
*dir
)
125 struct posix_acl
*default_acl
, *acl
;
128 /* this happens with subvols */
132 ret
= posix_acl_create(dir
, &inode
->i_mode
, &default_acl
, &acl
);
137 ret
= __btrfs_set_acl(trans
, inode
, default_acl
,
139 posix_acl_release(default_acl
);
144 ret
= __btrfs_set_acl(trans
, inode
, acl
,
146 posix_acl_release(acl
);
149 if (!default_acl
&& !acl
)