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 #include "btrfs_inode.h" 19 20 struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu) 21 { 22 int size; 23 const char *name; 24 char AUTO_KFREE(value); 25 struct posix_acl *acl; 26 27 if (rcu) 28 return ERR_PTR(-ECHILD); 29 30 switch (type) { 31 case ACL_TYPE_ACCESS: 32 name = XATTR_NAME_POSIX_ACL_ACCESS; 33 break; 34 case ACL_TYPE_DEFAULT: 35 name = XATTR_NAME_POSIX_ACL_DEFAULT; 36 break; 37 default: 38 return ERR_PTR(-EINVAL); 39 } 40 41 size = btrfs_getxattr(inode, name, NULL, 0); 42 if (size > 0) { 43 value = kzalloc(size, GFP_KERNEL); 44 if (!value) 45 return ERR_PTR(-ENOMEM); 46 size = btrfs_getxattr(inode, name, value, size); 47 } 48 if (size > 0) 49 acl = posix_acl_from_xattr(&init_user_ns, value, size); 50 else if (size == -ENODATA || size == 0) 51 acl = NULL; 52 else 53 acl = ERR_PTR(size); 54 55 return acl; 56 } 57 58 int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode, 59 struct posix_acl *acl, int type) 60 { 61 int ret; 62 size_t size = 0; 63 const char *name; 64 char AUTO_KFREE(value); 65 66 switch (type) { 67 case ACL_TYPE_ACCESS: 68 name = XATTR_NAME_POSIX_ACL_ACCESS; 69 break; 70 case ACL_TYPE_DEFAULT: 71 if (!S_ISDIR(inode->i_mode)) 72 return acl ? -EINVAL : 0; 73 name = XATTR_NAME_POSIX_ACL_DEFAULT; 74 break; 75 default: 76 return -EINVAL; 77 } 78 79 if (acl) { 80 unsigned int nofs_flag; 81 82 /* 83 * We're holding a transaction handle, so use a NOFS memory 84 * allocation context to avoid deadlock if reclaim happens. 85 */ 86 nofs_flag = memalloc_nofs_save(); 87 value = posix_acl_to_xattr(&init_user_ns, acl, &size, GFP_KERNEL); 88 memalloc_nofs_restore(nofs_flag); 89 if (!value) 90 return -ENOMEM; 91 } 92 93 if (trans) 94 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 95 else 96 ret = btrfs_setxattr_trans(inode, name, value, size, 0); 97 if (ret < 0) 98 return ret; 99 100 set_cached_acl(inode, type, acl); 101 return 0; 102 } 103 104 int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 105 struct posix_acl *acl, int type) 106 { 107 int ret; 108 struct inode *inode = d_inode(dentry); 109 umode_t old_mode = inode->i_mode; 110 111 if (btrfs_root_readonly(BTRFS_I(inode)->root)) 112 return -EROFS; 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