162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002-2004 462306a36Sopenharmony_ci * Copyright (C) Andreas Gruenbacher, 2001 562306a36Sopenharmony_ci * Copyright (C) Linus Torvalds, 1991, 1992 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/sched.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 1262306a36Sopenharmony_ci#include "jfs_incore.h" 1362306a36Sopenharmony_ci#include "jfs_txnmgr.h" 1462306a36Sopenharmony_ci#include "jfs_xattr.h" 1562306a36Sopenharmony_ci#include "jfs_acl.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct posix_acl *jfs_get_acl(struct inode *inode, int type, bool rcu) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct posix_acl *acl; 2062306a36Sopenharmony_ci char *ea_name; 2162306a36Sopenharmony_ci int size; 2262306a36Sopenharmony_ci char *value = NULL; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (rcu) 2562306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci switch(type) { 2862306a36Sopenharmony_ci case ACL_TYPE_ACCESS: 2962306a36Sopenharmony_ci ea_name = XATTR_NAME_POSIX_ACL_ACCESS; 3062306a36Sopenharmony_ci break; 3162306a36Sopenharmony_ci case ACL_TYPE_DEFAULT: 3262306a36Sopenharmony_ci ea_name = XATTR_NAME_POSIX_ACL_DEFAULT; 3362306a36Sopenharmony_ci break; 3462306a36Sopenharmony_ci default: 3562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci size = __jfs_getxattr(inode, ea_name, NULL, 0); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (size > 0) { 4162306a36Sopenharmony_ci value = kmalloc(size, GFP_KERNEL); 4262306a36Sopenharmony_ci if (!value) 4362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 4462306a36Sopenharmony_ci size = __jfs_getxattr(inode, ea_name, value, size); 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (size < 0) { 4862306a36Sopenharmony_ci if (size == -ENODATA) 4962306a36Sopenharmony_ci acl = NULL; 5062306a36Sopenharmony_ci else 5162306a36Sopenharmony_ci acl = ERR_PTR(size); 5262306a36Sopenharmony_ci } else { 5362306a36Sopenharmony_ci acl = posix_acl_from_xattr(&init_user_ns, value, size); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci kfree(value); 5662306a36Sopenharmony_ci return acl; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int __jfs_set_acl(tid_t tid, struct inode *inode, int type, 6062306a36Sopenharmony_ci struct posix_acl *acl) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci char *ea_name; 6362306a36Sopenharmony_ci int rc; 6462306a36Sopenharmony_ci int size = 0; 6562306a36Sopenharmony_ci char *value = NULL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci switch (type) { 6862306a36Sopenharmony_ci case ACL_TYPE_ACCESS: 6962306a36Sopenharmony_ci ea_name = XATTR_NAME_POSIX_ACL_ACCESS; 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci case ACL_TYPE_DEFAULT: 7262306a36Sopenharmony_ci ea_name = XATTR_NAME_POSIX_ACL_DEFAULT; 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci default: 7562306a36Sopenharmony_ci return -EINVAL; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (acl) { 7962306a36Sopenharmony_ci size = posix_acl_xattr_size(acl->a_count); 8062306a36Sopenharmony_ci value = kmalloc(size, GFP_KERNEL); 8162306a36Sopenharmony_ci if (!value) 8262306a36Sopenharmony_ci return -ENOMEM; 8362306a36Sopenharmony_ci rc = posix_acl_to_xattr(&init_user_ns, acl, value, size); 8462306a36Sopenharmony_ci if (rc < 0) 8562306a36Sopenharmony_ci goto out; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0); 8862306a36Sopenharmony_ciout: 8962306a36Sopenharmony_ci kfree(value); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (!rc) 9262306a36Sopenharmony_ci set_cached_acl(inode, type, acl); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return rc; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint jfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 9862306a36Sopenharmony_ci struct posix_acl *acl, int type) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int rc; 10162306a36Sopenharmony_ci tid_t tid; 10262306a36Sopenharmony_ci int update_mode = 0; 10362306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 10462306a36Sopenharmony_ci umode_t mode = inode->i_mode; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci tid = txBegin(inode->i_sb, 0); 10762306a36Sopenharmony_ci mutex_lock(&JFS_IP(inode)->commit_mutex); 10862306a36Sopenharmony_ci if (type == ACL_TYPE_ACCESS && acl) { 10962306a36Sopenharmony_ci rc = posix_acl_update_mode(&nop_mnt_idmap, inode, &mode, &acl); 11062306a36Sopenharmony_ci if (rc) 11162306a36Sopenharmony_ci goto end_tx; 11262306a36Sopenharmony_ci if (mode != inode->i_mode) 11362306a36Sopenharmony_ci update_mode = 1; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci rc = __jfs_set_acl(tid, inode, type, acl); 11662306a36Sopenharmony_ci if (!rc) { 11762306a36Sopenharmony_ci if (update_mode) { 11862306a36Sopenharmony_ci inode->i_mode = mode; 11962306a36Sopenharmony_ci inode_set_ctime_current(inode); 12062306a36Sopenharmony_ci mark_inode_dirty(inode); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci rc = txCommit(tid, 1, &inode, 0); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ciend_tx: 12562306a36Sopenharmony_ci txEnd(tid); 12662306a36Sopenharmony_ci mutex_unlock(&JFS_IP(inode)->commit_mutex); 12762306a36Sopenharmony_ci return rc; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciint jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct posix_acl *default_acl, *acl; 13362306a36Sopenharmony_ci int rc = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 13662306a36Sopenharmony_ci if (rc) 13762306a36Sopenharmony_ci return rc; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (default_acl) { 14062306a36Sopenharmony_ci rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); 14162306a36Sopenharmony_ci posix_acl_release(default_acl); 14262306a36Sopenharmony_ci } else { 14362306a36Sopenharmony_ci inode->i_default_acl = NULL; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (acl) { 14762306a36Sopenharmony_ci if (!rc) 14862306a36Sopenharmony_ci rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl); 14962306a36Sopenharmony_ci posix_acl_release(acl); 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci inode->i_acl = NULL; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | 15562306a36Sopenharmony_ci inode->i_mode; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return rc; 15862306a36Sopenharmony_ci} 159