18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/f2fs/acl.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd.
68c2ecf20Sopenharmony_ci *             http://www.samsung.com/
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Portions of this code from linux/fs/ext2/acl.c
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#include <linux/f2fs_fs.h>
138c2ecf20Sopenharmony_ci#include "f2fs.h"
148c2ecf20Sopenharmony_ci#include "xattr.h"
158c2ecf20Sopenharmony_ci#include "acl.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic inline size_t f2fs_acl_size(int count)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	if (count <= 4) {
208c2ecf20Sopenharmony_ci		return sizeof(struct f2fs_acl_header) +
218c2ecf20Sopenharmony_ci			count * sizeof(struct f2fs_acl_entry_short);
228c2ecf20Sopenharmony_ci	} else {
238c2ecf20Sopenharmony_ci		return sizeof(struct f2fs_acl_header) +
248c2ecf20Sopenharmony_ci			4 * sizeof(struct f2fs_acl_entry_short) +
258c2ecf20Sopenharmony_ci			(count - 4) * sizeof(struct f2fs_acl_entry);
268c2ecf20Sopenharmony_ci	}
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic inline int f2fs_acl_count(size_t size)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	ssize_t s;
328c2ecf20Sopenharmony_ci	size -= sizeof(struct f2fs_acl_header);
338c2ecf20Sopenharmony_ci	s = size - 4 * sizeof(struct f2fs_acl_entry_short);
348c2ecf20Sopenharmony_ci	if (s < 0) {
358c2ecf20Sopenharmony_ci		if (size % sizeof(struct f2fs_acl_entry_short))
368c2ecf20Sopenharmony_ci			return -1;
378c2ecf20Sopenharmony_ci		return size / sizeof(struct f2fs_acl_entry_short);
388c2ecf20Sopenharmony_ci	} else {
398c2ecf20Sopenharmony_ci		if (s % sizeof(struct f2fs_acl_entry))
408c2ecf20Sopenharmony_ci			return -1;
418c2ecf20Sopenharmony_ci		return s / sizeof(struct f2fs_acl_entry) + 4;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	int i, count;
488c2ecf20Sopenharmony_ci	struct posix_acl *acl;
498c2ecf20Sopenharmony_ci	struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value;
508c2ecf20Sopenharmony_ci	struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1);
518c2ecf20Sopenharmony_ci	const char *end = value + size;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (size < sizeof(struct f2fs_acl_header))
548c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION))
578c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	count = f2fs_acl_count(size);
608c2ecf20Sopenharmony_ci	if (count < 0)
618c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
628c2ecf20Sopenharmony_ci	if (count == 0)
638c2ecf20Sopenharmony_ci		return NULL;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	acl = posix_acl_alloc(count, GFP_NOFS);
668c2ecf20Sopenharmony_ci	if (!acl)
678c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		if ((char *)entry > end)
728c2ecf20Sopenharmony_ci			goto fail;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		acl->a_entries[i].e_tag  = le16_to_cpu(entry->e_tag);
758c2ecf20Sopenharmony_ci		acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		switch (acl->a_entries[i].e_tag) {
788c2ecf20Sopenharmony_ci		case ACL_USER_OBJ:
798c2ecf20Sopenharmony_ci		case ACL_GROUP_OBJ:
808c2ecf20Sopenharmony_ci		case ACL_MASK:
818c2ecf20Sopenharmony_ci		case ACL_OTHER:
828c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
838c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry_short));
848c2ecf20Sopenharmony_ci			break;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		case ACL_USER:
878c2ecf20Sopenharmony_ci			acl->a_entries[i].e_uid =
888c2ecf20Sopenharmony_ci				make_kuid(&init_user_ns,
898c2ecf20Sopenharmony_ci						le32_to_cpu(entry->e_id));
908c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
918c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry));
928c2ecf20Sopenharmony_ci			break;
938c2ecf20Sopenharmony_ci		case ACL_GROUP:
948c2ecf20Sopenharmony_ci			acl->a_entries[i].e_gid =
958c2ecf20Sopenharmony_ci				make_kgid(&init_user_ns,
968c2ecf20Sopenharmony_ci						le32_to_cpu(entry->e_id));
978c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
988c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry));
998c2ecf20Sopenharmony_ci			break;
1008c2ecf20Sopenharmony_ci		default:
1018c2ecf20Sopenharmony_ci			goto fail;
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	if ((char *)entry != end)
1058c2ecf20Sopenharmony_ci		goto fail;
1068c2ecf20Sopenharmony_ci	return acl;
1078c2ecf20Sopenharmony_cifail:
1088c2ecf20Sopenharmony_ci	posix_acl_release(acl);
1098c2ecf20Sopenharmony_ci	return ERR_PTR(-EINVAL);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void *f2fs_acl_to_disk(struct f2fs_sb_info *sbi,
1138c2ecf20Sopenharmony_ci				const struct posix_acl *acl, size_t *size)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct f2fs_acl_header *f2fs_acl;
1168c2ecf20Sopenharmony_ci	struct f2fs_acl_entry *entry;
1178c2ecf20Sopenharmony_ci	int i;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	f2fs_acl = f2fs_kmalloc(sbi, sizeof(struct f2fs_acl_header) +
1208c2ecf20Sopenharmony_ci			acl->a_count * sizeof(struct f2fs_acl_entry),
1218c2ecf20Sopenharmony_ci			GFP_NOFS);
1228c2ecf20Sopenharmony_ci	if (!f2fs_acl)
1238c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION);
1268c2ecf20Sopenharmony_ci	entry = (struct f2fs_acl_entry *)(f2fs_acl + 1);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	for (i = 0; i < acl->a_count; i++) {
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		entry->e_tag  = cpu_to_le16(acl->a_entries[i].e_tag);
1318c2ecf20Sopenharmony_ci		entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		switch (acl->a_entries[i].e_tag) {
1348c2ecf20Sopenharmony_ci		case ACL_USER:
1358c2ecf20Sopenharmony_ci			entry->e_id = cpu_to_le32(
1368c2ecf20Sopenharmony_ci					from_kuid(&init_user_ns,
1378c2ecf20Sopenharmony_ci						acl->a_entries[i].e_uid));
1388c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
1398c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry));
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci		case ACL_GROUP:
1428c2ecf20Sopenharmony_ci			entry->e_id = cpu_to_le32(
1438c2ecf20Sopenharmony_ci					from_kgid(&init_user_ns,
1448c2ecf20Sopenharmony_ci						acl->a_entries[i].e_gid));
1458c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
1468c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry));
1478c2ecf20Sopenharmony_ci			break;
1488c2ecf20Sopenharmony_ci		case ACL_USER_OBJ:
1498c2ecf20Sopenharmony_ci		case ACL_GROUP_OBJ:
1508c2ecf20Sopenharmony_ci		case ACL_MASK:
1518c2ecf20Sopenharmony_ci		case ACL_OTHER:
1528c2ecf20Sopenharmony_ci			entry = (struct f2fs_acl_entry *)((char *)entry +
1538c2ecf20Sopenharmony_ci					sizeof(struct f2fs_acl_entry_short));
1548c2ecf20Sopenharmony_ci			break;
1558c2ecf20Sopenharmony_ci		default:
1568c2ecf20Sopenharmony_ci			goto fail;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	*size = f2fs_acl_size(acl->a_count);
1608c2ecf20Sopenharmony_ci	return (void *)f2fs_acl;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cifail:
1638c2ecf20Sopenharmony_ci	kfree(f2fs_acl);
1648c2ecf20Sopenharmony_ci	return ERR_PTR(-EINVAL);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
1688c2ecf20Sopenharmony_ci						struct page *dpage)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
1718c2ecf20Sopenharmony_ci	void *value = NULL;
1728c2ecf20Sopenharmony_ci	struct posix_acl *acl;
1738c2ecf20Sopenharmony_ci	int retval;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (type == ACL_TYPE_ACCESS)
1768c2ecf20Sopenharmony_ci		name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage);
1798c2ecf20Sopenharmony_ci	if (retval > 0) {
1808c2ecf20Sopenharmony_ci		value = f2fs_kmalloc(F2FS_I_SB(inode), retval, GFP_F2FS_ZERO);
1818c2ecf20Sopenharmony_ci		if (!value)
1828c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
1838c2ecf20Sopenharmony_ci		retval = f2fs_getxattr(inode, name_index, "", value,
1848c2ecf20Sopenharmony_ci							retval, dpage);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (retval > 0)
1888c2ecf20Sopenharmony_ci		acl = f2fs_acl_from_disk(value, retval);
1898c2ecf20Sopenharmony_ci	else if (retval == -ENODATA)
1908c2ecf20Sopenharmony_ci		acl = NULL;
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		acl = ERR_PTR(retval);
1938c2ecf20Sopenharmony_ci	kfree(value);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return acl;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistruct posix_acl *f2fs_get_acl(struct inode *inode, int type)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	return __f2fs_get_acl(inode, type, NULL);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int __f2fs_set_acl(struct inode *inode, int type,
2048c2ecf20Sopenharmony_ci			struct posix_acl *acl, struct page *ipage)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	int name_index;
2078c2ecf20Sopenharmony_ci	void *value = NULL;
2088c2ecf20Sopenharmony_ci	size_t size = 0;
2098c2ecf20Sopenharmony_ci	int error;
2108c2ecf20Sopenharmony_ci	umode_t mode = inode->i_mode;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	switch (type) {
2138c2ecf20Sopenharmony_ci	case ACL_TYPE_ACCESS:
2148c2ecf20Sopenharmony_ci		name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
2158c2ecf20Sopenharmony_ci		if (acl && !ipage) {
2168c2ecf20Sopenharmony_ci			error = posix_acl_update_mode(inode, &mode, &acl);
2178c2ecf20Sopenharmony_ci			if (error)
2188c2ecf20Sopenharmony_ci				return error;
2198c2ecf20Sopenharmony_ci			set_acl_inode(inode, mode);
2208c2ecf20Sopenharmony_ci		}
2218c2ecf20Sopenharmony_ci		break;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	case ACL_TYPE_DEFAULT:
2248c2ecf20Sopenharmony_ci		name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
2258c2ecf20Sopenharmony_ci		if (!S_ISDIR(inode->i_mode))
2268c2ecf20Sopenharmony_ci			return acl ? -EACCES : 0;
2278c2ecf20Sopenharmony_ci		break;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	default:
2308c2ecf20Sopenharmony_ci		return -EINVAL;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (acl) {
2348c2ecf20Sopenharmony_ci		value = f2fs_acl_to_disk(F2FS_I_SB(inode), acl, &size);
2358c2ecf20Sopenharmony_ci		if (IS_ERR(value)) {
2368c2ecf20Sopenharmony_ci			clear_inode_flag(inode, FI_ACL_MODE);
2378c2ecf20Sopenharmony_ci			return PTR_ERR(value);
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	kfree(value);
2448c2ecf20Sopenharmony_ci	if (!error)
2458c2ecf20Sopenharmony_ci		set_cached_acl(inode, type, acl);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	clear_inode_flag(inode, FI_ACL_MODE);
2488c2ecf20Sopenharmony_ci	return error;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciint f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
2548c2ecf20Sopenharmony_ci		return -EIO;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return __f2fs_set_acl(inode, type, acl, NULL);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create
2618c2ecf20Sopenharmony_ci * are copied from posix_acl.c
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_cistatic struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
2648c2ecf20Sopenharmony_ci							gfp_t flags)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct posix_acl *clone = NULL;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (acl) {
2698c2ecf20Sopenharmony_ci		int size = sizeof(struct posix_acl) + acl->a_count *
2708c2ecf20Sopenharmony_ci				sizeof(struct posix_acl_entry);
2718c2ecf20Sopenharmony_ci		clone = kmemdup(acl, size, flags);
2728c2ecf20Sopenharmony_ci		if (clone)
2738c2ecf20Sopenharmony_ci			refcount_set(&clone->a_refcount, 1);
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci	return clone;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct posix_acl_entry *pa, *pe;
2818c2ecf20Sopenharmony_ci	struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
2828c2ecf20Sopenharmony_ci	umode_t mode = *mode_p;
2838c2ecf20Sopenharmony_ci	int not_equiv = 0;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* assert(atomic_read(acl->a_refcount) == 1); */
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	FOREACH_ACL_ENTRY(pa, acl, pe) {
2888c2ecf20Sopenharmony_ci		switch (pa->e_tag) {
2898c2ecf20Sopenharmony_ci		case ACL_USER_OBJ:
2908c2ecf20Sopenharmony_ci			pa->e_perm &= (mode >> 6) | ~S_IRWXO;
2918c2ecf20Sopenharmony_ci			mode &= (pa->e_perm << 6) | ~S_IRWXU;
2928c2ecf20Sopenharmony_ci			break;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		case ACL_USER:
2958c2ecf20Sopenharmony_ci		case ACL_GROUP:
2968c2ecf20Sopenharmony_ci			not_equiv = 1;
2978c2ecf20Sopenharmony_ci			break;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		case ACL_GROUP_OBJ:
3008c2ecf20Sopenharmony_ci			group_obj = pa;
3018c2ecf20Sopenharmony_ci			break;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci		case ACL_OTHER:
3048c2ecf20Sopenharmony_ci			pa->e_perm &= mode | ~S_IRWXO;
3058c2ecf20Sopenharmony_ci			mode &= pa->e_perm | ~S_IRWXO;
3068c2ecf20Sopenharmony_ci			break;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		case ACL_MASK:
3098c2ecf20Sopenharmony_ci			mask_obj = pa;
3108c2ecf20Sopenharmony_ci			not_equiv = 1;
3118c2ecf20Sopenharmony_ci			break;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		default:
3148c2ecf20Sopenharmony_ci			return -EIO;
3158c2ecf20Sopenharmony_ci		}
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (mask_obj) {
3198c2ecf20Sopenharmony_ci		mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
3208c2ecf20Sopenharmony_ci		mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
3218c2ecf20Sopenharmony_ci	} else {
3228c2ecf20Sopenharmony_ci		if (!group_obj)
3238c2ecf20Sopenharmony_ci			return -EIO;
3248c2ecf20Sopenharmony_ci		group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
3258c2ecf20Sopenharmony_ci		mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	*mode_p = (*mode_p & ~S_IRWXUGO) | mode;
3298c2ecf20Sopenharmony_ci	return not_equiv;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int f2fs_acl_create(struct inode *dir, umode_t *mode,
3338c2ecf20Sopenharmony_ci		struct posix_acl **default_acl, struct posix_acl **acl,
3348c2ecf20Sopenharmony_ci		struct page *dpage)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct posix_acl *p;
3378c2ecf20Sopenharmony_ci	struct posix_acl *clone;
3388c2ecf20Sopenharmony_ci	int ret;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	*acl = NULL;
3418c2ecf20Sopenharmony_ci	*default_acl = NULL;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
3448c2ecf20Sopenharmony_ci		return 0;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage);
3478c2ecf20Sopenharmony_ci	if (!p || p == ERR_PTR(-EOPNOTSUPP)) {
3488c2ecf20Sopenharmony_ci		*mode &= ~current_umask();
3498c2ecf20Sopenharmony_ci		return 0;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci	if (IS_ERR(p))
3528c2ecf20Sopenharmony_ci		return PTR_ERR(p);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	clone = f2fs_acl_clone(p, GFP_NOFS);
3558c2ecf20Sopenharmony_ci	if (!clone) {
3568c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3578c2ecf20Sopenharmony_ci		goto release_acl;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	ret = f2fs_acl_create_masq(clone, mode);
3618c2ecf20Sopenharmony_ci	if (ret < 0)
3628c2ecf20Sopenharmony_ci		goto release_clone;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (ret == 0)
3658c2ecf20Sopenharmony_ci		posix_acl_release(clone);
3668c2ecf20Sopenharmony_ci	else
3678c2ecf20Sopenharmony_ci		*acl = clone;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (!S_ISDIR(*mode))
3708c2ecf20Sopenharmony_ci		posix_acl_release(p);
3718c2ecf20Sopenharmony_ci	else
3728c2ecf20Sopenharmony_ci		*default_acl = p;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return 0;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cirelease_clone:
3778c2ecf20Sopenharmony_ci	posix_acl_release(clone);
3788c2ecf20Sopenharmony_cirelease_acl:
3798c2ecf20Sopenharmony_ci	posix_acl_release(p);
3808c2ecf20Sopenharmony_ci	return ret;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciint f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
3848c2ecf20Sopenharmony_ci							struct page *dpage)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct posix_acl *default_acl = NULL, *acl = NULL;
3878c2ecf20Sopenharmony_ci	int error = 0;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	error = f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage);
3908c2ecf20Sopenharmony_ci	if (error)
3918c2ecf20Sopenharmony_ci		return error;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	f2fs_mark_inode_dirty_sync(inode, true);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (default_acl) {
3968c2ecf20Sopenharmony_ci		error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
3978c2ecf20Sopenharmony_ci				       ipage);
3988c2ecf20Sopenharmony_ci		posix_acl_release(default_acl);
3998c2ecf20Sopenharmony_ci	} else {
4008c2ecf20Sopenharmony_ci		inode->i_default_acl = NULL;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	if (acl) {
4038c2ecf20Sopenharmony_ci		if (!error)
4048c2ecf20Sopenharmony_ci			error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl,
4058c2ecf20Sopenharmony_ci					       ipage);
4068c2ecf20Sopenharmony_ci		posix_acl_release(acl);
4078c2ecf20Sopenharmony_ci	} else {
4088c2ecf20Sopenharmony_ci		inode->i_acl = NULL;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return error;
4128c2ecf20Sopenharmony_ci}
413