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 18 struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu) 19 { 20 int size; 21 const char *name; 22 char *value = NULL; 23 struct posix_acl *acl; 24 25 if (rcu) 26 return ERR_PTR(-ECHILD); 27 28 switch (type) { 29 case ACL_TYPE_ACCESS: 30 name = XATTR_NAME_POSIX_ACL_ACCESS; 31 break; 32 case ACL_TYPE_DEFAULT: 33 name = XATTR_NAME_POSIX_ACL_DEFAULT; 34 break; 35 default: 36 return ERR_PTR(-EINVAL); 37 } 38 39 size = btrfs_getxattr(inode, name, NULL, 0); 40 if (size > 0) { 41 value = kzalloc(size, GFP_KERNEL); 42 if (!value) 43 return ERR_PTR(-ENOMEM); 44 size = btrfs_getxattr(inode, name, value, size); 45 } 46 if (size > 0) 47 acl = posix_acl_from_xattr(&init_user_ns, value, size); 48 else if (size == -ENODATA || size == 0) 49 acl = NULL; 50 else 51 acl = ERR_PTR(size); 52 kfree(value); 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 *value = NULL; 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 ret = -ENOMEM; 90 goto out; 91 } 92 93 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 94 if (ret < 0) 95 goto out; 96 } 97 98 if (trans) 99 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 100 else 101 ret = btrfs_setxattr_trans(inode, name, value, size, 0); 102 103 out: 104 kfree(value); 105 106 if (!ret) 107 set_cached_acl(inode, type, acl); 108 109 return ret; 110 } 111 112 int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 113 struct posix_acl *acl, int type) 114 { 115 int ret; 116 struct inode *inode = d_inode(dentry); 117 umode_t old_mode = inode->i_mode; 118 119 if (type == ACL_TYPE_ACCESS && acl) { 120 ret = posix_acl_update_mode(idmap, inode, 121 &inode->i_mode, &acl); 122 if (ret) 123 return ret; 124 } 125 ret = __btrfs_set_acl(NULL, inode, acl, type); 126 if (ret) 127 inode->i_mode = old_mode; 128 return ret; 129 } 130
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.