linux/fs/ocfs2/acl.c
<<
>>
Prefs
   1/* -*- mode: c; c-basic-offset: 8; -*-
   2 * vim: noexpandtab sw=8 ts=8 sts=0:
   3 *
   4 * acl.c
   5 *
   6 * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
   7 *
   8 * CREDITS:
   9 * Lots of code in this file is copy from linux/fs/ext3/acl.c.
  10 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  11 *
  12 * This program is free software; you can redistribute it and/or
  13 * modify it under the terms of the GNU General Public
  14 * License version 2 as published by the Free Software Foundation.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * General Public License for more details.
  20 */
  21
  22#include <linux/init.h>
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/string.h>
  26
  27#include <cluster/masklog.h>
  28
  29#include "ocfs2.h"
  30#include "alloc.h"
  31#include "dlmglue.h"
  32#include "file.h"
  33#include "inode.h"
  34#include "journal.h"
  35#include "ocfs2_fs.h"
  36
  37#include "xattr.h"
  38#include "acl.h"
  39
  40/*
  41 * Convert from xattr value to acl struct.
  42 */
  43static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
  44{
  45        int n, count;
  46        struct posix_acl *acl;
  47
  48        if (!value)
  49                return NULL;
  50        if (size < sizeof(struct posix_acl_entry))
  51                return ERR_PTR(-EINVAL);
  52
  53        count = size / sizeof(struct posix_acl_entry);
  54
  55        acl = posix_acl_alloc(count, GFP_NOFS);
  56        if (!acl)
  57                return ERR_PTR(-ENOMEM);
  58        for (n = 0; n < count; n++) {
  59                struct ocfs2_acl_entry *entry =
  60                        (struct ocfs2_acl_entry *)value;
  61
  62                acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
  63                acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
  64                switch(acl->a_entries[n].e_tag) {
  65                case ACL_USER:
  66                        acl->a_entries[n].e_uid =
  67                                make_kuid(&init_user_ns,
  68                                          le32_to_cpu(entry->e_id));
  69                        break;
  70                case ACL_GROUP:
  71                        acl->a_entries[n].e_gid =
  72                                make_kgid(&init_user_ns,
  73                                          le32_to_cpu(entry->e_id));
  74                        break;
  75                default:
  76                        break;
  77                }
  78                value += sizeof(struct posix_acl_entry);
  79
  80        }
  81        return acl;
  82}
  83
  84/*
  85 * Convert acl struct to xattr value.
  86 */
  87static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
  88{
  89        struct ocfs2_acl_entry *entry = NULL;
  90        char *ocfs2_acl;
  91        size_t n;
  92
  93        *size = acl->a_count * sizeof(struct posix_acl_entry);
  94
  95        ocfs2_acl = kmalloc(*size, GFP_NOFS);
  96        if (!ocfs2_acl)
  97                return ERR_PTR(-ENOMEM);
  98
  99        entry = (struct ocfs2_acl_entry *)ocfs2_acl;
 100        for (n = 0; n < acl->a_count; n++, entry++) {
 101                entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
 102                entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
 103                switch(acl->a_entries[n].e_tag) {
 104                case ACL_USER:
 105                        entry->e_id = cpu_to_le32(
 106                                from_kuid(&init_user_ns,
 107                                          acl->a_entries[n].e_uid));
 108                        break;
 109                case ACL_GROUP:
 110                        entry->e_id = cpu_to_le32(
 111                                from_kgid(&init_user_ns,
 112                                          acl->a_entries[n].e_gid));
 113                        break;
 114                default:
 115                        entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
 116                        break;
 117                }
 118        }
 119        return ocfs2_acl;
 120}
 121
 122static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
 123                                              int type,
 124                                              struct buffer_head *di_bh)
 125{
 126        int name_index;
 127        char *value = NULL;
 128        struct posix_acl *acl;
 129        int retval;
 130
 131        switch (type) {
 132        case ACL_TYPE_ACCESS:
 133                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
 134                break;
 135        case ACL_TYPE_DEFAULT:
 136                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
 137                break;
 138        default:
 139                return ERR_PTR(-EINVAL);
 140        }
 141
 142        retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
 143        if (retval > 0) {
 144                value = kmalloc(retval, GFP_NOFS);
 145                if (!value)
 146                        return ERR_PTR(-ENOMEM);
 147                retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
 148                                                "", value, retval);
 149        }
 150
 151        if (retval > 0)
 152                acl = ocfs2_acl_from_xattr(value, retval);
 153        else if (retval == -ENODATA || retval == 0)
 154                acl = NULL;
 155        else
 156                acl = ERR_PTR(retval);
 157
 158        kfree(value);
 159
 160        return acl;
 161}
 162
 163/*
 164 * Helper function to set i_mode in memory and disk. Some call paths
 165 * will not have di_bh or a journal handle to pass, in which case it
 166 * will create it's own.
 167 */
 168static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
 169                              handle_t *handle, umode_t new_mode)
 170{
 171        int ret, commit_handle = 0;
 172        struct ocfs2_dinode *di;
 173
 174        if (di_bh == NULL) {
 175                ret = ocfs2_read_inode_block(inode, &di_bh);
 176                if (ret) {
 177                        mlog_errno(ret);
 178                        goto out;
 179                }
 180        } else
 181                get_bh(di_bh);
 182
 183        if (handle == NULL) {
 184                handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
 185                                           OCFS2_INODE_UPDATE_CREDITS);
 186                if (IS_ERR(handle)) {
 187                        ret = PTR_ERR(handle);
 188                        mlog_errno(ret);
 189                        goto out_brelse;
 190                }
 191
 192                commit_handle = 1;
 193        }
 194
 195        di = (struct ocfs2_dinode *)di_bh->b_data;
 196        ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
 197                                      OCFS2_JOURNAL_ACCESS_WRITE);
 198        if (ret) {
 199                mlog_errno(ret);
 200                goto out_commit;
 201        }
 202
 203        inode->i_mode = new_mode;
 204        inode->i_ctime = CURRENT_TIME;
 205        di->i_mode = cpu_to_le16(inode->i_mode);
 206        di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
 207        di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
 208        ocfs2_update_inode_fsync_trans(handle, inode, 0);
 209
 210        ocfs2_journal_dirty(handle, di_bh);
 211
 212out_commit:
 213        if (commit_handle)
 214                ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
 215out_brelse:
 216        brelse(di_bh);
 217out:
 218        return ret;
 219}
 220
 221/*
 222 * Set the access or default ACL of an inode.
 223 */
 224int ocfs2_set_acl(handle_t *handle,
 225                         struct inode *inode,
 226                         struct buffer_head *di_bh,
 227                         int type,
 228                         struct posix_acl *acl,
 229                         struct ocfs2_alloc_context *meta_ac,
 230                         struct ocfs2_alloc_context *data_ac)
 231{
 232        int name_index;
 233        void *value = NULL;
 234        size_t size = 0;
 235        int ret;
 236
 237        if (S_ISLNK(inode->i_mode))
 238                return -EOPNOTSUPP;
 239
 240        switch (type) {
 241        case ACL_TYPE_ACCESS:
 242                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
 243                if (acl) {
 244                        umode_t mode = inode->i_mode;
 245                        ret = posix_acl_equiv_mode(acl, &mode);
 246                        if (ret < 0)
 247                                return ret;
 248
 249                        if (ret == 0)
 250                                acl = NULL;
 251
 252                        ret = ocfs2_acl_set_mode(inode, di_bh,
 253                                                 handle, mode);
 254                        if (ret)
 255                                return ret;
 256                }
 257                break;
 258        case ACL_TYPE_DEFAULT:
 259                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
 260                if (!S_ISDIR(inode->i_mode))
 261                        return acl ? -EACCES : 0;
 262                break;
 263        default:
 264                return -EINVAL;
 265        }
 266
 267        if (acl) {
 268                value = ocfs2_acl_to_xattr(acl, &size);
 269                if (IS_ERR(value))
 270                        return (int)PTR_ERR(value);
 271        }
 272
 273        if (handle)
 274                ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
 275                                             "", value, size, 0,
 276                                             meta_ac, data_ac);
 277        else
 278                ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
 279
 280        kfree(value);
 281
 282        return ret;
 283}
 284
 285int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 286{
 287        struct buffer_head *bh = NULL;
 288        int status = 0;
 289
 290        status = ocfs2_inode_lock(inode, &bh, 1);
 291        if (status < 0) {
 292                if (status != -ENOENT)
 293                        mlog_errno(status);
 294                return status;
 295        }
 296        status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
 297        ocfs2_inode_unlock(inode, 1);
 298        brelse(bh);
 299        return status;
 300}
 301
 302struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
 303{
 304        struct ocfs2_super *osb;
 305        struct buffer_head *di_bh = NULL;
 306        struct posix_acl *acl;
 307        int ret;
 308
 309        osb = OCFS2_SB(inode->i_sb);
 310        if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
 311                return NULL;
 312        ret = ocfs2_inode_lock(inode, &di_bh, 0);
 313        if (ret < 0) {
 314                if (ret != -ENOENT)
 315                        mlog_errno(ret);
 316                return ERR_PTR(ret);
 317        }
 318
 319        acl = ocfs2_get_acl_nolock(inode, type, di_bh);
 320
 321        ocfs2_inode_unlock(inode, 0);
 322        brelse(di_bh);
 323        return acl;
 324}
 325
 326int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
 327{
 328        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 329        struct posix_acl *acl;
 330        int ret;
 331
 332        if (S_ISLNK(inode->i_mode))
 333                return -EOPNOTSUPP;
 334
 335        if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
 336                return 0;
 337
 338        acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
 339        if (IS_ERR(acl) || !acl)
 340                return PTR_ERR(acl);
 341        ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
 342        if (ret)
 343                return ret;
 344        ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
 345                            acl, NULL, NULL);
 346        posix_acl_release(acl);
 347        return ret;
 348}
 349
 350/*
 351 * Initialize the ACLs of a new inode. If parent directory has default ACL,
 352 * then clone to new inode. Called from ocfs2_mknod.
 353 */
 354int ocfs2_init_acl(handle_t *handle,
 355                   struct inode *inode,
 356                   struct inode *dir,
 357                   struct buffer_head *di_bh,
 358                   struct buffer_head *dir_bh,
 359                   struct ocfs2_alloc_context *meta_ac,
 360                   struct ocfs2_alloc_context *data_ac)
 361{
 362        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 363        struct posix_acl *acl = NULL;
 364        int ret = 0, ret2;
 365        umode_t mode;
 366
 367        if (!S_ISLNK(inode->i_mode)) {
 368                if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
 369                        acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
 370                                                   dir_bh);
 371                        if (IS_ERR(acl))
 372                                return PTR_ERR(acl);
 373                }
 374                if (!acl) {
 375                        mode = inode->i_mode & ~current_umask();
 376                        ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
 377                        if (ret) {
 378                                mlog_errno(ret);
 379                                goto cleanup;
 380                        }
 381                }
 382        }
 383        if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
 384                if (S_ISDIR(inode->i_mode)) {
 385                        ret = ocfs2_set_acl(handle, inode, di_bh,
 386                                            ACL_TYPE_DEFAULT, acl,
 387                                            meta_ac, data_ac);
 388                        if (ret)
 389                                goto cleanup;
 390                }
 391                mode = inode->i_mode;
 392                ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
 393                if (ret < 0)
 394                        return ret;
 395
 396                ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
 397                if (ret2) {
 398                        mlog_errno(ret2);
 399                        ret = ret2;
 400                        goto cleanup;
 401                }
 402                if (ret > 0) {
 403                        ret = ocfs2_set_acl(handle, inode,
 404                                            di_bh, ACL_TYPE_ACCESS,
 405                                            acl, meta_ac, data_ac);
 406                }
 407        }
 408cleanup:
 409        posix_acl_release(acl);
 410        return ret;
 411}
 412