1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 4 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 5 */ 6 7 #include <linux/sched.h> 8 #include <linux/slab.h> 9 #include <linux/spinlock.h> 10 #include <linux/completion.h> 11 #include <linux/buffer_head.h> 12 #include <linux/xattr.h> 13 #include <linux/posix_acl.h> 14 #include <linux/posix_acl_xattr.h> 15 #include <linux/gfs2_ondisk.h> 16 17 #include "gfs2.h" 18 #include "incore.h" 19 #include "acl.h" 20 #include "xattr.h" 21 #include "glock.h" 22 #include "inode.h" 23 #include "meta_io.h" 24 #include "quota.h" 25 #include "rgrp.h" 26 #include "trans.h" 27 #include "util.h" 28 29 static const char *gfs2_acl_name(int type) 30 { 31 switch (type) { 32 case ACL_TYPE_ACCESS: 33 return XATTR_POSIX_ACL_ACCESS; 34 case ACL_TYPE_DEFAULT: 35 return XATTR_POSIX_ACL_DEFAULT; 36 } 37 return NULL; 38 } 39 40 static struct posix_acl *__gfs2_get_acl(struct inode *inode, int type) 41 { 42 struct gfs2_inode *ip = GFS2_I(inode); 43 struct posix_acl *acl; 44 const char *name; 45 char *data; 46 int len; 47 48 if (!ip->i_eattr) 49 return NULL; 50 51 name = gfs2_acl_name(type); 52 len = gfs2_xattr_acl_get(ip, name, &data); 53 if (len <= 0) 54 return ERR_PTR(len); 55 acl = posix_acl_from_xattr(&init_user_ns, data, len); 56 kfree(data); 57 return acl; 58 } 59 60 struct posix_acl *gfs2_get_acl(struct inode *inode, int type, bool rcu) 61 { 62 struct gfs2_inode *ip = GFS2_I(inode); 63 struct gfs2_holder gh; 64 bool need_unlock = false; 65 struct posix_acl *acl; 66 67 if (rcu) 68 return ERR_PTR(-ECHILD); 69 70 if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { 71 int ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 72 LM_FLAG_ANY, &gh); 73 if (ret) 74 return ERR_PTR(ret); 75 need_unlock = true; 76 } 77 acl = __gfs2_get_acl(inode, type); 78 if (need_unlock) 79 gfs2_glock_dq_uninit(&gh); 80 return acl; 81 } 82 83 int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) 84 { 85 int error; 86 size_t len; 87 char *data; 88 const char *name = gfs2_acl_name(type); 89 90 if (acl) { 91 len = posix_acl_xattr_size(acl->a_count); 92 data = kmalloc(len, GFP_NOFS); 93 if (data == NULL) 94 return -ENOMEM; 95 error = posix_acl_to_xattr(&init_user_ns, acl, data, len); 96 if (error < 0) 97 goto out; 98 } else { 99 data = NULL; 100 len = 0; 101 } 102 103 error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); 104 if (error) 105 goto out; 106 set_cached_acl(inode, type, acl); 107 out: 108 kfree(data); 109 return error; 110 } 111 112 int gfs2_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 113 struct posix_acl *acl, int type) 114 { 115 struct inode *inode = d_inode(dentry); 116 struct gfs2_inode *ip = GFS2_I(inode); 117 struct gfs2_holder gh; 118 bool need_unlock = false; 119 int ret; 120 umode_t mode; 121 122 if (acl && acl->a_count > GFS2_ACL_MAX_ENTRIES(GFS2_SB(inode))) 123 return -E2BIG; 124 125 ret = gfs2_qa_get(ip); 126 if (ret) 127 return ret; 128 129 if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { 130 ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); 131 if (ret) 132 goto out; 133 need_unlock = true; 134 } 135 136 mode = inode->i_mode; 137 if (type == ACL_TYPE_ACCESS && acl) { 138 ret = posix_acl_update_mode(&nop_mnt_idmap, inode, &mode, &acl); 139 if (ret) 140 goto unlock; 141 } 142 143 ret = __gfs2_set_acl(inode, acl, type); 144 if (!ret && mode != inode->i_mode) { 145 inode_set_ctime_current(inode); 146 inode->i_mode = mode; 147 mark_inode_dirty(inode); 148 } 149 unlock: 150 if (need_unlock) 151 gfs2_glock_dq_uninit(&gh); 152 out: 153 gfs2_qa_put(ip); 154 return ret; 155 } 156
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.