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; 61 size_t size = 0; 62 const char *name; 63 char AUTO_KFREE(value); 64 65 switch (type) { 66 case ACL_TYPE_ACCESS: 67 name = XATTR_NAME_POSIX_ACL_ACCESS; 68 break; 69 case ACL_TYPE_DEFAULT: 70 if (!S_ISDIR(inode->i_mode)) 71 return acl ? -EINVAL : 0; 72 name = XATTR_NAME_POSIX_ACL_DEFAULT; 73 break; 74 default: 75 return -EINVAL; 76 } 77 78 if (acl) { 79 unsigned int nofs_flag; 80 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 = posix_acl_to_xattr(&init_user_ns, acl, &size, GFP_KERNEL); 87 memalloc_nofs_restore(nofs_flag); 88 if (!value) 89 return -ENOMEM; 90 } 91 92 if (trans) 93 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 94 else 95 ret = btrfs_setxattr_trans(inode, name, value, size, 0); 96 if (ret < 0) 97 return ret; 98 99 set_cached_acl(inode, type, acl); 100 return 0; 101 } 102 103 int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 104 struct posix_acl *acl, int type) 105 { 106 int ret; 107 struct inode *inode = d_inode(dentry); 108 umode_t old_mode = inode->i_mode; 109 110 if (type == ACL_TYPE_ACCESS && acl) { 111 ret = posix_acl_update_mode(idmap, inode, 112 &inode->i_mode, &acl); 113 if (ret) 114 return ret; 115 } 116 ret = __btrfs_set_acl(NULL, inode, acl, type); 117 if (ret) 118 inode->i_mode = old_mode; 119 return ret; 120 } 121