18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * acl.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * CREDITS:
108c2ecf20Sopenharmony_ci * Lots of code in this file is copy from linux/fs/ext3/acl.c.
118c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/string.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <cluster/masklog.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "ocfs2.h"
228c2ecf20Sopenharmony_ci#include "alloc.h"
238c2ecf20Sopenharmony_ci#include "dlmglue.h"
248c2ecf20Sopenharmony_ci#include "file.h"
258c2ecf20Sopenharmony_ci#include "inode.h"
268c2ecf20Sopenharmony_ci#include "journal.h"
278c2ecf20Sopenharmony_ci#include "ocfs2_fs.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "xattr.h"
308c2ecf20Sopenharmony_ci#include "acl.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Convert from xattr value to acl struct.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int n, count;
388c2ecf20Sopenharmony_ci	struct posix_acl *acl;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (!value)
418c2ecf20Sopenharmony_ci		return NULL;
428c2ecf20Sopenharmony_ci	if (size < sizeof(struct posix_acl_entry))
438c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	count = size / sizeof(struct posix_acl_entry);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	acl = posix_acl_alloc(count, GFP_NOFS);
488c2ecf20Sopenharmony_ci	if (!acl)
498c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
508c2ecf20Sopenharmony_ci	for (n = 0; n < count; n++) {
518c2ecf20Sopenharmony_ci		struct ocfs2_acl_entry *entry =
528c2ecf20Sopenharmony_ci			(struct ocfs2_acl_entry *)value;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
558c2ecf20Sopenharmony_ci		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
568c2ecf20Sopenharmony_ci		switch(acl->a_entries[n].e_tag) {
578c2ecf20Sopenharmony_ci		case ACL_USER:
588c2ecf20Sopenharmony_ci			acl->a_entries[n].e_uid =
598c2ecf20Sopenharmony_ci				make_kuid(&init_user_ns,
608c2ecf20Sopenharmony_ci					  le32_to_cpu(entry->e_id));
618c2ecf20Sopenharmony_ci			break;
628c2ecf20Sopenharmony_ci		case ACL_GROUP:
638c2ecf20Sopenharmony_ci			acl->a_entries[n].e_gid =
648c2ecf20Sopenharmony_ci				make_kgid(&init_user_ns,
658c2ecf20Sopenharmony_ci					  le32_to_cpu(entry->e_id));
668c2ecf20Sopenharmony_ci			break;
678c2ecf20Sopenharmony_ci		default:
688c2ecf20Sopenharmony_ci			break;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci		value += sizeof(struct posix_acl_entry);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci	return acl;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/*
778c2ecf20Sopenharmony_ci * Convert acl struct to xattr value.
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_cistatic void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct ocfs2_acl_entry *entry = NULL;
828c2ecf20Sopenharmony_ci	char *ocfs2_acl;
838c2ecf20Sopenharmony_ci	size_t n;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	*size = acl->a_count * sizeof(struct posix_acl_entry);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	ocfs2_acl = kmalloc(*size, GFP_NOFS);
888c2ecf20Sopenharmony_ci	if (!ocfs2_acl)
898c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	entry = (struct ocfs2_acl_entry *)ocfs2_acl;
928c2ecf20Sopenharmony_ci	for (n = 0; n < acl->a_count; n++, entry++) {
938c2ecf20Sopenharmony_ci		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
948c2ecf20Sopenharmony_ci		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
958c2ecf20Sopenharmony_ci		switch(acl->a_entries[n].e_tag) {
968c2ecf20Sopenharmony_ci		case ACL_USER:
978c2ecf20Sopenharmony_ci			entry->e_id = cpu_to_le32(
988c2ecf20Sopenharmony_ci				from_kuid(&init_user_ns,
998c2ecf20Sopenharmony_ci					  acl->a_entries[n].e_uid));
1008c2ecf20Sopenharmony_ci			break;
1018c2ecf20Sopenharmony_ci		case ACL_GROUP:
1028c2ecf20Sopenharmony_ci			entry->e_id = cpu_to_le32(
1038c2ecf20Sopenharmony_ci				from_kgid(&init_user_ns,
1048c2ecf20Sopenharmony_ci					  acl->a_entries[n].e_gid));
1058c2ecf20Sopenharmony_ci			break;
1068c2ecf20Sopenharmony_ci		default:
1078c2ecf20Sopenharmony_ci			entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	return ocfs2_acl;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
1158c2ecf20Sopenharmony_ci					      int type,
1168c2ecf20Sopenharmony_ci					      struct buffer_head *di_bh)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	int name_index;
1198c2ecf20Sopenharmony_ci	char *value = NULL;
1208c2ecf20Sopenharmony_ci	struct posix_acl *acl;
1218c2ecf20Sopenharmony_ci	int retval;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	switch (type) {
1248c2ecf20Sopenharmony_ci	case ACL_TYPE_ACCESS:
1258c2ecf20Sopenharmony_ci		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case ACL_TYPE_DEFAULT:
1288c2ecf20Sopenharmony_ci		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
1298c2ecf20Sopenharmony_ci		break;
1308c2ecf20Sopenharmony_ci	default:
1318c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
1358c2ecf20Sopenharmony_ci	if (retval > 0) {
1368c2ecf20Sopenharmony_ci		value = kmalloc(retval, GFP_NOFS);
1378c2ecf20Sopenharmony_ci		if (!value)
1388c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
1398c2ecf20Sopenharmony_ci		retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
1408c2ecf20Sopenharmony_ci						"", value, retval);
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (retval > 0)
1448c2ecf20Sopenharmony_ci		acl = ocfs2_acl_from_xattr(value, retval);
1458c2ecf20Sopenharmony_ci	else if (retval == -ENODATA || retval == 0)
1468c2ecf20Sopenharmony_ci		acl = NULL;
1478c2ecf20Sopenharmony_ci	else
1488c2ecf20Sopenharmony_ci		acl = ERR_PTR(retval);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	kfree(value);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return acl;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*
1568c2ecf20Sopenharmony_ci * Helper function to set i_mode in memory and disk. Some call paths
1578c2ecf20Sopenharmony_ci * will not have di_bh or a journal handle to pass, in which case it
1588c2ecf20Sopenharmony_ci * will create it's own.
1598c2ecf20Sopenharmony_ci */
1608c2ecf20Sopenharmony_cistatic int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
1618c2ecf20Sopenharmony_ci			      handle_t *handle, umode_t new_mode)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	int ret, commit_handle = 0;
1648c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (di_bh == NULL) {
1678c2ecf20Sopenharmony_ci		ret = ocfs2_read_inode_block(inode, &di_bh);
1688c2ecf20Sopenharmony_ci		if (ret) {
1698c2ecf20Sopenharmony_ci			mlog_errno(ret);
1708c2ecf20Sopenharmony_ci			goto out;
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci	} else
1738c2ecf20Sopenharmony_ci		get_bh(di_bh);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (handle == NULL) {
1768c2ecf20Sopenharmony_ci		handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
1778c2ecf20Sopenharmony_ci					   OCFS2_INODE_UPDATE_CREDITS);
1788c2ecf20Sopenharmony_ci		if (IS_ERR(handle)) {
1798c2ecf20Sopenharmony_ci			ret = PTR_ERR(handle);
1808c2ecf20Sopenharmony_ci			mlog_errno(ret);
1818c2ecf20Sopenharmony_ci			goto out_brelse;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		commit_handle = 1;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	di = (struct ocfs2_dinode *)di_bh->b_data;
1888c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
1898c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
1908c2ecf20Sopenharmony_ci	if (ret) {
1918c2ecf20Sopenharmony_ci		mlog_errno(ret);
1928c2ecf20Sopenharmony_ci		goto out_commit;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	inode->i_mode = new_mode;
1968c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
1978c2ecf20Sopenharmony_ci	di->i_mode = cpu_to_le16(inode->i_mode);
1988c2ecf20Sopenharmony_ci	di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
1998c2ecf20Sopenharmony_ci	di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
2008c2ecf20Sopenharmony_ci	ocfs2_update_inode_fsync_trans(handle, inode, 0);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, di_bh);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ciout_commit:
2058c2ecf20Sopenharmony_ci	if (commit_handle)
2068c2ecf20Sopenharmony_ci		ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
2078c2ecf20Sopenharmony_ciout_brelse:
2088c2ecf20Sopenharmony_ci	brelse(di_bh);
2098c2ecf20Sopenharmony_ciout:
2108c2ecf20Sopenharmony_ci	return ret;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * Set the access or default ACL of an inode.
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_cistatic int ocfs2_set_acl(handle_t *handle,
2178c2ecf20Sopenharmony_ci			 struct inode *inode,
2188c2ecf20Sopenharmony_ci			 struct buffer_head *di_bh,
2198c2ecf20Sopenharmony_ci			 int type,
2208c2ecf20Sopenharmony_ci			 struct posix_acl *acl,
2218c2ecf20Sopenharmony_ci			 struct ocfs2_alloc_context *meta_ac,
2228c2ecf20Sopenharmony_ci			 struct ocfs2_alloc_context *data_ac)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	int name_index;
2258c2ecf20Sopenharmony_ci	void *value = NULL;
2268c2ecf20Sopenharmony_ci	size_t size = 0;
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (S_ISLNK(inode->i_mode))
2308c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	switch (type) {
2338c2ecf20Sopenharmony_ci	case ACL_TYPE_ACCESS:
2348c2ecf20Sopenharmony_ci		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	case ACL_TYPE_DEFAULT:
2378c2ecf20Sopenharmony_ci		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
2388c2ecf20Sopenharmony_ci		if (!S_ISDIR(inode->i_mode))
2398c2ecf20Sopenharmony_ci			return acl ? -EACCES : 0;
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci	default:
2428c2ecf20Sopenharmony_ci		return -EINVAL;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (acl) {
2468c2ecf20Sopenharmony_ci		value = ocfs2_acl_to_xattr(acl, &size);
2478c2ecf20Sopenharmony_ci		if (IS_ERR(value))
2488c2ecf20Sopenharmony_ci			return (int)PTR_ERR(value);
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (handle)
2528c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
2538c2ecf20Sopenharmony_ci					     "", value, size, 0,
2548c2ecf20Sopenharmony_ci					     meta_ac, data_ac);
2558c2ecf20Sopenharmony_ci	else
2568c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	kfree(value);
2598c2ecf20Sopenharmony_ci	if (!ret)
2608c2ecf20Sopenharmony_ci		set_cached_acl(inode, type, acl);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return ret;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciint ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct buffer_head *bh = NULL;
2688c2ecf20Sopenharmony_ci	int status, had_lock;
2698c2ecf20Sopenharmony_ci	struct ocfs2_lock_holder oh;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
2728c2ecf20Sopenharmony_ci	if (had_lock < 0)
2738c2ecf20Sopenharmony_ci		return had_lock;
2748c2ecf20Sopenharmony_ci	if (type == ACL_TYPE_ACCESS && acl) {
2758c2ecf20Sopenharmony_ci		umode_t mode;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		status = posix_acl_update_mode(inode, &mode, &acl);
2788c2ecf20Sopenharmony_ci		if (status)
2798c2ecf20Sopenharmony_ci			goto unlock;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
2828c2ecf20Sopenharmony_ci		if (status)
2838c2ecf20Sopenharmony_ci			goto unlock;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci	status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
2868c2ecf20Sopenharmony_ciunlock:
2878c2ecf20Sopenharmony_ci	ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
2888c2ecf20Sopenharmony_ci	brelse(bh);
2898c2ecf20Sopenharmony_ci	return status;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistruct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct ocfs2_super *osb;
2958c2ecf20Sopenharmony_ci	struct buffer_head *di_bh = NULL;
2968c2ecf20Sopenharmony_ci	struct posix_acl *acl;
2978c2ecf20Sopenharmony_ci	int had_lock;
2988c2ecf20Sopenharmony_ci	struct ocfs2_lock_holder oh;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	osb = OCFS2_SB(inode->i_sb);
3018c2ecf20Sopenharmony_ci	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
3028c2ecf20Sopenharmony_ci		return NULL;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
3058c2ecf20Sopenharmony_ci	if (had_lock < 0)
3068c2ecf20Sopenharmony_ci		return ERR_PTR(had_lock);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	down_read(&OCFS2_I(inode)->ip_xattr_sem);
3098c2ecf20Sopenharmony_ci	acl = ocfs2_get_acl_nolock(inode, type, di_bh);
3108c2ecf20Sopenharmony_ci	up_read(&OCFS2_I(inode)->ip_xattr_sem);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
3138c2ecf20Sopenharmony_ci	brelse(di_bh);
3148c2ecf20Sopenharmony_ci	return acl;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ciint ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3208c2ecf20Sopenharmony_ci	struct posix_acl *acl;
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (S_ISLNK(inode->i_mode))
3248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
3278c2ecf20Sopenharmony_ci		return 0;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	down_read(&OCFS2_I(inode)->ip_xattr_sem);
3308c2ecf20Sopenharmony_ci	acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
3318c2ecf20Sopenharmony_ci	up_read(&OCFS2_I(inode)->ip_xattr_sem);
3328c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(acl))
3338c2ecf20Sopenharmony_ci		return PTR_ERR_OR_ZERO(acl);
3348c2ecf20Sopenharmony_ci	ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
3358c2ecf20Sopenharmony_ci	if (ret)
3368c2ecf20Sopenharmony_ci		return ret;
3378c2ecf20Sopenharmony_ci	ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
3388c2ecf20Sopenharmony_ci			    acl, NULL, NULL);
3398c2ecf20Sopenharmony_ci	posix_acl_release(acl);
3408c2ecf20Sopenharmony_ci	return ret;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/*
3448c2ecf20Sopenharmony_ci * Initialize the ACLs of a new inode. If parent directory has default ACL,
3458c2ecf20Sopenharmony_ci * then clone to new inode. Called from ocfs2_mknod.
3468c2ecf20Sopenharmony_ci */
3478c2ecf20Sopenharmony_ciint ocfs2_init_acl(handle_t *handle,
3488c2ecf20Sopenharmony_ci		   struct inode *inode,
3498c2ecf20Sopenharmony_ci		   struct inode *dir,
3508c2ecf20Sopenharmony_ci		   struct buffer_head *di_bh,
3518c2ecf20Sopenharmony_ci		   struct buffer_head *dir_bh,
3528c2ecf20Sopenharmony_ci		   struct ocfs2_alloc_context *meta_ac,
3538c2ecf20Sopenharmony_ci		   struct ocfs2_alloc_context *data_ac)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3568c2ecf20Sopenharmony_ci	struct posix_acl *acl = NULL;
3578c2ecf20Sopenharmony_ci	int ret = 0, ret2;
3588c2ecf20Sopenharmony_ci	umode_t mode;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!S_ISLNK(inode->i_mode)) {
3618c2ecf20Sopenharmony_ci		if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
3628c2ecf20Sopenharmony_ci			down_read(&OCFS2_I(dir)->ip_xattr_sem);
3638c2ecf20Sopenharmony_ci			acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
3648c2ecf20Sopenharmony_ci						   dir_bh);
3658c2ecf20Sopenharmony_ci			up_read(&OCFS2_I(dir)->ip_xattr_sem);
3668c2ecf20Sopenharmony_ci			if (IS_ERR(acl))
3678c2ecf20Sopenharmony_ci				return PTR_ERR(acl);
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci		if (!acl) {
3708c2ecf20Sopenharmony_ci			mode = inode->i_mode & ~current_umask();
3718c2ecf20Sopenharmony_ci			ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
3728c2ecf20Sopenharmony_ci			if (ret) {
3738c2ecf20Sopenharmony_ci				mlog_errno(ret);
3748c2ecf20Sopenharmony_ci				goto cleanup;
3758c2ecf20Sopenharmony_ci			}
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci	if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
3798c2ecf20Sopenharmony_ci		if (S_ISDIR(inode->i_mode)) {
3808c2ecf20Sopenharmony_ci			ret = ocfs2_set_acl(handle, inode, di_bh,
3818c2ecf20Sopenharmony_ci					    ACL_TYPE_DEFAULT, acl,
3828c2ecf20Sopenharmony_ci					    meta_ac, data_ac);
3838c2ecf20Sopenharmony_ci			if (ret)
3848c2ecf20Sopenharmony_ci				goto cleanup;
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci		mode = inode->i_mode;
3878c2ecf20Sopenharmony_ci		ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
3888c2ecf20Sopenharmony_ci		if (ret < 0)
3898c2ecf20Sopenharmony_ci			return ret;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
3928c2ecf20Sopenharmony_ci		if (ret2) {
3938c2ecf20Sopenharmony_ci			mlog_errno(ret2);
3948c2ecf20Sopenharmony_ci			ret = ret2;
3958c2ecf20Sopenharmony_ci			goto cleanup;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci		if (ret > 0) {
3988c2ecf20Sopenharmony_ci			ret = ocfs2_set_acl(handle, inode,
3998c2ecf20Sopenharmony_ci					    di_bh, ACL_TYPE_ACCESS,
4008c2ecf20Sopenharmony_ci					    acl, meta_ac, data_ac);
4018c2ecf20Sopenharmony_ci		}
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_cicleanup:
4048c2ecf20Sopenharmony_ci	posix_acl_release(acl);
4058c2ecf20Sopenharmony_ci	return ret;
4068c2ecf20Sopenharmony_ci}
407