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