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 15 #include "ctree.h" 16 #include "btrfs_inode.h" 17 #include "xattr.h" 18 19 struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 20 { 21 int size; 22 const char *name; 23 char *value = NULL; 24 struct posix_acl *acl; 25 26 switch (type) { 27 case ACL_TYPE_ACCESS: 28 name = XATTR_NAME_POSIX_ACL_ACCESS; 29 break; 30 case ACL_TYPE_DEFAULT: 31 name = XATTR_NAME_POSIX_ACL_DEFAULT; 32 break; 33 default: 34 return ERR_PTR(-EINVAL); 35 } 36 37 size = btrfs_getxattr(inode, name, NULL, 0); 38 if (size > 0) { 39 value = kzalloc(size, GFP_KERNEL); 40 if (!value) 41 return ERR_PTR(-ENOMEM); 42 size = btrfs_getxattr(inode, name, value, size); 43 } 44 if (size > 0) 45 acl = posix_acl_from_xattr(&init_user_ns, value, size); 46 else if (size == -ENODATA || size == 0) 47 acl = NULL; 48 else 49 acl = ERR_PTR(size); 50 kfree(value); 51 52 return acl; 53 } 54 55 static int __btrfs_set_acl(struct btrfs_trans_handle *trans, 56 struct inode *inode, struct posix_acl *acl, int type) 57 { 58 int ret, size = 0; 59 const char *name; 60 char *value = NULL; 61 62 switch (type) { 63 case ACL_TYPE_ACCESS: 64 name = XATTR_NAME_POSIX_ACL_ACCESS; 65 break; 66 case ACL_TYPE_DEFAULT: 67 if (!S_ISDIR(inode->i_mode)) 68 return acl ? -EINVAL : 0; 69 name = XATTR_NAME_POSIX_ACL_DEFAULT; 70 break; 71 default: 72 return -EINVAL; 73 } 74 75 if (acl) { 76 unsigned int nofs_flag; 77 78 size = posix_acl_xattr_size(acl->a_count); 79 /* 80 * We're holding a transaction handle, so use a NOFS memory 81 * allocation context to avoid deadlock if reclaim happens. 82 */ 83 nofs_flag = memalloc_nofs_save(); 84 value = kmalloc(size, GFP_KERNEL); 85 memalloc_nofs_restore(nofs_flag); 86 if (!value) { 87 ret = -ENOMEM; 88 goto out; 89 } 90 91 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 92 if (ret < 0) 93 goto out; 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 101 out: 102 kfree(value); 103 104 if (!ret) 105 set_cached_acl(inode, type, acl); 106 107 return ret; 108 } 109 110 int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 111 { 112 int ret; 113 umode_t old_mode = inode->i_mode; 114 115 if (type == ACL_TYPE_ACCESS && acl) { 116 ret = posix_acl_update_mode(inode, &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 int btrfs_init_acl(struct btrfs_trans_handle *trans, 127 struct inode *inode, struct inode *dir) 128 { 129 struct posix_acl *default_acl, *acl; 130 int ret = 0; 131 132 /* this happens with subvols */ 133 if (!dir) 134 return 0; 135 136 ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 137 if (ret) 138 return ret; 139 140 if (default_acl) { 141 ret = __btrfs_set_acl(trans, inode, default_acl, 142 ACL_TYPE_DEFAULT); 143 posix_acl_release(default_acl); 144 } 145 146 if (acl) { 147 if (!ret) 148 ret = __btrfs_set_acl(trans, inode, acl, 149 ACL_TYPE_ACCESS); 150 posix_acl_release(acl); 151 } 152 153 if (!default_acl && !acl) 154 cache_no_acl(inode); 155 return ret; 156 } 157