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 29static 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 40static 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 60struct posix_acl *gfs2_get_acl(struct inode *inode, int type) 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 (!gfs2_glock_is_locked_by_me(ip->i_gl)) { 68 int ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 69 LM_FLAG_ANY, &gh); 70 if (ret) 71 return ERR_PTR(ret); 72 need_unlock = true; 73 } 74 acl = __gfs2_get_acl(inode, type); 75 if (need_unlock) 76 gfs2_glock_dq_uninit(&gh); 77 return acl; 78} 79 80int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) 81{ 82 int error; 83 size_t len; 84 char *data; 85 const char *name = gfs2_acl_name(type); 86 87 if (acl) { 88 len = posix_acl_xattr_size(acl->a_count); 89 data = kmalloc(len, GFP_NOFS); 90 if (data == NULL) 91 return -ENOMEM; 92 error = posix_acl_to_xattr(&init_user_ns, acl, data, len); 93 if (error < 0) 94 goto out; 95 } else { 96 data = NULL; 97 len = 0; 98 } 99 100 error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS); 101 if (error) 102 goto out; 103 set_cached_acl(inode, type, acl); 104out: 105 kfree(data); 106 return error; 107} 108 109int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) 110{ 111 struct gfs2_inode *ip = GFS2_I(inode); 112 struct gfs2_holder gh; 113 bool need_unlock = false; 114 int ret; 115 umode_t mode; 116 117 if (acl && acl->a_count > GFS2_ACL_MAX_ENTRIES(GFS2_SB(inode))) 118 return -E2BIG; 119 120 ret = gfs2_qa_get(ip); 121 if (ret) 122 return ret; 123 124 if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { 125 ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); 126 if (ret) 127 goto out; 128 need_unlock = true; 129 } 130 131 mode = inode->i_mode; 132 if (type == ACL_TYPE_ACCESS && acl) { 133 ret = posix_acl_update_mode(inode, &mode, &acl); 134 if (ret) 135 goto unlock; 136 } 137 138 ret = __gfs2_set_acl(inode, acl, type); 139 if (!ret && mode != inode->i_mode) { 140 inode->i_ctime = current_time(inode); 141 inode->i_mode = mode; 142 mark_inode_dirty(inode); 143 } 144unlock: 145 if (need_unlock) 146 gfs2_glock_dq_uninit(&gh); 147out: 148 gfs2_qa_put(ip); 149 return ret; 150} 151