X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fmdd%2Fmdd_permission.c;h=1debe3255129c477d229e0a49a1c225c3c95ae5b;hb=49c61548c35d67f34120fd64916a55fd20a6ab68;hp=1dad3ebbb07be2d4ed7d784bd735855b6bfb4580;hpb=3192e52a89946f12fd36d28a686c169d01d36e64;p=fs%2Flustre-release.git diff --git a/lustre/mdd/mdd_permission.c b/lustre/mdd/mdd_permission.c index 1dad3eb..1debe32 100644 --- a/lustre/mdd/mdd_permission.c +++ b/lustre/mdd/mdd_permission.c @@ -1,116 +1,176 @@ -/* -*- MODE: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * mdd/mdd_handler.c - * Lustre Metadata Server (mdd) routines + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. * - * Copyright (C) 2006 Cluster File Systems, Inc. - * Author: fangyong@clusterfs.com - * lsy@clusterfs.com - * This file is part of the Lustre file system, http://www.lustre.org - * Lustre is a trademark of Cluster File Systems, Inc. + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). * - * You may have signed or agreed to another license before downloading - * this software. If so, you are bound by the terms and conditions - * of that agreement, and the following does not apply to you. See the - * LICENSE file included with this distribution for more information. + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * If you did not agree to a different license, then this copy of Lustre - * is open source software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * - * In either case, Lustre is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * license text for more details. + * GPL HEADER END */ -#ifndef EXPORT_SYMTAB -# define EXPORT_SYMTAB -#endif +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2012, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lustre/mdd/mdd_permission.c + * + * Lustre Metadata Server (mdd) routines + * + * Author: fangyong@clusterfs.com + * Author: lsy@clusterfs.com + */ + #define DEBUG_SUBSYSTEM S_MDS -#include -#include -#include #include #include -#include #include - -#include #include -#include #include "mdd_internal.h" #ifdef CONFIG_FS_POSIX_ACL /* - * Get default acl EA only. - * Hold read_lock for mdd_obj. + * Hold write_lock for o. */ -int mdd_acl_def_get(const struct lu_env *env, struct mdd_object *mdd_obj, - struct md_attr *ma) +int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, + struct thandle *handle) { - struct lu_buf *buf; - int rc; - ENTRY; - - if (ma->ma_valid & MA_ACL_DEF) - RETURN(0); - - buf = mdd_buf_get(env, ma->ma_acl, ma->ma_acl_size); - rc = mdo_xattr_get(env, mdd_obj, buf, XATTR_NAME_ACL_DEFAULT, - BYPASS_CAPA); - if (rc > 0) { - ma->ma_acl_size = rc; - ma->ma_valid |= MA_ACL_DEF; - rc = 0; - } else if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) { - rc = 0; - } - RETURN(rc); + struct lu_buf *buf; + posix_acl_xattr_header *head; + posix_acl_xattr_entry *entry; + int entry_count; + int rc; + + ENTRY; + + buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, + sizeof(mdd_env_info(env)->mti_xattr_buf)); + + rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); + if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) + RETURN(0); + else if (rc <= 0) + RETURN(rc); + + buf->lb_len = rc; + head = (posix_acl_xattr_header *)(buf->lb_buf); + entry = head->a_entries; + entry_count = (buf->lb_len - sizeof(head->a_version)) / + sizeof(posix_acl_xattr_entry); + if (entry_count <= 0) + RETURN(0); + + rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count); + if (rc) + RETURN(rc); + + rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS, + 0, handle, BYPASS_CAPA); + RETURN(rc); } -/* - * Hold write_lock for o. - */ -int mdd_acl_chmod(const struct lu_env *env, struct mdd_object *o, __u32 mode, - struct thandle *handle) +int mdd_acl_set(const struct lu_env *env, struct mdd_object *obj, + const struct lu_buf *buf, int fl) { - struct lu_buf *buf; - posix_acl_xattr_header *head; - posix_acl_xattr_entry *entry; - int entry_count; - int rc; - - ENTRY; - - buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, - sizeof(mdd_env_info(env)->mti_xattr_buf)); - - rc = mdo_xattr_get(env, o, buf, XATTR_NAME_ACL_ACCESS, BYPASS_CAPA); - if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) - RETURN(0); - else if (rc <= 0) - RETURN(rc); - - buf->lb_len = rc; - head = (posix_acl_xattr_header *)(buf->lb_buf); - entry = head->a_entries; - entry_count = (buf->lb_len - sizeof(head->a_version)) / - sizeof(posix_acl_xattr_entry); - if (entry_count <= 0) - RETURN(0); - - rc = lustre_posix_acl_chmod_masq(entry, mode, entry_count); - if (rc) - RETURN(rc); + struct mdd_device *mdd = mdd_obj2mdd_dev(obj); + struct lu_attr *la = &mdd_env_info(env)->mti_la; + struct thandle *handle; + posix_acl_xattr_header *head; + posix_acl_xattr_entry *entry; + int rc, entry_count; + bool not_equiv, mode_change; + mode_t mode; + ENTRY; + + rc = mdd_la_get(env, obj, la, BYPASS_CAPA); + if (rc) + RETURN(rc); + + head = (posix_acl_xattr_header *)(buf->lb_buf); + entry = head->a_entries; + entry_count = (buf->lb_len - sizeof(head->a_version)) / + sizeof(posix_acl_xattr_entry); + if (entry_count <= 0) + RETURN(0); + + LASSERT(la->la_valid & LA_MODE); + mode = la->la_mode; + rc = lustre_posix_acl_equiv_mode(entry, &mode, entry_count); + if (rc < 0) + RETURN(rc); + + not_equiv = (rc > 0); + mode_change = (mode != la->la_mode); + + handle = mdd_trans_create(env, mdd); + if (IS_ERR(handle)) + RETURN(PTR_ERR(handle)); + + /* rc tells whether ACL can be represented by i_mode only */ + if (not_equiv) + rc = mdo_declare_xattr_set(env, obj, buf, + XATTR_NAME_ACL_ACCESS, fl, handle); + else + rc = mdo_declare_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS, + handle); + if (rc) + GOTO(stop, rc); + + if (mode_change) { + la->la_mode = mode; + rc = mdo_declare_attr_set(env, obj, la, handle); + } - rc = mdo_xattr_set(env, o, buf, XATTR_NAME_ACL_ACCESS, - 0, handle, BYPASS_CAPA); - RETURN(rc); + rc = mdd_trans_start(env, mdd, handle); + if (rc) + GOTO(stop, rc); + + mdd_write_lock(env, obj, MOR_TGT_CHILD); + /* whether ACL can be represented by i_mode only */ + if (not_equiv) + rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, fl, + handle, mdd_object_capa(env, obj)); + else + rc = mdo_xattr_del(env, obj, XATTR_NAME_ACL_ACCESS, handle, + mdd_object_capa(env, obj)); + if (rc) + GOTO(unlock, rc); + + if (mode_change) + rc = mdo_attr_set(env, obj, la, handle, + mdd_object_capa(env, obj)); + + /* security-replated changes may require sync */ + handle->th_sync |= !!mdd->mdd_sync_permission; +unlock: + mdd_write_unlock(env, obj); +stop: + mdd_trans_stop(env, mdd, rc, handle); + + RETURN(rc); } /* @@ -122,7 +182,8 @@ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, posix_acl_xattr_header *head; posix_acl_xattr_entry *entry; int entry_count; - int rc; + __u32 old = *mode; + int rc, rc2; ENTRY; @@ -132,48 +193,36 @@ int __mdd_acl_init(const struct lu_env *env, struct mdd_object *obj, sizeof(posix_acl_xattr_entry); if (entry_count <= 0) RETURN(0); - - if (S_ISDIR(*mode)) { - rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_DEFAULT, 0, + + if (S_ISDIR(*mode)) { + rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_DEFAULT, 0, handle, BYPASS_CAPA); if (rc) RETURN(rc); - } + } rc = lustre_posix_acl_create_masq(entry, mode, entry_count); - if (rc <= 0) + if (rc < 0) RETURN(rc); - rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, handle, - BYPASS_CAPA); - RETURN(rc); -} - -/* - * Hold read_lock for pobj. - * Hold write_lock for cobj. - */ -int mdd_acl_init(const struct lu_env *env, struct mdd_object *pobj, - struct mdd_object *cobj, __u32 *mode, struct thandle *handle) -{ - struct lu_buf *buf; - int rc; - ENTRY; - - if (S_ISLNK(*mode)) - RETURN(0); - - buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, - sizeof(mdd_env_info(env)->mti_xattr_buf)); - rc = mdo_xattr_get(env, pobj, buf, XATTR_NAME_ACL_DEFAULT, BYPASS_CAPA); - if ((rc == -EOPNOTSUPP) || (rc == -ENODATA)) - RETURN(0); - else if (rc <= 0) - RETURN(rc); + /* part of ACL went into i_mode */ + if (*mode != old) { + struct mdd_thread_info *info = mdd_env_info(env); + struct lu_attr *pattr = &info->mti_pattr; + + /* mode was initialized within object creation, + * so we need explict ->attr_set() to update it */ + pattr->la_valid = LA_MODE; + pattr->la_mode = *mode; + rc2 = mdo_attr_set(env, obj, pattr, handle, BYPASS_CAPA); + if (rc2 < 0) + rc = rc2; + } - buf->lb_len = rc; - rc = __mdd_acl_init(env, cobj, buf, mode, handle); - RETURN(rc); + if (rc > 0) + rc = mdo_xattr_set(env, obj, buf, XATTR_NAME_ACL_ACCESS, 0, + handle, BYPASS_CAPA); + RETURN(rc); } #endif @@ -184,7 +233,7 @@ static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, struct lu_attr *la, int mask) { #ifdef CONFIG_FS_POSIX_ACL - struct md_ucred *uc = md_ucred(env); + struct lu_ucred *uc = lu_ucred_assert(env); posix_acl_xattr_header *head; posix_acl_xattr_entry *entry; struct lu_buf *buf; @@ -192,7 +241,7 @@ static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, int rc; ENTRY; - buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, + buf = mdd_buf_get(env, mdd_env_info(env)->mti_xattr_buf, sizeof(mdd_env_info(env)->mti_xattr_buf)); rc = mdo_xattr_get(env, obj, buf, XATTR_NAME_ACL_ACCESS, mdd_object_capa(env, obj)); @@ -214,9 +263,9 @@ static int mdd_check_acl(const struct lu_env *env, struct mdd_object *obj, } int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, - struct lu_attr *la, int mask, int needlock) + struct lu_attr *la, int mask, int role) { - struct md_ucred *uc = md_ucred(env); + struct lu_ucred *uc = lu_ucred(env); __u32 mode; int rc; ENTRY; @@ -224,13 +273,13 @@ int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, if (mask == 0) RETURN(0); - /* These means unnecessary for permission check */ - if ((uc == NULL) || (uc->mu_valid == UCRED_INIT)) - RETURN(0); + /* These means unnecessary for permission check */ + if ((uc == NULL) || (uc->uc_valid == UCRED_INIT)) + RETURN(0); - /* Invalid user credit */ - if (uc->mu_valid == UCRED_INVALID) - RETURN(-EACCES); + /* Invalid user credit */ + if (uc->uc_valid == UCRED_INVALID) + RETURN(-EACCES); /* * Nobody gets write access to an immutable file. @@ -246,14 +295,14 @@ int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, } mode = la->la_mode; - if (uc->mu_fsuid == la->la_uid) { - mode >>= 6; + if (uc->uc_fsuid == la->la_uid) { + mode >>= 6; } else { if (mode & S_IRWXG) { - if (needlock) - mdd_read_lock(env, obj); + if (role != -1) + mdd_read_lock(env, obj, role); rc = mdd_check_acl(env, obj, la, mask); - if (needlock) + if (role != -1) mdd_read_unlock(env, obj); if (rc == -EACCES) goto check_capabilities; @@ -271,24 +320,24 @@ int __mdd_permission_internal(const struct lu_env *env, struct mdd_object *obj, check_capabilities: if (!(mask & MAY_EXEC) || (la->la_mode & S_IXUGO) || S_ISDIR(la->la_mode)) - if (mdd_capable(uc, CAP_DAC_OVERRIDE)) + if (mdd_capable(uc, CFS_CAP_DAC_OVERRIDE)) RETURN(0); if ((mask == MAY_READ) || (S_ISDIR(la->la_mode) && !(mask & MAY_WRITE))) - if (mdd_capable(uc, CAP_DAC_READ_SEARCH)) + if (mdd_capable(uc, CFS_CAP_DAC_READ_SEARCH)) RETURN(0); RETURN(-EACCES); } -int mdd_permission(const struct lu_env *env, +int mdd_permission(const struct lu_env *env, struct md_object *pobj, struct md_object *cobj, struct md_attr *ma, int mask) { struct mdd_object *mdd_pobj, *mdd_cobj; - struct md_ucred *uc = NULL; - struct lu_attr *la = NULL; + struct lu_ucred *uc = NULL; + struct lu_attr *la = &mdd_env_info(env)->mti_cattr; int check_create, check_link; int check_unlink; int check_rename_src, check_rename_tar; @@ -300,17 +349,15 @@ int mdd_permission(const struct lu_env *env, LASSERT(cobj); mdd_cobj = md2mdd_obj(cobj); + rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); + if (rc) + RETURN(rc); + /* For cross_open case, the "mask" is open flags, * so convert it to permission mask first. * XXX: MDS_OPEN_CROSS must be NOT equal to permission mask MAY_*. */ - if (unlikely(mask & MDS_OPEN_CROSS)) { - la = &mdd_env_info(env)->mti_la; - rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - - mask = accmode(env, la, mask & ~MDS_OPEN_CROSS); - } + if (unlikely(mask & MDS_OPEN_CROSS)) + mask = accmode(env, la, mask & ~MDS_OPEN_CROSS); check_create = mask & MAY_CREATE; check_link = mask & MAY_LINK; @@ -327,27 +374,24 @@ int mdd_permission(const struct lu_env *env, MAY_VTX_PART | MAY_VTX_FULL | MAY_RGETFACL); - rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask); + rc = mdd_permission_internal_locked(env, mdd_cobj, NULL, mask, + MOR_TGT_CHILD); if (!rc && (check_create || check_link)) rc = mdd_may_create(env, mdd_cobj, NULL, 1, check_link); - if (!rc && check_unlink) { - LASSERT(ma); - rc = mdd_may_unlink(env, mdd_cobj, ma); - } + if (!rc && check_unlink) + rc = mdd_may_unlink(env, mdd_cobj, la); if (!rc && (check_rename_src || check_rename_tar)) { LASSERT(pobj); - LASSERT(ma); mdd_pobj = md2mdd_obj(pobj); - rc = mdd_may_delete(env, mdd_pobj, mdd_cobj, ma, 1, + rc = mdd_may_delete(env, mdd_pobj, mdd_cobj, la, NULL, 1, check_rename_tar); } if (!rc && (check_vtx_part || check_vtx_full)) { - uc = md_ucred(env); - LASSERT(ma); + uc = lu_ucred_assert(env); if (likely(!la)) { la = &mdd_env_info(env)->mti_la; rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); @@ -355,10 +399,10 @@ int mdd_permission(const struct lu_env *env, RETURN(rc); } - if (!(la->la_mode & S_ISVTX) || (la->la_uid == uc->mu_fsuid) || - (check_vtx_full && (ma->ma_attr.la_valid & LA_UID) && - (ma->ma_attr.la_uid == uc->mu_fsuid))) { - ma->ma_attr_flags |= MDS_VTX_BYPASS; + if (!(la->la_mode & S_ISVTX) || (la->la_uid == uc->uc_fsuid) || + (check_vtx_full && (ma->ma_attr.la_valid & LA_UID) && + (ma->ma_attr.la_uid == uc->uc_fsuid))) { + ma->ma_attr_flags |= MDS_VTX_BYPASS; } else { ma->ma_attr_flags &= ~MDS_VTX_BYPASS; if (check_vtx_full) @@ -368,17 +412,11 @@ int mdd_permission(const struct lu_env *env, if (unlikely(!rc && check_rgetfacl)) { if (likely(!uc)) - uc = md_ucred(env); - - if (likely(!la)) { - la = &mdd_env_info(env)->mti_la; - rc = mdd_la_get(env, mdd_cobj, la, BYPASS_CAPA); - if (rc) - RETURN(rc); - } + uc = lu_ucred_assert(env); - if (la->la_uid != uc->mu_fsuid && !mdd_capable(uc, CAP_FOWNER)) - rc = -EPERM; + if (la->la_uid != uc->uc_fsuid && + !mdd_capable(uc, CFS_CAP_FOWNER)) + rc = -EPERM; } RETURN(rc); @@ -396,7 +434,7 @@ int mdd_capa_get(const struct lu_env *env, struct md_object *obj, capa->lc_opc); if (IS_ERR(oc)) { rc = PTR_ERR(oc); - } else { + } else if (likely(oc != NULL)) { capa_cpy(capa, oc); capa_put(oc); }