xref: /openbmc/linux/fs/btrfs/acl.c (revision 700b7940)
1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
25103e947SJosef Bacik /*
35103e947SJosef Bacik  * Copyright (C) 2007 Red Hat.  All rights reserved.
45103e947SJosef Bacik  */
55103e947SJosef Bacik 
65103e947SJosef Bacik #include <linux/fs.h>
75103e947SJosef Bacik #include <linux/string.h>
85103e947SJosef Bacik #include <linux/xattr.h>
95103e947SJosef Bacik #include <linux/posix_acl_xattr.h>
1033268eafSJosef Bacik #include <linux/posix_acl.h>
11c1e32da6SChris Mason #include <linux/sched.h>
12a0873490SFilipe Manana #include <linux/sched/mm.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
145103e947SJosef Bacik #include "ctree.h"
1533268eafSJosef Bacik #include "btrfs_inode.h"
165103e947SJosef Bacik #include "xattr.h"
1733cf97a7SJosef Bacik #include "acl.h"
1833268eafSJosef Bacik 
btrfs_get_acl(struct inode * inode,int type,bool rcu)190cad6246SMiklos Szeredi struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
2033268eafSJosef Bacik {
2195819c05SChristoph Hellwig 	int size;
2295819c05SChristoph Hellwig 	const char *name;
2333268eafSJosef Bacik 	char *value = NULL;
24073aaa1bSAl Viro 	struct posix_acl *acl;
25073aaa1bSAl Viro 
260cad6246SMiklos Szeredi 	if (rcu)
270cad6246SMiklos Szeredi 		return ERR_PTR(-ECHILD);
280cad6246SMiklos Szeredi 
2933268eafSJosef Bacik 	switch (type) {
3033268eafSJosef Bacik 	case ACL_TYPE_ACCESS:
3197d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_ACCESS;
3233268eafSJosef Bacik 		break;
3333268eafSJosef Bacik 	case ACL_TYPE_DEFAULT:
3497d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_DEFAULT;
3533268eafSJosef Bacik 		break;
3633268eafSJosef Bacik 	default:
37ab3629edSChengguang Xu 		return ERR_PTR(-EINVAL);
3833268eafSJosef Bacik 	}
3933268eafSJosef Bacik 
407e35eab9SChengguang Xu 	size = btrfs_getxattr(inode, name, NULL, 0);
4133268eafSJosef Bacik 	if (size > 0) {
4239a27ec1SDavid Sterba 		value = kzalloc(size, GFP_KERNEL);
4333268eafSJosef Bacik 		if (!value)
4433268eafSJosef Bacik 			return ERR_PTR(-ENOMEM);
457852781dSDavid Sterba 		size = btrfs_getxattr(inode, name, value, size);
46cfbffc39STsutomu Itoh 	}
474de426cdSChengguang Xu 	if (size > 0)
485f3a4a28SEric W. Biederman 		acl = posix_acl_from_xattr(&init_user_ns, value, size);
494de426cdSChengguang Xu 	else if (size == -ENODATA || size == 0)
5033268eafSJosef Bacik 		acl = NULL;
514de426cdSChengguang Xu 	else
52dc7789efSChengguang Xu 		acl = ERR_PTR(size);
53cfbffc39STsutomu Itoh 	kfree(value);
54cfbffc39STsutomu Itoh 
5533268eafSJosef Bacik 	return acl;
5633268eafSJosef Bacik }
5733268eafSJosef Bacik 
__btrfs_set_acl(struct btrfs_trans_handle * trans,struct inode * inode,struct posix_acl * acl,int type)583538d68dSOmar Sandoval int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
593538d68dSOmar Sandoval 		    struct posix_acl *acl, int type)
6033268eafSJosef Bacik {
6195819c05SChristoph Hellwig 	int ret, size = 0;
6295819c05SChristoph Hellwig 	const char *name;
6333268eafSJosef Bacik 	char *value = NULL;
6433268eafSJosef Bacik 
6533268eafSJosef Bacik 	switch (type) {
6633268eafSJosef Bacik 	case ACL_TYPE_ACCESS:
6797d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_ACCESS;
6833268eafSJosef Bacik 		break;
6933268eafSJosef Bacik 	case ACL_TYPE_DEFAULT:
7033268eafSJosef Bacik 		if (!S_ISDIR(inode->i_mode))
7133268eafSJosef Bacik 			return acl ? -EINVAL : 0;
7297d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_DEFAULT;
7333268eafSJosef Bacik 		break;
7433268eafSJosef Bacik 	default:
7533268eafSJosef Bacik 		return -EINVAL;
7633268eafSJosef Bacik 	}
7733268eafSJosef Bacik 
7833268eafSJosef Bacik 	if (acl) {
79a0873490SFilipe Manana 		unsigned int nofs_flag;
80a0873490SFilipe Manana 
8133268eafSJosef Bacik 		size = posix_acl_xattr_size(acl->a_count);
82a0873490SFilipe Manana 		/*
83a0873490SFilipe Manana 		 * We're holding a transaction handle, so use a NOFS memory
84a0873490SFilipe Manana 		 * allocation context to avoid deadlock if reclaim happens.
85a0873490SFilipe Manana 		 */
86a0873490SFilipe Manana 		nofs_flag = memalloc_nofs_save();
8739a27ec1SDavid Sterba 		value = kmalloc(size, GFP_KERNEL);
88a0873490SFilipe Manana 		memalloc_nofs_restore(nofs_flag);
8933268eafSJosef Bacik 		if (!value) {
9033268eafSJosef Bacik 			ret = -ENOMEM;
9133268eafSJosef Bacik 			goto out;
9233268eafSJosef Bacik 		}
9333268eafSJosef Bacik 
945f3a4a28SEric W. Biederman 		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
9533268eafSJosef Bacik 		if (ret < 0)
9633268eafSJosef Bacik 			goto out;
9733268eafSJosef Bacik 	}
9833268eafSJosef Bacik 
9904e6863bSAnand Jain 	if (trans)
10004e6863bSAnand Jain 		ret = btrfs_setxattr(trans, inode, name, value, size, 0);
10104e6863bSAnand Jain 	else
102e3de9b15SAnand Jain 		ret = btrfs_setxattr_trans(inode, name, value, size, 0);
10304e6863bSAnand Jain 
10433268eafSJosef Bacik out:
10533268eafSJosef Bacik 	kfree(value);
10633268eafSJosef Bacik 
10733268eafSJosef Bacik 	if (!ret)
108073aaa1bSAl Viro 		set_cached_acl(inode, type, acl);
10933268eafSJosef Bacik 
11033268eafSJosef Bacik 	return ret;
11133268eafSJosef Bacik }
112fb4bc1e0SYan 
btrfs_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,struct posix_acl * acl,int type)11313e83a49SChristian Brauner int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
114549c7297SChristian Brauner 		  struct posix_acl *acl, int type)
115744f52f9SYan {
116b7f8a09fSJan Kara 	int ret;
117138060baSChristian Brauner 	struct inode *inode = d_inode(dentry);
118d7d82496SErnesto A. Fernández 	umode_t old_mode = inode->i_mode;
119b7f8a09fSJan Kara 
120b7f8a09fSJan Kara 	if (type == ACL_TYPE_ACCESS && acl) {
121*700b7940SChristian Brauner 		ret = posix_acl_update_mode(idmap, inode,
122e65ce2a5SChristian Brauner 					    &inode->i_mode, &acl);
123b7f8a09fSJan Kara 		if (ret)
124b7f8a09fSJan Kara 			return ret;
125b7f8a09fSJan Kara 	}
12675b993cfSOmar Sandoval 	ret = __btrfs_set_acl(NULL, inode, acl, type);
127d7d82496SErnesto A. Fernández 	if (ret)
128d7d82496SErnesto A. Fernández 		inode->i_mode = old_mode;
129d7d82496SErnesto A. Fernández 	return ret;
130744f52f9SYan }
131