linux/fs/gfs2/acl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
   4 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
   5 */
   6
   7#include <linux/sched.h>
   8#include <linux/slab.h>
   9#include <linux/spinlock.h>
  10#include <linux/completion.h>
  11#include <linux/buffer_head.h>
  12#include <linux/xattr.h>
  13#include <linux/posix_acl.h>
  14#include <linux/posix_acl_xattr.h>
  15#include <linux/gfs2_ondisk.h>
  16
  17#include "gfs2.h"
  18#include "incore.h"
  19#include "acl.h"
  20#include "xattr.h"
  21#include "glock.h"
  22#include "inode.h"
  23#include "meta_io.h"
  24#include "quota.h"
  25#include "rgrp.h"
  26#include "trans.h"
  27#include "util.h"
  28
  29static const char *gfs2_acl_name(int type)
  30{
  31        switch (type) {
  32        case ACL_TYPE_ACCESS:
  33                return XATTR_POSIX_ACL_ACCESS;
  34        case ACL_TYPE_DEFAULT:
  35                return XATTR_POSIX_ACL_DEFAULT;
  36        }
  37        return NULL;
  38}
  39
  40static struct posix_acl *__gfs2_get_acl(struct inode *inode, int type)
  41{
  42        struct gfs2_inode *ip = GFS2_I(inode);
  43        struct posix_acl *acl;
  44        const char *name;
  45        char *data;
  46        int len;
  47
  48        if (!ip->i_eattr)
  49                return NULL;
  50
  51        name = gfs2_acl_name(type);
  52        len = gfs2_xattr_acl_get(ip, name, &data);
  53        if (len <= 0)
  54                return ERR_PTR(len);
  55        acl = posix_acl_from_xattr(&init_user_ns, data, len);
  56        kfree(data);
  57        return acl;
  58}
  59
  60struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
  61{
  62        struct gfs2_inode *ip = GFS2_I(inode);
  63        struct gfs2_holder gh;
  64        bool need_unlock = false;
  65        struct posix_acl *acl;
  66
  67        if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
  68                int ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
  69                                             LM_FLAG_ANY, &gh);
  70                if (ret)
  71                        return ERR_PTR(ret);
  72                need_unlock = true;
  73        }
  74        acl = __gfs2_get_acl(inode, type);
  75        if (need_unlock)
  76                gfs2_glock_dq_uninit(&gh);
  77        return acl;
  78}
  79
  80int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  81{
  82        int error;
  83        size_t len;
  84        char *data;
  85        const char *name = gfs2_acl_name(type);
  86
  87        if (acl) {
  88                len = posix_acl_xattr_size(acl->a_count);
  89                data = kmalloc(len, GFP_NOFS);
  90                if (data == NULL)
  91                        return -ENOMEM;
  92                error = posix_acl_to_xattr(&init_user_ns, acl, data, len);
  93                if (error < 0)
  94                        goto out;
  95        } else {
  96                data = NULL;
  97                len = 0;
  98        }
  99
 100        error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
 101        if (error)
 102                goto out;
 103        set_cached_acl(inode, type, acl);
 104out:
 105        kfree(data);
 106        return error;
 107}
 108
 109int gfs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
 110                 struct posix_acl *acl, int type)
 111{
 112        struct gfs2_inode *ip = GFS2_I(inode);
 113        struct gfs2_holder gh;
 114        bool need_unlock = false;
 115        int ret;
 116        umode_t mode;
 117
 118        if (acl && acl->a_count > GFS2_ACL_MAX_ENTRIES(GFS2_SB(inode)))
 119                return -E2BIG;
 120
 121        ret = gfs2_qa_get(ip);
 122        if (ret)
 123                return ret;
 124
 125        if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
 126                ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
 127                if (ret)
 128                        goto out;
 129                need_unlock = true;
 130        }
 131
 132        mode = inode->i_mode;
 133        if (type == ACL_TYPE_ACCESS && acl) {
 134                ret = posix_acl_update_mode(&init_user_ns, inode, &mode, &acl);
 135                if (ret)
 136                        goto unlock;
 137        }
 138
 139        ret = __gfs2_set_acl(inode, acl, type);
 140        if (!ret && mode != inode->i_mode) {
 141                inode->i_ctime = current_time(inode);
 142                inode->i_mode = mode;
 143                mark_inode_dirty(inode);
 144        }
 145unlock:
 146        if (need_unlock)
 147                gfs2_glock_dq_uninit(&gh);
 148out:
 149        gfs2_qa_put(ip);
 150        return ret;
 151}
 152