acl.c (2683B)
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 19struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu) 20{ 21 int size; 22 const char *name; 23 char *value = NULL; 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 kfree(value); 54 55 return acl; 56} 57 58int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode, 59 struct posix_acl *acl, int type) 60{ 61 int ret, size = 0; 62 const char *name; 63 char *value = NULL; 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 size = posix_acl_xattr_size(acl->a_count); 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 = kmalloc(size, GFP_KERNEL); 88 memalloc_nofs_restore(nofs_flag); 89 if (!value) { 90 ret = -ENOMEM; 91 goto out; 92 } 93 94 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 95 if (ret < 0) 96 goto out; 97 } 98 99 if (trans) 100 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 101 else 102 ret = btrfs_setxattr_trans(inode, name, value, size, 0); 103 104out: 105 kfree(value); 106 107 if (!ret) 108 set_cached_acl(inode, type, acl); 109 110 return ret; 111} 112 113int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, 114 struct posix_acl *acl, int type) 115{ 116 int ret; 117 umode_t old_mode = inode->i_mode; 118 119 if (type == ACL_TYPE_ACCESS && acl) { 120 ret = posix_acl_update_mode(mnt_userns, 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}