17c1a000dSChao Yu // SPDX-License-Identifier: GPL-2.0 20a8165d7SJaegeuk Kim /* 3af48b85bSJaegeuk Kim * fs/f2fs/acl.c 4af48b85bSJaegeuk Kim * 5af48b85bSJaegeuk Kim * Copyright (c) 2012 Samsung Electronics Co., Ltd. 6af48b85bSJaegeuk Kim * http://www.samsung.com/ 7af48b85bSJaegeuk Kim * 8af48b85bSJaegeuk Kim * Portions of this code from linux/fs/ext2/acl.c 9af48b85bSJaegeuk Kim * 10af48b85bSJaegeuk Kim * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 11af48b85bSJaegeuk Kim */ 12af48b85bSJaegeuk Kim #include <linux/f2fs_fs.h> 13af48b85bSJaegeuk Kim #include "f2fs.h" 14af48b85bSJaegeuk Kim #include "xattr.h" 15af48b85bSJaegeuk Kim #include "acl.h" 16af48b85bSJaegeuk Kim 17af48b85bSJaegeuk Kim static inline size_t f2fs_acl_size(int count) 18af48b85bSJaegeuk Kim { 19af48b85bSJaegeuk Kim if (count <= 4) { 20af48b85bSJaegeuk Kim return sizeof(struct f2fs_acl_header) + 21af48b85bSJaegeuk Kim count * sizeof(struct f2fs_acl_entry_short); 22af48b85bSJaegeuk Kim } else { 23af48b85bSJaegeuk Kim return sizeof(struct f2fs_acl_header) + 24af48b85bSJaegeuk Kim 4 * sizeof(struct f2fs_acl_entry_short) + 25af48b85bSJaegeuk Kim (count - 4) * sizeof(struct f2fs_acl_entry); 26af48b85bSJaegeuk Kim } 27af48b85bSJaegeuk Kim } 28af48b85bSJaegeuk Kim 29af48b85bSJaegeuk Kim static inline int f2fs_acl_count(size_t size) 30af48b85bSJaegeuk Kim { 31af48b85bSJaegeuk Kim ssize_t s; 325f029c04SYi Zhuang 33af48b85bSJaegeuk Kim size -= sizeof(struct f2fs_acl_header); 34af48b85bSJaegeuk Kim s = size - 4 * sizeof(struct f2fs_acl_entry_short); 35af48b85bSJaegeuk Kim if (s < 0) { 36af48b85bSJaegeuk Kim if (size % sizeof(struct f2fs_acl_entry_short)) 37af48b85bSJaegeuk Kim return -1; 38af48b85bSJaegeuk Kim return size / sizeof(struct f2fs_acl_entry_short); 39af48b85bSJaegeuk Kim } else { 40af48b85bSJaegeuk Kim if (s % sizeof(struct f2fs_acl_entry)) 41af48b85bSJaegeuk Kim return -1; 42af48b85bSJaegeuk Kim return s / sizeof(struct f2fs_acl_entry) + 4; 43af48b85bSJaegeuk Kim } 44af48b85bSJaegeuk Kim } 45af48b85bSJaegeuk Kim 46af48b85bSJaegeuk Kim static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) 47af48b85bSJaegeuk Kim { 48af48b85bSJaegeuk Kim int i, count; 49af48b85bSJaegeuk Kim struct posix_acl *acl; 50af48b85bSJaegeuk Kim struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; 51af48b85bSJaegeuk Kim struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); 52af48b85bSJaegeuk Kim const char *end = value + size; 53af48b85bSJaegeuk Kim 541618e6e2SChengguang Xu if (size < sizeof(struct f2fs_acl_header)) 551618e6e2SChengguang Xu return ERR_PTR(-EINVAL); 561618e6e2SChengguang Xu 57af48b85bSJaegeuk Kim if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) 58af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 59af48b85bSJaegeuk Kim 60af48b85bSJaegeuk Kim count = f2fs_acl_count(size); 61af48b85bSJaegeuk Kim if (count < 0) 62af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 63af48b85bSJaegeuk Kim if (count == 0) 64af48b85bSJaegeuk Kim return NULL; 65af48b85bSJaegeuk Kim 66dd802406SJaegeuk Kim acl = posix_acl_alloc(count, GFP_NOFS); 67af48b85bSJaegeuk Kim if (!acl) 68af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 69af48b85bSJaegeuk Kim 70af48b85bSJaegeuk Kim for (i = 0; i < count; i++) { 71af48b85bSJaegeuk Kim 72af48b85bSJaegeuk Kim if ((char *)entry > end) 73af48b85bSJaegeuk Kim goto fail; 74af48b85bSJaegeuk Kim 75af48b85bSJaegeuk Kim acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); 76af48b85bSJaegeuk Kim acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); 77af48b85bSJaegeuk Kim 78af48b85bSJaegeuk Kim switch (acl->a_entries[i].e_tag) { 79af48b85bSJaegeuk Kim case ACL_USER_OBJ: 80af48b85bSJaegeuk Kim case ACL_GROUP_OBJ: 81af48b85bSJaegeuk Kim case ACL_MASK: 82af48b85bSJaegeuk Kim case ACL_OTHER: 83af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 84af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry_short)); 85af48b85bSJaegeuk Kim break; 86af48b85bSJaegeuk Kim 87af48b85bSJaegeuk Kim case ACL_USER: 88af48b85bSJaegeuk Kim acl->a_entries[i].e_uid = 89af48b85bSJaegeuk Kim make_kuid(&init_user_ns, 90af48b85bSJaegeuk Kim le32_to_cpu(entry->e_id)); 91af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 92af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 93af48b85bSJaegeuk Kim break; 94af48b85bSJaegeuk Kim case ACL_GROUP: 95af48b85bSJaegeuk Kim acl->a_entries[i].e_gid = 96af48b85bSJaegeuk Kim make_kgid(&init_user_ns, 97af48b85bSJaegeuk Kim le32_to_cpu(entry->e_id)); 98af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 99af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 100af48b85bSJaegeuk Kim break; 101af48b85bSJaegeuk Kim default: 102af48b85bSJaegeuk Kim goto fail; 103af48b85bSJaegeuk Kim } 104af48b85bSJaegeuk Kim } 105af48b85bSJaegeuk Kim if ((char *)entry != end) 106af48b85bSJaegeuk Kim goto fail; 107af48b85bSJaegeuk Kim return acl; 108af48b85bSJaegeuk Kim fail: 109af48b85bSJaegeuk Kim posix_acl_release(acl); 110af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 111af48b85bSJaegeuk Kim } 112af48b85bSJaegeuk Kim 1131ecc0c5cSChao Yu static void *f2fs_acl_to_disk(struct f2fs_sb_info *sbi, 1141ecc0c5cSChao Yu const struct posix_acl *acl, size_t *size) 115af48b85bSJaegeuk Kim { 116af48b85bSJaegeuk Kim struct f2fs_acl_header *f2fs_acl; 117af48b85bSJaegeuk Kim struct f2fs_acl_entry *entry; 118af48b85bSJaegeuk Kim int i; 119af48b85bSJaegeuk Kim 1201ecc0c5cSChao Yu f2fs_acl = f2fs_kmalloc(sbi, sizeof(struct f2fs_acl_header) + 1211ecc0c5cSChao Yu acl->a_count * sizeof(struct f2fs_acl_entry), 1221ecc0c5cSChao Yu GFP_NOFS); 123af48b85bSJaegeuk Kim if (!f2fs_acl) 124af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 125af48b85bSJaegeuk Kim 126af48b85bSJaegeuk Kim f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION); 127af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)(f2fs_acl + 1); 128af48b85bSJaegeuk Kim 129af48b85bSJaegeuk Kim for (i = 0; i < acl->a_count; i++) { 130af48b85bSJaegeuk Kim 131af48b85bSJaegeuk Kim entry->e_tag = cpu_to_le16(acl->a_entries[i].e_tag); 132af48b85bSJaegeuk Kim entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm); 133af48b85bSJaegeuk Kim 134af48b85bSJaegeuk Kim switch (acl->a_entries[i].e_tag) { 135af48b85bSJaegeuk Kim case ACL_USER: 136af48b85bSJaegeuk Kim entry->e_id = cpu_to_le32( 137af48b85bSJaegeuk Kim from_kuid(&init_user_ns, 138af48b85bSJaegeuk Kim acl->a_entries[i].e_uid)); 139af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 140af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 141af48b85bSJaegeuk Kim break; 142af48b85bSJaegeuk Kim case ACL_GROUP: 143af48b85bSJaegeuk Kim entry->e_id = cpu_to_le32( 144af48b85bSJaegeuk Kim from_kgid(&init_user_ns, 145af48b85bSJaegeuk Kim acl->a_entries[i].e_gid)); 146af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 147af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 148af48b85bSJaegeuk Kim break; 149af48b85bSJaegeuk Kim case ACL_USER_OBJ: 150af48b85bSJaegeuk Kim case ACL_GROUP_OBJ: 151af48b85bSJaegeuk Kim case ACL_MASK: 152af48b85bSJaegeuk Kim case ACL_OTHER: 153af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 154af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry_short)); 155af48b85bSJaegeuk Kim break; 156af48b85bSJaegeuk Kim default: 157af48b85bSJaegeuk Kim goto fail; 158af48b85bSJaegeuk Kim } 159af48b85bSJaegeuk Kim } 160af48b85bSJaegeuk Kim *size = f2fs_acl_size(acl->a_count); 161af48b85bSJaegeuk Kim return (void *)f2fs_acl; 162af48b85bSJaegeuk Kim 163af48b85bSJaegeuk Kim fail: 164c8eb7024SChao Yu kfree(f2fs_acl); 165af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 166af48b85bSJaegeuk Kim } 167af48b85bSJaegeuk Kim 168bce8d112SJaegeuk Kim static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, 169bce8d112SJaegeuk Kim struct page *dpage) 170af48b85bSJaegeuk Kim { 171af48b85bSJaegeuk Kim int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 172af48b85bSJaegeuk Kim void *value = NULL; 173af48b85bSJaegeuk Kim struct posix_acl *acl; 174af48b85bSJaegeuk Kim int retval; 175af48b85bSJaegeuk Kim 176af48b85bSJaegeuk Kim if (type == ACL_TYPE_ACCESS) 177af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 178af48b85bSJaegeuk Kim 179bce8d112SJaegeuk Kim retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage); 180af48b85bSJaegeuk Kim if (retval > 0) { 1811ecc0c5cSChao Yu value = f2fs_kmalloc(F2FS_I_SB(inode), retval, GFP_F2FS_ZERO); 182af48b85bSJaegeuk Kim if (!value) 183af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 184bce8d112SJaegeuk Kim retval = f2fs_getxattr(inode, name_index, "", value, 185bce8d112SJaegeuk Kim retval, dpage); 186af48b85bSJaegeuk Kim } 187af48b85bSJaegeuk Kim 188c1b75eabSJaegeuk Kim if (retval > 0) 189c1b75eabSJaegeuk Kim acl = f2fs_acl_from_disk(value, retval); 190c1b75eabSJaegeuk Kim else if (retval == -ENODATA) 191af48b85bSJaegeuk Kim acl = NULL; 192af48b85bSJaegeuk Kim else 193af48b85bSJaegeuk Kim acl = ERR_PTR(retval); 194c8eb7024SChao Yu kfree(value); 195c1b75eabSJaegeuk Kim 196af48b85bSJaegeuk Kim return acl; 197af48b85bSJaegeuk Kim } 198af48b85bSJaegeuk Kim 199*0cad6246SMiklos Szeredi struct posix_acl *f2fs_get_acl(struct inode *inode, int type, bool rcu) 200bce8d112SJaegeuk Kim { 201*0cad6246SMiklos Szeredi if (rcu) 202*0cad6246SMiklos Szeredi return ERR_PTR(-ECHILD); 203*0cad6246SMiklos Szeredi 204bce8d112SJaegeuk Kim return __f2fs_get_acl(inode, type, NULL); 205bce8d112SJaegeuk Kim } 206bce8d112SJaegeuk Kim 20717232e83SChao Yu static int f2fs_acl_update_mode(struct inode *inode, umode_t *mode_p, 20817232e83SChao Yu struct posix_acl **acl) 20917232e83SChao Yu { 21017232e83SChao Yu umode_t mode = inode->i_mode; 21117232e83SChao Yu int error; 21217232e83SChao Yu 21317232e83SChao Yu if (is_inode_flag_set(inode, FI_ACL_MODE)) 21417232e83SChao Yu mode = F2FS_I(inode)->i_acl_mode; 21517232e83SChao Yu 21617232e83SChao Yu error = posix_acl_equiv_mode(*acl, &mode); 21717232e83SChao Yu if (error < 0) 21817232e83SChao Yu return error; 21917232e83SChao Yu if (error == 0) 22017232e83SChao Yu *acl = NULL; 2217d6beb71SLinus Torvalds if (!in_group_p(i_gid_into_mnt(&init_user_ns, inode)) && 2227d6beb71SLinus Torvalds !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) 22317232e83SChao Yu mode &= ~S_ISGID; 22417232e83SChao Yu *mode_p = mode; 22517232e83SChao Yu return 0; 22617232e83SChao Yu } 22717232e83SChao Yu 228a6dda0e6SChristoph Hellwig static int __f2fs_set_acl(struct inode *inode, int type, 2292ed2d5b3SJaegeuk Kim struct posix_acl *acl, struct page *ipage) 230af48b85bSJaegeuk Kim { 231af48b85bSJaegeuk Kim int name_index; 232af48b85bSJaegeuk Kim void *value = NULL; 233af48b85bSJaegeuk Kim size_t size = 0; 234af48b85bSJaegeuk Kim int error; 23514af20fcSErnesto A. Fernández umode_t mode = inode->i_mode; 236af48b85bSJaegeuk Kim 237af48b85bSJaegeuk Kim switch (type) { 238af48b85bSJaegeuk Kim case ACL_TYPE_ACCESS: 239af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 240c925dc16SJaegeuk Kim if (acl && !ipage) { 24117232e83SChao Yu error = f2fs_acl_update_mode(inode, &mode, &acl); 24207393101SJan Kara if (error) 243af48b85bSJaegeuk Kim return error; 24414af20fcSErnesto A. Fernández set_acl_inode(inode, mode); 245af48b85bSJaegeuk Kim } 246af48b85bSJaegeuk Kim break; 247af48b85bSJaegeuk Kim 248af48b85bSJaegeuk Kim case ACL_TYPE_DEFAULT: 249af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 250af48b85bSJaegeuk Kim if (!S_ISDIR(inode->i_mode)) 251af48b85bSJaegeuk Kim return acl ? -EACCES : 0; 252af48b85bSJaegeuk Kim break; 253af48b85bSJaegeuk Kim 254af48b85bSJaegeuk Kim default: 255af48b85bSJaegeuk Kim return -EINVAL; 256af48b85bSJaegeuk Kim } 257af48b85bSJaegeuk Kim 258af48b85bSJaegeuk Kim if (acl) { 2591ecc0c5cSChao Yu value = f2fs_acl_to_disk(F2FS_I_SB(inode), acl, &size); 260af48b85bSJaegeuk Kim if (IS_ERR(value)) { 26191942321SJaegeuk Kim clear_inode_flag(inode, FI_ACL_MODE); 26268390dd9SZhang Shengju return PTR_ERR(value); 263af48b85bSJaegeuk Kim } 264af48b85bSJaegeuk Kim } 265af48b85bSJaegeuk Kim 266c02745efSJaegeuk Kim error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0); 267af48b85bSJaegeuk Kim 268c8eb7024SChao Yu kfree(value); 269af48b85bSJaegeuk Kim if (!error) 270af48b85bSJaegeuk Kim set_cached_acl(inode, type, acl); 271af48b85bSJaegeuk Kim 27291942321SJaegeuk Kim clear_inode_flag(inode, FI_ACL_MODE); 273af48b85bSJaegeuk Kim return error; 274af48b85bSJaegeuk Kim } 275af48b85bSJaegeuk Kim 276549c7297SChristian Brauner int f2fs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, 277549c7297SChristian Brauner struct posix_acl *acl, int type) 278a6dda0e6SChristoph Hellwig { 2791f227a3eSJaegeuk Kim if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 2801f227a3eSJaegeuk Kim return -EIO; 2811f227a3eSJaegeuk Kim 282a6dda0e6SChristoph Hellwig return __f2fs_set_acl(inode, type, acl, NULL); 283a6dda0e6SChristoph Hellwig } 284a6dda0e6SChristoph Hellwig 285bce8d112SJaegeuk Kim /* 286bce8d112SJaegeuk Kim * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create 287bce8d112SJaegeuk Kim * are copied from posix_acl.c 288bce8d112SJaegeuk Kim */ 289bce8d112SJaegeuk Kim static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl, 290bce8d112SJaegeuk Kim gfp_t flags) 291af48b85bSJaegeuk Kim { 292bce8d112SJaegeuk Kim struct posix_acl *clone = NULL; 293bce8d112SJaegeuk Kim 294bce8d112SJaegeuk Kim if (acl) { 295bce8d112SJaegeuk Kim int size = sizeof(struct posix_acl) + acl->a_count * 296bce8d112SJaegeuk Kim sizeof(struct posix_acl_entry); 297bce8d112SJaegeuk Kim clone = kmemdup(acl, size, flags); 298bce8d112SJaegeuk Kim if (clone) 29966717260SElena Reshetova refcount_set(&clone->a_refcount, 1); 300bce8d112SJaegeuk Kim } 301bce8d112SJaegeuk Kim return clone; 302bce8d112SJaegeuk Kim } 303bce8d112SJaegeuk Kim 304bce8d112SJaegeuk Kim static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) 305bce8d112SJaegeuk Kim { 306bce8d112SJaegeuk Kim struct posix_acl_entry *pa, *pe; 307bce8d112SJaegeuk Kim struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; 308bce8d112SJaegeuk Kim umode_t mode = *mode_p; 309bce8d112SJaegeuk Kim int not_equiv = 0; 310bce8d112SJaegeuk Kim 311bce8d112SJaegeuk Kim /* assert(atomic_read(acl->a_refcount) == 1); */ 312bce8d112SJaegeuk Kim 313bce8d112SJaegeuk Kim FOREACH_ACL_ENTRY(pa, acl, pe) { 314bce8d112SJaegeuk Kim switch (pa->e_tag) { 315bce8d112SJaegeuk Kim case ACL_USER_OBJ: 316bce8d112SJaegeuk Kim pa->e_perm &= (mode >> 6) | ~S_IRWXO; 317bce8d112SJaegeuk Kim mode &= (pa->e_perm << 6) | ~S_IRWXU; 318bce8d112SJaegeuk Kim break; 319bce8d112SJaegeuk Kim 320bce8d112SJaegeuk Kim case ACL_USER: 321bce8d112SJaegeuk Kim case ACL_GROUP: 322bce8d112SJaegeuk Kim not_equiv = 1; 323bce8d112SJaegeuk Kim break; 324bce8d112SJaegeuk Kim 325bce8d112SJaegeuk Kim case ACL_GROUP_OBJ: 326bce8d112SJaegeuk Kim group_obj = pa; 327bce8d112SJaegeuk Kim break; 328bce8d112SJaegeuk Kim 329bce8d112SJaegeuk Kim case ACL_OTHER: 330bce8d112SJaegeuk Kim pa->e_perm &= mode | ~S_IRWXO; 331bce8d112SJaegeuk Kim mode &= pa->e_perm | ~S_IRWXO; 332bce8d112SJaegeuk Kim break; 333bce8d112SJaegeuk Kim 334bce8d112SJaegeuk Kim case ACL_MASK: 335bce8d112SJaegeuk Kim mask_obj = pa; 336bce8d112SJaegeuk Kim not_equiv = 1; 337bce8d112SJaegeuk Kim break; 338bce8d112SJaegeuk Kim 339bce8d112SJaegeuk Kim default: 340bce8d112SJaegeuk Kim return -EIO; 341bce8d112SJaegeuk Kim } 342bce8d112SJaegeuk Kim } 343bce8d112SJaegeuk Kim 344bce8d112SJaegeuk Kim if (mask_obj) { 345bce8d112SJaegeuk Kim mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; 346bce8d112SJaegeuk Kim mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; 347bce8d112SJaegeuk Kim } else { 348bce8d112SJaegeuk Kim if (!group_obj) 349bce8d112SJaegeuk Kim return -EIO; 350bce8d112SJaegeuk Kim group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; 351bce8d112SJaegeuk Kim mode &= (group_obj->e_perm << 3) | ~S_IRWXG; 352bce8d112SJaegeuk Kim } 353bce8d112SJaegeuk Kim 354bce8d112SJaegeuk Kim *mode_p = (*mode_p & ~S_IRWXUGO) | mode; 355bce8d112SJaegeuk Kim return not_equiv; 356bce8d112SJaegeuk Kim } 357bce8d112SJaegeuk Kim 358bce8d112SJaegeuk Kim static int f2fs_acl_create(struct inode *dir, umode_t *mode, 359bce8d112SJaegeuk Kim struct posix_acl **default_acl, struct posix_acl **acl, 360bce8d112SJaegeuk Kim struct page *dpage) 361bce8d112SJaegeuk Kim { 362bce8d112SJaegeuk Kim struct posix_acl *p; 363272e083fSChao Yu struct posix_acl *clone; 364bce8d112SJaegeuk Kim int ret; 365bce8d112SJaegeuk Kim 366272e083fSChao Yu *acl = NULL; 367272e083fSChao Yu *default_acl = NULL; 368272e083fSChao Yu 369bce8d112SJaegeuk Kim if (S_ISLNK(*mode) || !IS_POSIXACL(dir)) 370272e083fSChao Yu return 0; 371bce8d112SJaegeuk Kim 372bce8d112SJaegeuk Kim p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage); 373272e083fSChao Yu if (!p || p == ERR_PTR(-EOPNOTSUPP)) { 374272e083fSChao Yu *mode &= ~current_umask(); 375272e083fSChao Yu return 0; 376bce8d112SJaegeuk Kim } 377272e083fSChao Yu if (IS_ERR(p)) 378272e083fSChao Yu return PTR_ERR(p); 379bce8d112SJaegeuk Kim 380272e083fSChao Yu clone = f2fs_acl_clone(p, GFP_NOFS); 381f6176473STiezhu Yang if (!clone) { 382f6176473STiezhu Yang ret = -ENOMEM; 383f6176473STiezhu Yang goto release_acl; 384f6176473STiezhu Yang } 385bce8d112SJaegeuk Kim 386272e083fSChao Yu ret = f2fs_acl_create_masq(clone, mode); 38783dfe53cSChao Yu if (ret < 0) 388f6176473STiezhu Yang goto release_clone; 389bce8d112SJaegeuk Kim 390272e083fSChao Yu if (ret == 0) 391272e083fSChao Yu posix_acl_release(clone); 392272e083fSChao Yu else 393272e083fSChao Yu *acl = clone; 394bce8d112SJaegeuk Kim 395272e083fSChao Yu if (!S_ISDIR(*mode)) 396bce8d112SJaegeuk Kim posix_acl_release(p); 397272e083fSChao Yu else 398bce8d112SJaegeuk Kim *default_acl = p; 399bce8d112SJaegeuk Kim 400bce8d112SJaegeuk Kim return 0; 40183dfe53cSChao Yu 402f6176473STiezhu Yang release_clone: 403272e083fSChao Yu posix_acl_release(clone); 404f6176473STiezhu Yang release_acl: 40583dfe53cSChao Yu posix_acl_release(p); 406f6176473STiezhu Yang return ret; 407bce8d112SJaegeuk Kim } 408bce8d112SJaegeuk Kim 409bce8d112SJaegeuk Kim int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, 410bce8d112SJaegeuk Kim struct page *dpage) 411bce8d112SJaegeuk Kim { 412bce8d112SJaegeuk Kim struct posix_acl *default_acl = NULL, *acl = NULL; 413beb78181SZhang Qilong int error; 414af48b85bSJaegeuk Kim 415bce8d112SJaegeuk Kim error = f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage); 416af48b85bSJaegeuk Kim if (error) 417af48b85bSJaegeuk Kim return error; 418b8b60e1aSJaegeuk Kim 4197c45729aSJaegeuk Kim f2fs_mark_inode_dirty_sync(inode, true); 420205b9822SJaegeuk Kim 421a6dda0e6SChristoph Hellwig if (default_acl) { 422a6dda0e6SChristoph Hellwig error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, 423a6dda0e6SChristoph Hellwig ipage); 424a6dda0e6SChristoph Hellwig posix_acl_release(default_acl); 425313ed62aSChengguang Xu } else { 426313ed62aSChengguang Xu inode->i_default_acl = NULL; 427af48b85bSJaegeuk Kim } 428af48b85bSJaegeuk Kim if (acl) { 4293b6709b7SKinglong Mee if (!error) 430a6dda0e6SChristoph Hellwig error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, 431a6dda0e6SChristoph Hellwig ipage); 432af48b85bSJaegeuk Kim posix_acl_release(acl); 433313ed62aSChengguang Xu } else { 434313ed62aSChengguang Xu inode->i_acl = NULL; 435a6dda0e6SChristoph Hellwig } 436a6dda0e6SChristoph Hellwig 437af48b85bSJaegeuk Kim return error; 438af48b85bSJaegeuk Kim } 439