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