X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fmdt%2Fmdt_lib.c;h=d6dacde27f1dae9459aaf66f94052678c250902a;hb=49fd10ec8a2a85bbc56618d70f2f71d323d90a4c;hp=9fe52e2774ca613e6fe8d3f32001809d00f80258;hpb=b3fa6d5458e8ae1e4b695e03097c638db2738a38;p=fs%2Flustre-release.git diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index 9fe52e2..d6dacde 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -1,45 +1,60 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: +/* + * GPL HEADER START * - * lustre/mdt/mdt_lib.c - * Lustre Metadata Target (mdt) request unpacking helper. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright (c) 2006 Cluster File Systems, Inc. - * Author: Peter Braam - * Author: Andreas Dilger - * Author: Phil Schwan - * Author: Mike Shaver - * Author: Nikita Danilov - * Author: Huang Hua + * 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. * + * 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). * - * This file is part of the Lustre file system, http://www.lustre.org - * Lustre is a trademark of Cluster File Systems, Inc. + * 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 * - * 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. + * 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. * - * 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. + * GPL HEADER END + */ +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. * - * 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. + * Copyright (c) 2011, 2015, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lustre/mdt/mdt_lib.c + * + * Lustre Metadata Target (mdt) request unpacking helper. + * + * Author: Peter Braam + * Author: Andreas Dilger + * Author: Phil Schwan + * Author: Mike Shaver + * Author: Nikita Danilov + * Author: Huang Hua + * Author: Fan Yong */ - -#ifndef EXPORT_SYMTAB -# define EXPORT_SYMTAB -#endif #define DEBUG_SUBSYSTEM S_MDS +#include +#ifdef HAVE_UIDGID_HEADER +# include +#endif #include "mdt_internal.h" - +#include +#include typedef enum ucred_init_type { NONE_INIT = 0, @@ -47,276 +62,332 @@ typedef enum ucred_init_type { REC_INIT = 2 } ucred_init_type_t; -int groups_from_list(struct group_info *ginfo, gid_t *glist) +void mdt_exit_ucred(struct mdt_thread_info *info) { - int i; - int count = ginfo->ngroups; - - /* fill group_info from gid array */ - for (i = 0; i < ginfo->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*glist); - - if (memcpy(ginfo->blocks[i], glist + off, len)) - return -EFAULT; + struct lu_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + + LASSERT(uc != NULL); + if (uc->uc_valid != UCRED_INIT) { + uc->uc_suppgids[0] = uc->uc_suppgids[1] = -1; + if (uc->uc_ginfo) { + put_group_info(uc->uc_ginfo); + uc->uc_ginfo = NULL; + } + if (uc->uc_identity) { + mdt_identity_put(mdt->mdt_identity_cache, + uc->uc_identity); + uc->uc_identity = NULL; + } + uc->uc_valid = UCRED_INIT; + } +} - count -= cp_count; - } - return 0; +static int match_nosquash_list(struct rw_semaphore *sem, + struct list_head *nidlist, + lnet_nid_t peernid) +{ + int rc; + ENTRY; + down_read(sem); + rc = cfs_match_nid(peernid, nidlist); + up_read(sem); + RETURN(rc); } -/* groups_sort() is copied from linux kernel! */ -/* a simple shell-metzner sort */ -void groups_sort(struct group_info *group_info) +/* root_squash for inter-MDS operations */ +static int mdt_root_squash(struct mdt_thread_info *info, lnet_nid_t peernid) { - int base, max, stride; - int gidsetsize = group_info->ngroups; - - for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) - ; /* nothing */ - stride /= 3; - - while (stride) { - max = gidsetsize - stride; - for (base = 0; base < max; base++) { - int left = base; - int right = left + stride; - gid_t tmp = GROUP_AT(group_info, right); - - while (left >= 0 && GROUP_AT(group_info, left) > tmp) { - GROUP_AT(group_info, right) = - GROUP_AT(group_info, left); - right = left; - left -= stride; - } - GROUP_AT(group_info, right) = tmp; - } - stride /= 3; - } + struct lu_ucred *ucred = mdt_ucred(info); + struct root_squash_info *squash = &info->mti_mdt->mdt_squash; + ENTRY; + + LASSERT(ucred != NULL); + if (!squash->rsi_uid || ucred->uc_fsuid) + RETURN(0); + + if (match_nosquash_list(&squash->rsi_sem, + &squash->rsi_nosquash_nids, + peernid)) { + CDEBUG(D_OTHER, "%s is in nosquash_nids list\n", + libcfs_nid2str(peernid)); + RETURN(0); + } + + CDEBUG(D_OTHER, "squash req from %s, (%d:%d/%x)=>(%d:%d/%x)\n", + libcfs_nid2str(peernid), + ucred->uc_fsuid, ucred->uc_fsgid, ucred->uc_cap, + squash->rsi_uid, squash->rsi_gid, 0); + + ucred->uc_fsuid = squash->rsi_uid; + ucred->uc_fsgid = squash->rsi_gid; + ucred->uc_cap = 0; + ucred->uc_suppgids[0] = -1; + ucred->uc_suppgids[1] = -1; + + RETURN(0); } -void mdt_exit_ucred(struct mdt_thread_info *info) +static void ucred_set_jobid(struct mdt_thread_info *info, struct lu_ucred *uc) { - struct md_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - - if (uc->mu_valid != UCRED_INIT) { - uc->mu_suppgids[0] = uc->mu_suppgids[1] = -1; - if (uc->mu_ginfo) { - groups_free(uc->mu_ginfo); - uc->mu_ginfo = NULL; - } - if (uc->mu_identity) { - mdt_identity_put(mdt->mdt_identity_cache, - uc->mu_identity); - uc->mu_identity = NULL; - } - uc->mu_valid = UCRED_INIT; - } + struct ptlrpc_request *req = mdt_info_req(info); + const char *jobid = mdt_req_get_jobid(req); + + /* set jobid if specified. */ + if (jobid) + strlcpy(uc->uc_jobid, jobid, sizeof(uc->uc_jobid)); + else + uc->uc_jobid[0] = '\0'; } -static int old_init_ucred(struct mdt_thread_info *info, - struct mdt_body *body) +static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, + void *buf, bool drop_fs_cap) { - struct md_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct mdt_identity *identity = NULL; + struct ptlrpc_request *req = mdt_info_req(info); + struct mdt_device *mdt = info->mti_mdt; + struct ptlrpc_user_desc *pud = req->rq_user_desc; + struct lu_ucred *ucred = mdt_ucred(info); + lnet_nid_t peernid = req->rq_peer.nid; + __u32 perm = 0; + __u32 remote = exp_connect_rmtclient(info->mti_exp); + int setuid; + int setgid; + int rc = 0; ENTRY; - uc->mu_valid = UCRED_INVALID; + LASSERT(req->rq_auth_gss); + LASSERT(!req->rq_auth_usr_mdt); + LASSERT(req->rq_user_desc); + LASSERT(ucred != NULL); - if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { - /* get identity info of this user */ - identity = mdt_identity_get(mdt->mdt_identity_cache, - body->fsuid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", - body->fsuid); - RETURN(-EACCES); - } - } + ucred->uc_valid = UCRED_INVALID; - uc->mu_valid = UCRED_OLD; - uc->mu_squash = SQUASH_NONE; - uc->mu_o_uid = uc->mu_uid = body->uid; - uc->mu_o_gid = uc->mu_gid = body->gid; - uc->mu_o_fsuid = uc->mu_fsuid = body->fsuid; - uc->mu_o_fsgid = uc->mu_fsgid = body->fsgid; - uc->mu_suppgids[0] = body->suppgid; - uc->mu_suppgids[1] = -1; - if (uc->mu_fsuid) - uc->mu_cap = body->capability & ~CAP_FS_MASK; - else - uc->mu_cap = body->capability; - uc->mu_ginfo = NULL; - uc->mu_identity = identity; + ucred->uc_o_uid = pud->pud_uid; + ucred->uc_o_gid = pud->pud_gid; + ucred->uc_o_fsuid = pud->pud_fsuid; + ucred->uc_o_fsgid = pud->pud_fsgid; - RETURN(0); -} + if (type == BODY_INIT) { + struct mdt_body *body = (struct mdt_body *)buf; -static int old_init_ucred_reint(struct mdt_thread_info *info) -{ - struct md_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct mdt_identity *identity = NULL; + ucred->uc_suppgids[0] = body->mbo_suppgid; + ucred->uc_suppgids[1] = -1; + } - ENTRY; + /* sanity check: we expect the uid which client claimed is true */ + if (remote) { + if (!uid_valid(make_kuid(&init_user_ns, req->rq_auth_mapped_uid))) { + CDEBUG(D_SEC, "remote user not mapped, deny access!\n"); + RETURN(-EACCES); + } - uc->mu_valid = UCRED_INVALID; + if (ptlrpc_user_desc_do_idmap(req, pud)) + RETURN(-EACCES); - if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { - /* get identity info of this user */ - identity = mdt_identity_get(mdt->mdt_identity_cache, - uc->mu_fsuid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", - uc->mu_fsuid); + if (req->rq_auth_mapped_uid != pud->pud_uid) { + CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u " + "while client claims %u:%u/%u:%u\n", + libcfs_nid2str(peernid), req->rq_auth_uid, + req->rq_auth_mapped_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); + RETURN(-EACCES); + } + } else { + if (!flvr_is_rootonly(req->rq_flvr.sf_rpc) && + req->rq_auth_uid != pud->pud_uid) { + CDEBUG(D_SEC, "local client %s: auth uid %u " + "while client claims %u:%u/%u:%u\n", + libcfs_nid2str(peernid), req->rq_auth_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); RETURN(-EACCES); } } - uc->mu_valid = UCRED_OLD; - uc->mu_squash = SQUASH_NONE; - uc->mu_o_uid = uc->mu_o_fsuid = uc->mu_uid = uc->mu_fsuid; - uc->mu_o_gid = uc->mu_o_fsgid = uc->mu_gid = uc->mu_fsgid; - if (uc->mu_fsuid) - uc->mu_cap &= ~CAP_FS_MASK; - uc->mu_ginfo = NULL; - uc->mu_identity = identity; - - RETURN(0); -} - -static int nid_nosquash(struct mdt_device *mdt, lnet_nid_t nid) -{ - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - int i; - - for (i = 0; i < rsi->rsi_n_nosquash_nids; i++) - if ((rsi->rsi_nosquash_nids[i] == nid) || - (rsi->rsi_nosquash_nids[i] == LNET_NID_ANY)) - return 1; - - return 0; -} - -static int mdt_squash_root(struct mdt_device *mdt, struct md_ucred *ucred, - struct ptlrpc_user_desc *pud, lnet_nid_t peernid) -{ - struct rootsquash_info *rsi = mdt->mdt_rootsquash_info; - - if (!rsi || (!rsi->rsi_uid && !rsi->rsi_gid) || - nid_nosquash(mdt, peernid)) - return 0; - - CDEBUG(D_SEC, "squash req from "LPX64":" - "(%u:%u-%u:%u/%x)=>(%u:%u-%u:%u/%x)\n", peernid, - pud->pud_uid, pud->pud_gid, - pud->pud_fsuid, pud->pud_fsgid, pud->pud_cap, - pud->pud_uid ? pud->pud_uid : rsi->rsi_uid, - pud->pud_uid ? pud->pud_gid : rsi->rsi_gid, - pud->pud_fsuid ? pud->pud_fsuid : rsi->rsi_uid, - pud->pud_fsuid ? pud->pud_fsgid : rsi->rsi_gid, - pud->pud_cap & ~CAP_FS_MASK); - - if (rsi->rsi_uid) { - if (!pud->pud_uid) { - ucred->mu_uid = rsi->rsi_uid; - ucred->mu_squash |= SQUASH_UID; + if (is_identity_get_disabled(mdt->mdt_identity_cache)) { + if (remote) { + CDEBUG(D_SEC, "remote client must run with identity_get " + "enabled!\n"); + RETURN(-EACCES); } else { - ucred->mu_uid = pud->pud_uid; + ucred->uc_identity = NULL; + perm = CFS_SETUID_PERM | CFS_SETGID_PERM | + CFS_SETGRP_PERM; } + } else { + struct md_identity *identity; - if (!pud->pud_fsuid) { - ucred->mu_fsuid = rsi->rsi_uid; - ucred->mu_squash |= SQUASH_UID; + identity = mdt_identity_get(mdt->mdt_identity_cache, + pud->pud_uid); + if (IS_ERR(identity)) { + if (unlikely(PTR_ERR(identity) == -EREMCHG && + !remote)) { + ucred->uc_identity = NULL; + perm = CFS_SETUID_PERM | CFS_SETGID_PERM | + CFS_SETGRP_PERM; + } else { + CDEBUG(D_SEC, "Deny access without identity: uid %u\n", + pud->pud_uid); + RETURN(-EACCES); + } } else { - ucred->mu_fsuid = pud->pud_fsuid; + ucred->uc_identity = identity; + perm = mdt_identity_get_perm(ucred->uc_identity, + remote, peernid); } - } else { - ucred->mu_uid = pud->pud_uid; - ucred->mu_fsuid = pud->pud_fsuid; } - if (rsi->rsi_gid) { - int i; + /* find out the setuid/setgid attempt */ + setuid = (pud->pud_uid != pud->pud_fsuid); + setgid = ((pud->pud_gid != pud->pud_fsgid) || + (ucred->uc_identity && + (pud->pud_gid != ucred->uc_identity->mi_gid))); - if (!pud->pud_gid) { - ucred->mu_gid = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } else { - ucred->mu_gid = pud->pud_gid; - } + /* check permission of setuid */ + if (setuid && !(perm & CFS_SETUID_PERM)) { + CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n", + pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid)); + GOTO(out, rc = -EACCES); + } - if (!pud->pud_fsgid) { - ucred->mu_fsgid = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } else { - ucred->mu_fsgid = pud->pud_fsgid; - } + /* check permission of setgid */ + if (setgid && !(perm & CFS_SETGID_PERM)) { + CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) " + "from %s\n", pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid, + ucred->uc_identity->mi_gid, libcfs_nid2str(peernid)); + GOTO(out, rc = -EACCES); + } - for (i = 0; i < 2; i++) { - if (!ucred->mu_suppgids[i]) { - ucred->mu_suppgids[i] = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } - } + /* + * NB: remote client not allowed to setgroups anyway. + */ + if (!remote && perm & CFS_SETGRP_PERM) { + if (pud->pud_ngroups) { + /* setgroups for local client */ + ucred->uc_ginfo = groups_alloc(pud->pud_ngroups); + if (!ucred->uc_ginfo) { + CERROR("failed to alloc %d groups\n", + pud->pud_ngroups); + GOTO(out, rc = -ENOMEM); + } + + lustre_groups_from_list(ucred->uc_ginfo, + pud->pud_groups); + lustre_groups_sort(ucred->uc_ginfo); + } else { + ucred->uc_ginfo = NULL; + } + } else { + ucred->uc_suppgids[0] = -1; + ucred->uc_suppgids[1] = -1; + ucred->uc_ginfo = NULL; + } + + ucred->uc_uid = pud->pud_uid; + ucred->uc_gid = pud->pud_gid; + ucred->uc_fsuid = pud->pud_fsuid; + ucred->uc_fsgid = pud->pud_fsgid; + + /* process root_squash here. */ + mdt_root_squash(info, peernid); + + /* remove fs privilege for non-root user. */ + if (ucred->uc_fsuid && drop_fs_cap) + ucred->uc_cap = pud->pud_cap & ~CFS_CAP_FS_MASK; + else + ucred->uc_cap = pud->pud_cap; + if (remote && !(perm & CFS_RMTOWN_PERM)) + ucred->uc_cap &= ~(CFS_CAP_SYS_RESOURCE_MASK | + CFS_CAP_CHOWN_MASK); + ucred->uc_valid = UCRED_NEW; + ucred_set_jobid(info, ucred); + + EXIT; - for (i = 0; i < pud->pud_ngroups; i++) { - if (!pud->pud_groups[i]) { - pud->pud_groups[i] = rsi->rsi_gid; - ucred->mu_squash |= SQUASH_GID; - } - } - } else { - ucred->mu_gid = pud->pud_gid; - ucred->mu_fsgid = pud->pud_fsgid; - } +out: + if (rc) { + if (ucred->uc_ginfo) { + put_group_info(ucred->uc_ginfo); + ucred->uc_ginfo = NULL; + } + if (ucred->uc_identity) { + mdt_identity_put(mdt->mdt_identity_cache, + ucred->uc_identity); + ucred->uc_identity = NULL; + } + } + + return rc; +} - return 1; +/** + * Check whether allow the client to set supplementary group IDs or not. + * + * \param[in] info pointer to the thread context + * \param[in] uc pointer to the RPC user descriptor + * + * \retval true if allow to set supplementary group IDs + * \retval false for other cases + */ +bool allow_client_chgrp(struct mdt_thread_info *info, struct lu_ucred *uc) +{ + __u32 remote = exp_connect_rmtclient(info->mti_exp); + __u32 perm; + + /* 1. If identity_upcall is disabled, then forbid remote client to set + * supplementary group IDs, but permit local client to do that. */ + if (is_identity_get_disabled(info->mti_mdt->mdt_identity_cache)) { + if (remote) + return false; + + return true; + } + + /* 2. If fail to get related identities, then forbid any client to + * set supplementary group IDs. */ + if (uc->uc_identity == NULL) + return false; + + /* 3. Check the permission in the identities. */ + perm = mdt_identity_get_perm(uc->uc_identity, remote, + mdt_info_req(info)->rq_peer.nid); + if (perm & CFS_SETGRP_PERM) + return true; + + return false; } -static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, - void *buf) +int mdt_check_ucred(struct mdt_thread_info *info) { struct ptlrpc_request *req = mdt_info_req(info); - struct mdt_export_data *med = mdt_req2med(req); struct mdt_device *mdt = info->mti_mdt; struct ptlrpc_user_desc *pud = req->rq_user_desc; - struct md_ucred *ucred = mdt_ucred(info); - struct mdt_identity *identity = NULL; - lnet_nid_t peernid = req->rq_peer.nid; - __u32 setxid_perm = 0; - int setuid; - int setgid; - int rc = 0; + struct lu_ucred *ucred = mdt_ucred(info); + struct md_identity *identity = NULL; + lnet_nid_t peernid = req->rq_peer.nid; + __u32 perm = 0; + __u32 remote = exp_connect_rmtclient(info->mti_exp); + int setuid; + int setgid; + int rc = 0; ENTRY; - LASSERT(req->rq_auth_gss); - LASSERT(!req->rq_auth_usr_mdt); - LASSERT(req->rq_user_desc); - - ucred->mu_valid = UCRED_INVALID; - - ucred->mu_o_uid = pud->pud_uid; - ucred->mu_o_gid = pud->pud_gid; - ucred->mu_o_fsuid = pud->pud_fsuid; - ucred->mu_o_fsgid = pud->pud_fsgid; + LASSERT(ucred != NULL); + if ((ucred->uc_valid == UCRED_OLD) || (ucred->uc_valid == UCRED_NEW)) + RETURN(0); - if (type == BODY_INIT) { - struct mdt_body *body = (struct mdt_body *)buf; - - ucred->mu_suppgids[0] = body->suppgid; - ucred->mu_suppgids[1] = -1; - } + if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) + RETURN(0); - /* sanity check: we expect the uid which client claimed is true */ - if (med->med_rmtclient) { - if (req->rq_auth_mapped_uid == INVALID_UID) { - CWARN("remote user not mapped, deny access!\n"); + /* sanity check: if we use strong authentication, we expect the + * uid which client claimed is true */ + if (remote) { + if (!uid_valid(make_kuid(&init_user_ns, req->rq_auth_mapped_uid))) { + CDEBUG(D_SEC, "remote user not mapped, deny access!\n"); RETURN(-EACCES); } @@ -324,261 +395,327 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type, RETURN(-EACCES); if (req->rq_auth_mapped_uid != pud->pud_uid) { - CERROR("remote client "LPU64": auth uid %u " - "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid); + CDEBUG(D_SEC, "remote client %s: auth/mapped uid %u/%u " + "while client claims %u:%u/%u:%u\n", + libcfs_nid2str(peernid), req->rq_auth_uid, + req->rq_auth_mapped_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); RETURN(-EACCES); } } else { - if (req->rq_auth_uid != pud->pud_uid) { - CERROR("local client "LPU64": auth uid %u " - "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, pud->pud_fsgid); + if (!flvr_is_rootonly(req->rq_flvr.sf_rpc) && + req->rq_auth_uid != pud->pud_uid) { + CDEBUG(D_SEC, "local client %s: auth uid %u " + "while client claims %u:%u/%u:%u\n", + libcfs_nid2str(peernid), req->rq_auth_uid, + pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid); RETURN(-EACCES); } } if (is_identity_get_disabled(mdt->mdt_identity_cache)) { - if (med->med_rmtclient) { - CERROR("remote client must run with identity_get " + if (remote) { + CDEBUG(D_SEC, "remote client must run with identity_get " "enabled!\n"); RETURN(-EACCES); - } else { - setxid_perm |= LUSTRE_SETGRP_PERM; - goto check_squash; } + RETURN(0); } identity = mdt_identity_get(mdt->mdt_identity_cache, pud->pud_uid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", pud->pud_uid); - RETURN(-EACCES); + if (IS_ERR(identity)) { + if (unlikely(PTR_ERR(identity) == -EREMCHG && + !remote)) { + RETURN(0); + } else { + CDEBUG(D_SEC, "Deny access without identity: uid %u\n", + pud->pud_uid); + RETURN(-EACCES); + } } - setxid_perm = mdt_identity_get_setxid_perm(identity, - med->med_rmtclient, - peernid); - + perm = mdt_identity_get_perm(identity, remote, peernid); /* find out the setuid/setgid attempt */ setuid = (pud->pud_uid != pud->pud_fsuid); setgid = (pud->pud_gid != pud->pud_fsgid || pud->pud_gid != identity->mi_gid); /* check permission of setuid */ - if (setuid && !(setxid_perm & LUSTRE_SETUID_PERM)) { - CWARN("mdt blocked setuid attempt (%u -> %u) from " - LPX64"\n", pud->pud_uid, pud->pud_fsuid, peernid); + if (setuid && !(perm & CFS_SETUID_PERM)) { + CDEBUG(D_SEC, "mdt blocked setuid attempt (%u -> %u) from %s\n", + pud->pud_uid, pud->pud_fsuid, libcfs_nid2str(peernid)); GOTO(out, rc = -EACCES); } /* check permission of setgid */ - if (setgid && !(setxid_perm & LUSTRE_SETGID_PERM)) { - CWARN("mdt blocked setgid attempt (%u:%u/%u:%u -> %u) " - "from "LPX64"\n", pud->pud_uid, pud->pud_gid, - pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid, - peernid); + if (setgid && !(perm & CFS_SETGID_PERM)) { + CDEBUG(D_SEC, "mdt blocked setgid attempt (%u:%u/%u:%u -> %u) " + "from %s\n", pud->pud_uid, pud->pud_gid, + pud->pud_fsuid, pud->pud_fsgid, identity->mi_gid, + libcfs_nid2str(peernid)); GOTO(out, rc = -EACCES); } -check_squash: - /* FIXME: The exact behavior of root_squash is not defined. */ - ucred->mu_squash = SQUASH_NONE; - if (mdt_squash_root(mdt, ucred, pud, peernid) == 0) { - ucred->mu_uid = pud->pud_uid; - ucred->mu_gid = pud->pud_gid; - ucred->mu_fsuid = pud->pud_fsuid; - ucred->mu_fsgid = pud->pud_fsgid; - } - - /* remove fs privilege for non-root user */ - if (ucred->mu_fsuid) - ucred->mu_cap = pud->pud_cap & ~CAP_FS_MASK; - else - ucred->mu_cap = pud->pud_cap; - - /* - * NB: remote client not allowed to setgroups anyway. - */ - if (!med->med_rmtclient && pud->pud_ngroups && - (setxid_perm & LUSTRE_SETGRP_PERM)) { - struct group_info *ginfo; - - /* setgroups for local client */ - ginfo = groups_alloc(pud->pud_ngroups); - if (!ginfo) { - CERROR("failed to alloc %d groups\n", - pud->pud_ngroups); - GOTO(out, rc = -ENOMEM); - } - groups_from_list(ginfo, pud->pud_groups); - groups_sort(ginfo); - ucred->mu_ginfo = ginfo; - } else { - ucred->mu_ginfo = NULL; - } - - ucred->mu_identity = identity; - ucred->mu_valid = UCRED_NEW; - EXIT; out: - if (rc && identity) - mdt_identity_put(mdt->mdt_identity_cache, identity); - + mdt_identity_put(mdt->mdt_identity_cache, identity); return rc; } -int mdt_check_ucred(struct mdt_thread_info *info) +static int old_init_ucred_common(struct mdt_thread_info *info, + struct lu_nodemap *nodemap, + bool drop_fs_cap) { - struct ptlrpc_request *req = mdt_info_req(info); - struct mdt_export_data *med = mdt_req2med(req); - struct mdt_device *mdt = info->mti_mdt; - struct ptlrpc_user_desc *pud = req->rq_user_desc; - struct md_ucred *ucred = mdt_ucred(info); - struct mdt_identity *identity; - lnet_nid_t peernid = req->rq_peer.nid; - - ENTRY; + struct lu_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + struct md_identity *identity = NULL; + + if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { + identity = mdt_identity_get(mdt->mdt_identity_cache, + uc->uc_fsuid); + if (IS_ERR(identity)) { + if (unlikely(PTR_ERR(identity) == -EREMCHG || + uc->uc_cap & CFS_CAP_FS_MASK)) { + identity = NULL; + } else { + CDEBUG(D_SEC, "Deny access without identity: " + "uid %u\n", uc->uc_fsuid); + RETURN(-EACCES); + } + } + } + uc->uc_identity = identity; + + if (nodemap && uc->uc_o_uid == nodemap->nm_squash_uid) { + uc->uc_fsuid = nodemap->nm_squash_uid; + uc->uc_fsgid = nodemap->nm_squash_gid; + uc->uc_cap = 0; + uc->uc_suppgids[0] = -1; + uc->uc_suppgids[1] = -1; + } + + /* process root_squash here. */ + mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid); + + /* remove fs privilege for non-root user. */ + if (uc->uc_fsuid && drop_fs_cap) + uc->uc_cap &= ~CFS_CAP_FS_MASK; + uc->uc_valid = UCRED_OLD; + ucred_set_jobid(info, uc); + + return 0; +} - if ((ucred->mu_valid == UCRED_OLD) || (ucred->mu_valid == UCRED_NEW)) - RETURN(0); +static int old_init_ucred(struct mdt_thread_info *info, + struct mdt_body *body, bool drop_fs_cap) +{ + struct lu_ucred *uc = mdt_ucred(info); + struct lu_nodemap *nodemap; + int rc; + ENTRY; + + nodemap = nodemap_get_from_exp(info->mti_exp); + if (IS_ERR(nodemap)) + RETURN(PTR_ERR(nodemap)); + + body->mbo_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, body->mbo_uid); + body->mbo_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, body->mbo_gid); + body->mbo_fsuid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, body->mbo_fsuid); + body->mbo_fsgid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, body->mbo_fsgid); + + LASSERT(uc != NULL); + uc->uc_valid = UCRED_INVALID; + uc->uc_o_uid = uc->uc_uid = body->mbo_uid; + uc->uc_o_gid = uc->uc_gid = body->mbo_gid; + uc->uc_o_fsuid = uc->uc_fsuid = body->mbo_fsuid; + uc->uc_o_fsgid = uc->uc_fsgid = body->mbo_fsgid; + uc->uc_suppgids[0] = body->mbo_suppgid; + uc->uc_suppgids[1] = -1; + uc->uc_ginfo = NULL; + uc->uc_cap = body->mbo_capability; + + rc = old_init_ucred_common(info, nodemap, drop_fs_cap); + nodemap_putref(nodemap); + + RETURN(rc); +} - if (!req->rq_user_desc) - RETURN(0); +static int old_init_ucred_reint(struct mdt_thread_info *info) +{ + struct lu_ucred *uc = mdt_ucred(info); + struct lu_nodemap *nodemap; + int rc; + ENTRY; - /* sanity check: if we use strong authentication, we expect the - * uid which client claimed is true */ - if (req->rq_auth_gss) { - if (med->med_rmtclient) { - if (req->rq_auth_mapped_uid == INVALID_UID) { - CWARN("remote user not mapped, deny access!\n"); - RETURN(-EACCES); - } + nodemap = nodemap_get_from_exp(info->mti_exp); + if (IS_ERR(nodemap)) + RETURN(PTR_ERR(nodemap)); - if (ptlrpc_user_desc_do_idmap(req, pud)) - RETURN(-EACCES); + LASSERT(uc != NULL); - if (req->rq_auth_mapped_uid != pud->pud_uid) { - CERROR("remote client "LPU64": auth uid %u " - "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, - pud->pud_fsgid); - RETURN(-EACCES); - } - } else { - if (req->rq_auth_uid != pud->pud_uid) { - CERROR("local client "LPU64": auth uid %u " - "while client claim %u:%u/%u:%u\n", - peernid, req->rq_auth_uid, pud->pud_uid, - pud->pud_gid, pud->pud_fsuid, - pud->pud_fsgid); - RETURN(-EACCES); - } - } - } + uc->uc_fsuid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, uc->uc_fsuid); + uc->uc_fsgid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, uc->uc_fsgid); - if (is_identity_get_disabled(mdt->mdt_identity_cache)) { - if (med->med_rmtclient) { - CERROR("remote client must run with " - "identity_get enabled!\n"); - RETURN(-EACCES); - } - } else { - identity = mdt_identity_get(mdt->mdt_identity_cache, - pud->pud_uid); - if (!identity) { - CERROR("Deny access without identity: uid %d\n", - pud->pud_uid); - RETURN(-EACCES); - } + uc->uc_valid = UCRED_INVALID; + uc->uc_o_uid = uc->uc_o_fsuid = uc->uc_uid = uc->uc_fsuid; + uc->uc_o_gid = uc->uc_o_fsgid = uc->uc_gid = uc->uc_fsgid; + uc->uc_ginfo = NULL; - mdt_identity_put(mdt->mdt_identity_cache, identity); - } + rc = old_init_ucred_common(info, nodemap, true); /* drop_fs_cap=true */ + nodemap_putref(nodemap); - RETURN(0); + RETURN(rc); } -int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body) +static inline int __mdt_init_ucred(struct mdt_thread_info *info, + struct mdt_body *body, + bool drop_fs_cap) { - struct ptlrpc_request *req = mdt_info_req(info); - struct md_ucred *uc = mdt_ucred(info); + struct ptlrpc_request *req = mdt_info_req(info); + struct lu_ucred *uc = mdt_ucred(info); - if ((uc->mu_valid == UCRED_OLD) || (uc->mu_valid == UCRED_NEW)) - return 0; + LASSERT(uc != NULL); + if ((uc->uc_valid == UCRED_OLD) || (uc->uc_valid == UCRED_NEW)) + return 0; - mdt_exit_ucred(info); + mdt_exit_ucred(info); - if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) - return old_init_ucred(info, body); - else - return new_init_ucred(info, BODY_INIT, body); + if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) + return old_init_ucred(info, body, drop_fs_cap); + else + return new_init_ucred(info, BODY_INIT, body, drop_fs_cap); +} + +int mdt_init_ucred(struct mdt_thread_info *info, struct mdt_body *body) +{ + return __mdt_init_ucred(info, body, true); +} + +/* LU-6528 when "no_subtree_check" is set for NFS export, nfsd_set_fh_dentry() + * doesn't set correct fsuid explicitely, but raise capability to allow + * exportfs_decode_fh() to reconnect disconnected dentry into dcache. So for + * lookup (i.e. intent_getattr), we should keep FS capability, otherwise it + * will fail permission check. */ +int mdt_init_ucred_intent_getattr(struct mdt_thread_info *info, + struct mdt_body *body) +{ + return __mdt_init_ucred(info, body, false); } int mdt_init_ucred_reint(struct mdt_thread_info *info) { - struct ptlrpc_request *req = mdt_info_req(info); - struct md_ucred *uc = mdt_ucred(info); + struct ptlrpc_request *req = mdt_info_req(info); + struct lu_ucred *uc = mdt_ucred(info); - if ((uc->mu_valid == UCRED_OLD) || (uc->mu_valid == UCRED_NEW)) - return 0; + LASSERT(uc != NULL); + if ((uc->uc_valid == UCRED_OLD) || (uc->uc_valid == UCRED_NEW)) + return 0; - mdt_exit_ucred(info); + mdt_exit_ucred(info); - if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) - return old_init_ucred_reint(info); - else - return new_init_ucred(info, REC_INIT, NULL); + if (!req->rq_auth_gss || req->rq_auth_usr_mdt || !req->rq_user_desc) + return old_init_ucred_reint(info); + else + return new_init_ucred(info, REC_INIT, NULL, true); } /* copied from lov/lov_ea.c, just for debugging, will be removed later */ -void mdt_dump_lmm(int level, const struct lov_mds_md *lmm) +void mdt_dump_lmm(int level, const struct lov_mds_md *lmm, __u64 valid) { - const struct lov_ost_data_v1 *lod; - int i; - __s16 stripe_count = - le16_to_cpu(((struct lov_user_md*)lmm)->lmm_stripe_count); - - CDEBUG(level, "objid "LPX64", magic 0x%08X, pattern %#X\n", - le64_to_cpu(lmm->lmm_object_id), le32_to_cpu(lmm->lmm_magic), - le32_to_cpu(lmm->lmm_pattern)); - CDEBUG(level,"stripe_size=0x%x, stripe_count=0x%x\n", - le32_to_cpu(lmm->lmm_stripe_size), - le32_to_cpu(lmm->lmm_stripe_count)); - LASSERT(stripe_count <= (__s16)LOV_MAX_STRIPE_COUNT); - for (i = 0, lod = lmm->lmm_objects; i < stripe_count; i++, lod++) { - CDEBUG(level, "stripe %u idx %u subobj "LPX64"/"LPX64"\n", - i, le32_to_cpu(lod->l_ost_idx), - le64_to_cpu(lod->l_object_gr), - le64_to_cpu(lod->l_object_id)); - } + const struct lov_ost_data_v1 *lod; + int i; + __u16 count; + + if (likely(!cfs_cdebug_show(level, DEBUG_SUBSYSTEM))) + return; + + count = le16_to_cpu(((struct lov_user_md *)lmm)->lmm_stripe_count); + + CDEBUG(level, "objid "DOSTID", magic 0x%08X, pattern %#X\n", + POSTID(&lmm->lmm_oi), le32_to_cpu(lmm->lmm_magic), + le32_to_cpu(lmm->lmm_pattern)); + CDEBUG(level, "stripe_size=0x%x, stripe_count=0x%x\n", + le32_to_cpu(lmm->lmm_stripe_size), count); + + /* If it's a directory or a released file, then there are + * no actual objects to print, so bail out. */ + if (valid & OBD_MD_FLDIREA || + le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED) + return; + + LASSERT(count <= LOV_MAX_STRIPE_COUNT); + for (i = 0, lod = lmm->lmm_objects; i < count; i++, lod++) { + struct ost_id oi; + + ostid_le_to_cpu(&lod->l_ost_oi, &oi); + CDEBUG(level, "stripe %u idx %u subobj "DOSTID"\n", + i, le32_to_cpu(lod->l_ost_idx), POSTID(&oi)); + } } -void mdt_shrink_reply(struct mdt_thread_info *info) +void mdt_dump_lmv(unsigned int level, const union lmv_mds_md *lmv) { - struct req_capsule *pill = &info->mti_pill; - struct mdt_body *body; - int acl_size, md_size, adjust = 0; + const struct lmv_mds_md_v1 *lmm1; + int i; + + if (likely(!cfs_cdebug_show(level, DEBUG_SUBSYSTEM))) + return; + + lmm1 = &lmv->lmv_md_v1; + CDEBUG(level, "magic 0x%08X, master %#X stripe_count %#x\n", + le32_to_cpu(lmm1->lmv_magic), + le32_to_cpu(lmm1->lmv_master_mdt_index), + le32_to_cpu(lmm1->lmv_stripe_count)); + + if (le32_to_cpu(lmm1->lmv_magic) == LMV_MAGIC_STRIPE) + return; + + for (i = 0; i < le32_to_cpu(lmm1->lmv_stripe_count); i++) { + struct lu_fid fid; + + fid_le_to_cpu(&fid, &lmm1->lmv_stripe_fids[i]); + CDEBUG(level, "idx %u subobj "DFID"\n", i, PFID(&fid)); + } +} + +/* Shrink and/or grow reply buffers */ +int mdt_fix_reply(struct mdt_thread_info *info) +{ + struct req_capsule *pill = info->mti_pill; + struct mdt_body *body; + int md_size, md_packed = 0; + int acl_size; + int rc = 0; ENTRY; body = req_capsule_server_get(pill, &RMF_MDT_BODY); LASSERT(body != NULL); - if (body->valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE | OBD_MD_LINKNAME)) - md_size = body->eadatasize; - else - md_size = 0; + if (body->mbo_valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE | + OBD_MD_LINKNAME)) + md_size = body->mbo_eadatasize; + else + md_size = 0; - acl_size = body->aclsize; + acl_size = body->mbo_aclsize; - CDEBUG(D_INFO, "Shrink to md_size = %d cookie/acl_size = %d" - " MDSCAPA = %d, OSSCAPA = %d\n", - md_size, acl_size, - (int)(body->valid & OBD_MD_FLMDSCAPA), - (int)(body->valid & OBD_MD_FLOSSCAPA)); + /* this replay - not send info to client */ + if (info->mti_spec.no_create) { + md_size = 0; + acl_size = 0; + } + + CDEBUG(D_INFO, "Shrink to md_size = %d cookie/acl_size = %d\n", + md_size, acl_size); /* &RMF_MDT_BODY, &RMF_MDT_MD, @@ -587,39 +724,87 @@ void mdt_shrink_reply(struct mdt_thread_info *info) (optional) &RMF_CAPA2, (optional) something else */ - adjust += req_capsule_shrink(pill, &RMF_MDT_MD, - md_size, adjust, 1); + + /* MDT_MD buffer may be bigger than packed value, let's shrink all + * buffers before growing it */ + if (info->mti_big_lmm_used) { + /* big_lmm buffer may be used even without packing the result + * into reply, just for internal server needs */ + if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) + md_packed = req_capsule_get_size(pill, &RMF_MDT_MD, + RCL_SERVER); + + /* free big lmm if md_size is not needed */ + if (md_size == 0 || md_packed == 0) { + info->mti_big_lmm_used = 0; + } else { + /* buffer must be allocated separately */ + LASSERT(info->mti_attr.ma_lmm != + req_capsule_server_get(pill, &RMF_MDT_MD)); + req_capsule_shrink(pill, &RMF_MDT_MD, 0, RCL_SERVER); + } + } else if (req_capsule_has_field(pill, &RMF_MDT_MD, RCL_SERVER)) { + req_capsule_shrink(pill, &RMF_MDT_MD, md_size, RCL_SERVER); + } if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER)) - adjust += req_capsule_shrink(pill, &RMF_ACL, - acl_size, adjust, 1); + req_capsule_shrink(pill, &RMF_ACL, acl_size, RCL_SERVER); else if (req_capsule_has_field(pill, &RMF_LOGCOOKIES, RCL_SERVER)) - adjust += req_capsule_shrink(pill, &RMF_LOGCOOKIES, - acl_size, adjust, 1); - - /* RMF_CAPA1 on server-side maybe for OBD_MD_FLMDSCAPA or - * OBD_MD_FLOSSCAPA. If RMF_CAPA2 exist also, RMF_CAPA1 is - * for OBD_MD_FLMDSCAPA only. */ - if (req_capsule_has_field(pill, &RMF_CAPA1, RCL_SERVER)) { - if ((req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) && - !(body->valid & OBD_MD_FLMDSCAPA)) || - (!req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) && - !(body->valid & OBD_MD_FLMDSCAPA) && - !(body->valid & OBD_MD_FLOSSCAPA))) - adjust += req_capsule_shrink(pill, &RMF_CAPA1, - 0, adjust, 1); - } + req_capsule_shrink(pill, &RMF_LOGCOOKIES, + acl_size, RCL_SERVER); - /* RMF_CAPA2 on server-side is for OBD_MD_FLOSSCAPA only. */ - if ((req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) && - !(body->valid & OBD_MD_FLOSSCAPA))) - adjust += req_capsule_shrink(pill, &RMF_CAPA2, 0, adjust, 0); + if (req_capsule_has_field(pill, &RMF_CAPA1, RCL_SERVER) && + !(body->mbo_valid & OBD_MD_FLMDSCAPA)) + req_capsule_shrink(pill, &RMF_CAPA1, 0, RCL_SERVER); + + if (req_capsule_has_field(pill, &RMF_CAPA2, RCL_SERVER) && + !(body->mbo_valid & OBD_MD_FLOSSCAPA)) + req_capsule_shrink(pill, &RMF_CAPA2, 0, RCL_SERVER); /* * Some more field should be shrinked if needed. * This should be done by those who added fields to reply message. */ - EXIT; + + /* Grow MD buffer if needed finally */ + if (info->mti_big_lmm_used) { + void *lmm; + + LASSERT(md_size > md_packed); + CDEBUG(D_INFO, "Enlarge reply buffer, need extra %d bytes\n", + md_size - md_packed); + rc = req_capsule_server_grow(pill, &RMF_MDT_MD, md_size); + if (rc) { + /* we can't answer with proper LOV EA, drop flags, + * the rc is also returned so this request is + * considered as failed */ + body->mbo_valid &= ~(OBD_MD_FLDIREA | OBD_MD_FLEASIZE); + /* don't return transno along with error */ + lustre_msg_set_transno(pill->rc_req->rq_repmsg, 0); + } else { + /* now we need to pack right LOV/LMV EA */ + lmm = req_capsule_server_get(pill, &RMF_MDT_MD); + if (info->mti_attr.ma_valid & MA_LOV) { + LASSERT(req_capsule_get_size(pill, &RMF_MDT_MD, + RCL_SERVER) == + info->mti_attr.ma_lmm_size); + memcpy(lmm, info->mti_attr.ma_lmm, + info->mti_attr.ma_lmm_size); + } else if (info->mti_attr.ma_valid & MA_LMV) { + LASSERT(req_capsule_get_size(pill, &RMF_MDT_MD, + RCL_SERVER) == + info->mti_attr.ma_lmv_size); + memcpy(lmm, info->mti_attr.ma_lmv, + info->mti_attr.ma_lmv_size); + } + } + /* update mdt_max_mdsize so clients will be aware about that */ + if (info->mti_mdt->mdt_max_mdsize < info->mti_attr.ma_lmm_size) + info->mti_mdt->mdt_max_mdsize = + info->mti_attr.ma_lmm_size; + info->mti_big_lmm_used = 0; + } + RETURN(rc); } @@ -632,37 +817,17 @@ int mdt_handle_last_unlink(struct mdt_thread_info *info, struct mdt_object *mo, const struct lu_attr *la = &ma->ma_attr; ENTRY; - repbody = req_capsule_server_get(&info->mti_pill, &RMF_MDT_BODY); + repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY); LASSERT(repbody != NULL); if (ma->ma_valid & MA_INODE) mdt_pack_attr2body(info, repbody, la, mdt_object_fid(mo)); if (ma->ma_valid & MA_LOV) { - __u32 mode; - - if (mdt_object_exists(mo) < 0) - /* If it is a remote object, and we do not retrieve - * EA back unlink reg file*/ - mode = S_IFREG; - else - mode = lu_object_attr(&mo->mot_obj.mo_lu); - - LASSERT(ma->ma_lmm_size); - mdt_dump_lmm(D_INFO, ma->ma_lmm); - repbody->eadatasize = ma->ma_lmm_size; - if (S_ISREG(mode)) - repbody->valid |= OBD_MD_FLEASIZE; - else if (S_ISDIR(mode)) - repbody->valid |= OBD_MD_FLDIREA; - else - LBUG(); - } - - if (ma->ma_cookie_size && (ma->ma_valid & MA_COOKIE)) { - repbody->aclsize = ma->ma_cookie_size; - repbody->valid |= OBD_MD_FLCOOKIE; + CERROR("No need in LOV EA upon unlink\n"); + dump_stack(); } + repbody->mbo_eadatasize = 0; RETURN(0); } @@ -670,117 +835,178 @@ int mdt_handle_last_unlink(struct mdt_thread_info *info, struct mdt_object *mo, static __u64 mdt_attr_valid_xlate(__u64 in, struct mdt_reint_record *rr, struct md_attr *ma) { - __u64 out; - - out = 0; - if (in & ATTR_MODE) - out |= LA_MODE; - if (in & ATTR_UID) - out |= LA_UID; - if (in & ATTR_GID) - out |= LA_GID; - if (in & ATTR_SIZE) - out |= LA_SIZE; - if (in & ATTR_BLOCKS) - out |= LA_BLOCKS; - - if (in & ATTR_FROM_OPEN) - rr->rr_flags |= MRF_SETATTR_LOCKED; - - if (in & ATTR_ATIME_SET) - out |= LA_ATIME; - - if (in & ATTR_CTIME_SET) - out |= LA_CTIME; - - if (in & ATTR_MTIME_SET) - out |= LA_MTIME; - - if (in & ATTR_ATTR_FLAG) - out |= LA_FLAGS; - - if (in & MDS_OPEN_OWNEROVERRIDE) - out |= MDS_OPEN_OWNEROVERRIDE; - - /*XXX need ATTR_RAW?*/ - in &= ~(ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_BLOCKS| - ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_FROM_OPEN| - ATTR_ATIME_SET|ATTR_CTIME_SET|ATTR_MTIME_SET| - ATTR_ATTR_FLAG|ATTR_RAW|MDS_OPEN_OWNEROVERRIDE); - if (in != 0) - CERROR("Unknown attr bits: %#llx\n", in); - return out; + __u64 out; + + out = 0; + if (in & MDS_ATTR_MODE) + out |= LA_MODE; + if (in & MDS_ATTR_UID) + out |= LA_UID; + if (in & MDS_ATTR_GID) + out |= LA_GID; + if (in & MDS_ATTR_SIZE) + out |= LA_SIZE; + if (in & MDS_ATTR_BLOCKS) + out |= LA_BLOCKS; + if (in & MDS_ATTR_ATIME_SET) + out |= LA_ATIME; + if (in & MDS_ATTR_CTIME_SET) + out |= LA_CTIME; + if (in & MDS_ATTR_MTIME_SET) + out |= LA_MTIME; + if (in & MDS_ATTR_ATTR_FLAG) + out |= LA_FLAGS; + if (in & MDS_ATTR_KILL_SUID) + out |= LA_KILL_SUID; + if (in & MDS_ATTR_KILL_SGID) + out |= LA_KILL_SGID; + + if (in & MDS_ATTR_FROM_OPEN) + rr->rr_flags |= MRF_OPEN_TRUNC; + if (in & MDS_OPEN_OWNEROVERRIDE) + ma->ma_attr_flags |= MDS_OWNEROVERRIDE; + if (in & MDS_ATTR_FORCE) + ma->ma_attr_flags |= MDS_PERM_BYPASS; + + in &= ~(MDS_ATTR_MODE | MDS_ATTR_UID | MDS_ATTR_GID | + MDS_ATTR_ATIME | MDS_ATTR_MTIME | MDS_ATTR_CTIME | + MDS_ATTR_ATIME_SET | MDS_ATTR_CTIME_SET | MDS_ATTR_MTIME_SET | + MDS_ATTR_SIZE | MDS_ATTR_BLOCKS | MDS_ATTR_ATTR_FLAG | + MDS_ATTR_FORCE | MDS_ATTR_KILL_SUID | MDS_ATTR_KILL_SGID | + MDS_ATTR_FROM_OPEN | MDS_OPEN_OWNEROVERRIDE); + if (in != 0) + CERROR("Unknown attr bits: "LPX64"\n", in); + return out; } + /* unpacking */ +int mdt_name_unpack(struct req_capsule *pill, + const struct req_msg_field *field, + struct lu_name *ln, + enum mdt_name_flags flags) +{ + ln->ln_name = req_capsule_client_get(pill, field); + ln->ln_namelen = req_capsule_get_size(pill, field, RCL_CLIENT) - 1; + + if (!lu_name_is_valid(ln)) { + ln->ln_name = NULL; + ln->ln_namelen = 0; + + return -EPROTO; + } + + if ((flags & MNF_FIX_ANON) && + ln->ln_namelen == 1 && ln->ln_name[0] == '/') { + /* Newer (3.x) kernels use a name of "/" for the + * "anonymous" disconnected dentries from NFS + * filehandle conversion. See d_obtain_alias(). */ + ln->ln_name = NULL; + ln->ln_namelen = 0; + } + + return 0; +} + static int mdt_setattr_unpack_rec(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); - struct md_attr *ma = &info->mti_attr; - struct lu_attr *la = &ma->ma_attr; - struct req_capsule *pill = &info->mti_pill; - struct mdt_reint_record *rr = &info->mti_rr; - struct mdt_rec_setattr *rec; + struct lu_ucred *uc = mdt_ucred(info); + struct md_attr *ma = &info->mti_attr; + struct lu_attr *la = &ma->ma_attr; + struct req_capsule *pill = info->mti_pill; + struct mdt_reint_record *rr = &info->mti_rr; + struct mdt_rec_setattr *rec; + struct lu_nodemap *nodemap; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_SETATTR); + CLASSERT(sizeof(struct mdt_rec_setattr)== sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->sa_fsuid; - uc->mu_fsgid = rec->sa_fsgid; - uc->mu_cap = rec->sa_cap; - uc->mu_suppgids[0] = rec->sa_suppgid; - uc->mu_suppgids[1] = -1; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->sa_fsuid; + uc->uc_fsgid = rec->sa_fsgid; + uc->uc_cap = rec->sa_cap; + uc->uc_suppgids[0] = rec->sa_suppgid; + uc->uc_suppgids[1] = -1; rr->rr_fid1 = &rec->sa_fid; - la->la_valid = mdt_attr_valid_xlate(rec->sa_valid, rr, ma); - la->la_mode = rec->sa_mode; - la->la_flags = rec->sa_attr_flags; - la->la_uid = rec->sa_uid; - la->la_gid = rec->sa_gid; - la->la_size = rec->sa_size; - la->la_blocks = rec->sa_blocks; - la->la_ctime = rec->sa_ctime; - la->la_atime = rec->sa_atime; - la->la_mtime = rec->sa_mtime; - ma->ma_valid = MA_INODE; - - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); - - RETURN(0); + la->la_valid = mdt_attr_valid_xlate(rec->sa_valid, rr, ma); + la->la_mode = rec->sa_mode; + la->la_flags = rec->sa_attr_flags; + + nodemap = nodemap_get_from_exp(info->mti_exp); + if (IS_ERR(nodemap)) + RETURN(PTR_ERR(nodemap)); + + la->la_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, rec->sa_uid); + la->la_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, rec->sa_gid); + nodemap_putref(nodemap); + + la->la_size = rec->sa_size; + la->la_blocks = rec->sa_blocks; + la->la_ctime = rec->sa_ctime; + la->la_atime = rec->sa_atime; + la->la_mtime = rec->sa_mtime; + ma->ma_valid = MA_INODE; + + if (rec->sa_bias & MDS_DATA_MODIFIED) + ma->ma_attr_flags |= MDS_DATA_MODIFIED; + else + ma->ma_attr_flags &= ~MDS_DATA_MODIFIED; + + if (rec->sa_bias & MDS_HSM_RELEASE) + ma->ma_attr_flags |= MDS_HSM_RELEASE; + else + ma->ma_attr_flags &= ~MDS_HSM_RELEASE; + + if (rec->sa_bias & MDS_CLOSE_LAYOUT_SWAP) + ma->ma_attr_flags |= MDS_CLOSE_LAYOUT_SWAP; + else + ma->ma_attr_flags &= ~MDS_CLOSE_LAYOUT_SWAP; + + RETURN(0); } -static int mdt_epoch_unpack(struct mdt_thread_info *info) +static int mdt_close_handle_unpack(struct mdt_thread_info *info) { - struct req_capsule *pill = &info->mti_pill; - ENTRY; + struct req_capsule *pill = info->mti_pill; + struct mdt_ioepoch *ioepoch; + ENTRY; - if (req_capsule_get_size(pill, &RMF_MDT_EPOCH, RCL_CLIENT)) - info->mti_epoch = req_capsule_client_get(pill, &RMF_MDT_EPOCH); - else - info->mti_epoch = NULL; - RETURN(info->mti_epoch == NULL ? -EFAULT : 0); + if (req_capsule_get_size(pill, &RMF_MDT_EPOCH, RCL_CLIENT)) + ioepoch = req_capsule_client_get(pill, &RMF_MDT_EPOCH); + else + ioepoch = NULL; + + if (ioepoch == NULL) + RETURN(-EPROTO); + + info->mti_close_handle = ioepoch->mio_handle; + + RETURN(0); } static inline int mdt_dlmreq_unpack(struct mdt_thread_info *info) { - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; if (req_capsule_get_size(pill, &RMF_DLM_REQ, RCL_CLIENT)) { info->mti_dlm_req = req_capsule_client_get(pill, &RMF_DLM_REQ); if (info->mti_dlm_req == NULL) RETURN(-EFAULT); } - + RETURN(0); } static int mdt_setattr_unpack(struct mdt_thread_info *info) { + struct mdt_reint_record *rr = &info->mti_rr; struct md_attr *ma = &info->mti_attr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; int rc; ENTRY; @@ -788,58 +1014,93 @@ static int mdt_setattr_unpack(struct mdt_thread_info *info) if (rc) RETURN(rc); - /* Epoch may be absent */ - mdt_epoch_unpack(info); + if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) { + rr->rr_eadata = req_capsule_client_get(pill, &RMF_EADATA); + rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA, + RCL_CLIENT); + if (rr->rr_eadatalen > 0) { + const struct lmv_user_md *lum; + + lum = rr->rr_eadata; + /* Sigh ma_valid(from req) does not indicate whether + * it will set LOV/LMV EA, so we have to check magic */ + if (le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC) { + ma->ma_valid |= MA_LMV; + ma->ma_lmv = (void *)rr->rr_eadata; + ma->ma_lmv_size = rr->rr_eadatalen; + } else { + ma->ma_valid |= MA_LOV; + ma->ma_lmm = (void *)rr->rr_eadata; + ma->ma_lmm_size = rr->rr_eadatalen; + } + } + } + + rc = mdt_dlmreq_unpack(info); + RETURN(rc); +} - ma->ma_lmm_size = req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT); - if (ma->ma_lmm_size) { - ma->ma_lmm = req_capsule_client_get(pill, &RMF_EADATA); - ma->ma_valid |= MA_LOV; - } +static int mdt_intent_close_unpack(struct mdt_thread_info *info) +{ + struct md_attr *ma = &info->mti_attr; + struct req_capsule *pill = info->mti_pill; + ENTRY; - ma->ma_cookie_size = req_capsule_get_size(pill, &RMF_LOGCOOKIES, - RCL_CLIENT); - if (ma->ma_cookie_size) { - ma->ma_cookie = req_capsule_client_get(pill, &RMF_LOGCOOKIES); - ma->ma_valid |= MA_COOKIE; - } + if (!(ma->ma_attr_flags & (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP))) + RETURN(0); - rc = mdt_dlmreq_unpack(info); - RETURN(rc); + req_capsule_extend(pill, &RQF_MDS_INTENT_CLOSE); + + if (!(req_capsule_has_field(pill, &RMF_CLOSE_DATA, RCL_CLIENT) && + req_capsule_field_present(pill, &RMF_CLOSE_DATA, RCL_CLIENT))) + RETURN(-EFAULT); + + RETURN(0); } int mdt_close_unpack(struct mdt_thread_info *info) { - int rc; - ENTRY; + int rc; + ENTRY; - rc = mdt_epoch_unpack(info); + rc = mdt_close_handle_unpack(info); if (rc) RETURN(rc); - RETURN(mdt_setattr_unpack_rec(info)); + rc = mdt_setattr_unpack_rec(info); + if (rc) + RETURN(rc); + + rc = mdt_intent_close_unpack(info); + if (rc) + RETURN(rc); + + RETURN(mdt_init_ucred_reint(info)); } static int mdt_create_unpack(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); + struct lu_ucred *uc = mdt_ucred(info); struct mdt_rec_create *rec; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_reint_record *rr = &info->mti_rr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; struct md_op_spec *sp = &info->mti_spec; int rc; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_CREATE); + CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->cr_fsuid; - uc->mu_fsgid = rec->cr_fsgid; - uc->mu_cap = rec->cr_cap; - uc->mu_suppgids[0] = rec->cr_suppgid1; - uc->mu_suppgids[1] = -1; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->cr_fsuid; + uc->uc_fsgid = rec->cr_fsgid; + uc->uc_cap = rec->cr_cap; + uc->uc_suppgids[0] = rec->cr_suppgid1; + uc->uc_suppgids[1] = -1; + uc->uc_umask = rec->cr_umask; rr->rr_fid1 = &rec->cr_fid1; rr->rr_fid2 = &rec->cr_fid2; @@ -850,56 +1111,16 @@ static int mdt_create_unpack(struct mdt_thread_info *info) attr->la_ctime = rec->cr_time; attr->la_mtime = rec->cr_time; attr->la_atime = rec->cr_time; - attr->la_valid = LA_MODE | LA_RDEV | LA_UID | LA_GID | - LA_CTIME | LA_MTIME | LA_ATIME; + attr->la_valid = LA_MODE | LA_RDEV | LA_UID | LA_GID | LA_TYPE | + LA_CTIME | LA_MTIME | LA_ATIME; memset(&sp->u, 0, sizeof(sp->u)); - sp->sp_cr_flags = rec->cr_flags; - sp->sp_ck_split = !!(rec->cr_bias & MDS_CHECK_SPLIT); - info->mti_cross_ref = !!(rec->cr_bias & MDS_CROSS_REF); + sp->sp_cr_flags = get_mrc_cr_flags(rec); - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); - mdt_set_capainfo(info, 1, rr->rr_fid2, BYPASS_CAPA); - - rr->rr_name = req_capsule_client_get(pill, &RMF_NAME); - rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1; - LASSERT(rr->rr_namelen > 0); - -#ifdef CONFIG_FS_POSIX_ACL - if (sp->sp_cr_flags & MDS_CREATE_RMT_ACL) { - if (S_ISDIR(attr->la_mode)) - sp->u.sp_pfid = rr->rr_fid1; - req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL); - LASSERT(req_capsule_field_present(pill, &RMF_EADATA, - RCL_CLIENT)); - sp->u.sp_ea.eadata = req_capsule_client_get(pill, &RMF_EADATA); - sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, &RMF_EADATA, - RCL_CLIENT); - sp->u.sp_ea.fid = rr->rr_fid1; - RETURN(0); - } -#endif - if (S_ISDIR(attr->la_mode)) { - /* pass parent fid for cross-ref cases */ - sp->u.sp_pfid = rr->rr_fid1; - if (sp->sp_cr_flags & MDS_CREATE_SLAVE_OBJ) { - /* create salve object req, need - * unpack split ea here - */ - req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SLAVE); - LASSERT(req_capsule_field_present(pill, &RMF_EADATA, - RCL_CLIENT)); - sp->u.sp_ea.eadata = req_capsule_client_get(pill, - &RMF_EADATA); - sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, - &RMF_EADATA, - RCL_CLIENT); - sp->u.sp_ea.fid = rr->rr_fid1; - RETURN(0); - } - req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL); - } else if (S_ISLNK(attr->la_mode)) { + rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0); + if (rc < 0) + RETURN(rc); + + if (S_ISLNK(attr->la_mode)) { const char *tgt = NULL; req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_SYM); @@ -911,30 +1132,42 @@ static int mdt_create_unpack(struct mdt_thread_info *info) RETURN(-EFAULT); } else { req_capsule_extend(pill, &RQF_MDS_REINT_CREATE_RMT_ACL); - } - rc = mdt_dlmreq_unpack(info); - RETURN(rc); + if (S_ISDIR(attr->la_mode) && + req_capsule_get_size(pill, &RMF_EADATA, RCL_CLIENT) > 0) { + sp->u.sp_ea.eadata = + req_capsule_client_get(pill, &RMF_EADATA); + sp->u.sp_ea.eadatalen = + req_capsule_get_size(pill, &RMF_EADATA, + RCL_CLIENT); + sp->sp_cr_flags |= MDS_OPEN_HAS_EA; + } + } + + rc = mdt_dlmreq_unpack(info); + RETURN(rc); } static int mdt_link_unpack(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); + struct lu_ucred *uc = mdt_ucred(info); struct mdt_rec_link *rec; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_reint_record *rr = &info->mti_rr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; int rc; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_LINK); + CLASSERT(sizeof(struct mdt_rec_link) == sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->lk_fsuid; - uc->mu_fsgid = rec->lk_fsgid; - uc->mu_cap = rec->lk_cap; - uc->mu_suppgids[0] = rec->lk_suppgid1; - uc->mu_suppgids[1] = rec->lk_suppgid2; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->lk_fsuid; + uc->uc_fsgid = rec->lk_fsgid; + uc->uc_cap = rec->lk_cap; + uc->uc_suppgids[0] = rec->lk_suppgid1; + uc->uc_suppgids[1] = rec->lk_suppgid2; attr->la_uid = rec->lk_fsuid; attr->la_gid = rec->lk_fsgid; @@ -944,45 +1177,37 @@ static int mdt_link_unpack(struct mdt_thread_info *info) attr->la_mtime = rec->lk_time; attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME; - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); - if (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT)) - mdt_set_capainfo(info, 1, rr->rr_fid2, - req_capsule_client_get(pill, &RMF_CAPA2)); + rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0); + if (rc < 0) + RETURN(rc); - rr->rr_name = req_capsule_client_get(pill, &RMF_NAME); - if (rr->rr_name == NULL) - RETURN(-EFAULT); - rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1; - LASSERT(rr->rr_namelen > 0); - info->mti_spec.sp_ck_split = !!(rec->lk_bias & MDS_CHECK_SPLIT); - info->mti_cross_ref = !!(rec->lk_bias & MDS_CROSS_REF); + rc = mdt_dlmreq_unpack(info); - rc = mdt_dlmreq_unpack(info); - RETURN(rc); + RETURN(rc); } static int mdt_unlink_unpack(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); + struct lu_ucred *uc = mdt_ucred(info); struct mdt_rec_unlink *rec; struct md_attr *ma = &info->mti_attr; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_reint_record *rr = &info->mti_rr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; int rc; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_UNLINK); + CLASSERT(sizeof(struct mdt_rec_unlink) == sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->ul_fsuid; - uc->mu_fsgid = rec->ul_fsgid; - uc->mu_cap = rec->ul_cap; - uc->mu_suppgids[0] = rec->ul_suppgid; - uc->mu_suppgids[1] = -1; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->ul_fsuid; + uc->uc_fsgid = rec->ul_fsgid; + uc->uc_cap = rec->ul_cap; + uc->uc_suppgids[0] = rec->ul_suppgid1; + uc->uc_suppgids[1] = -1; attr->la_uid = rec->ul_fsuid; attr->la_gid = rec->ul_fsgid; @@ -993,46 +1218,49 @@ static int mdt_unlink_unpack(struct mdt_thread_info *info) attr->la_mode = rec->ul_mode; attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE; - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); + rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0); + if (rc < 0) + RETURN(rc); - rr->rr_name = req_capsule_client_get(pill, &RMF_NAME); - if (rr->rr_name == NULL) - RETURN(-EFAULT); - rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1; - LASSERT(rr->rr_namelen > 0); - info->mti_spec.sp_ck_split = !!(rec->ul_bias & MDS_CHECK_SPLIT); - info->mti_cross_ref = !!(rec->ul_bias & MDS_CROSS_REF); if (rec->ul_bias & MDS_VTX_BYPASS) ma->ma_attr_flags |= MDS_VTX_BYPASS; else ma->ma_attr_flags &= ~MDS_VTX_BYPASS; + info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info)); + rc = mdt_dlmreq_unpack(info); RETURN(rc); } +static int mdt_rmentry_unpack(struct mdt_thread_info *info) +{ + info->mti_spec.sp_rm_entry = 1; + return mdt_unlink_unpack(info); +} + static int mdt_rename_unpack(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); + struct lu_ucred *uc = mdt_ucred(info); struct mdt_rec_rename *rec; struct md_attr *ma = &info->mti_attr; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_reint_record *rr = &info->mti_rr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; int rc; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_RENAME); + CLASSERT(sizeof(struct mdt_rec_rename) == sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->rn_fsuid; - uc->mu_fsgid = rec->rn_fsgid; - uc->mu_cap = rec->rn_cap; - uc->mu_suppgids[0] = rec->rn_suppgid1; - uc->mu_suppgids[1] = rec->rn_suppgid2; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->rn_fsuid; + uc->uc_fsgid = rec->rn_fsgid; + uc->uc_cap = rec->rn_cap; + uc->uc_suppgids[0] = rec->rn_suppgid1; + uc->uc_suppgids[1] = rec->rn_suppgid2; attr->la_uid = rec->rn_fsuid; attr->la_gid = rec->rn_fsgid; @@ -1044,52 +1272,82 @@ static int mdt_rename_unpack(struct mdt_thread_info *info) attr->la_mode = rec->rn_mode; attr->la_valid = LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_MODE; - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); - if (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT)) - mdt_set_capainfo(info, 1, rr->rr_fid2, - req_capsule_client_get(pill, &RMF_CAPA2)); + rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0); + if (rc < 0) + RETURN(rc); + + rc = mdt_name_unpack(pill, &RMF_SYMTGT, &rr->rr_tgt_name, 0); + if (rc < 0) + RETURN(rc); - rr->rr_name = req_capsule_client_get(pill, &RMF_NAME); - rr->rr_tgt = req_capsule_client_get(pill, &RMF_SYMTGT); - if (rr->rr_name == NULL || rr->rr_tgt == NULL) - RETURN(-EFAULT); - rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1; - LASSERT(rr->rr_namelen > 0); - rr->rr_tgtlen = req_capsule_get_size(pill, &RMF_SYMTGT, RCL_CLIENT) - 1; - LASSERT(rr->rr_tgtlen > 0); - info->mti_spec.sp_ck_split = !!(rec->rn_bias & MDS_CHECK_SPLIT); - info->mti_cross_ref = !!(rec->rn_bias & MDS_CROSS_REF); if (rec->rn_bias & MDS_VTX_BYPASS) ma->ma_attr_flags |= MDS_VTX_BYPASS; else ma->ma_attr_flags &= ~MDS_VTX_BYPASS; - rc = mdt_dlmreq_unpack(info); - RETURN(rc); + if (rec->rn_bias & MDS_RENAME_MIGRATE) { + req_capsule_extend(info->mti_pill, &RQF_MDS_REINT_MIGRATE); + rc = mdt_close_handle_unpack(info); + if (rc < 0) + RETURN(rc); + info->mti_spec.sp_migrate_close = 1; + } + + info->mti_spec.no_create = !!req_is_replay(mdt_info_req(info)); + + + rc = mdt_dlmreq_unpack(info); + + RETURN(rc); +} + +/* + * please see comment above LOV_MAGIC_V1_DEF + */ +static void mdt_fix_lov_magic(struct mdt_thread_info *info) +{ + struct mdt_reint_record *rr = &info->mti_rr; + struct lov_user_md_v1 *v1; + + v1 = (void *)rr->rr_eadata; + LASSERT(v1); + + if (unlikely(req_is_replay(mdt_info_req(info)))) { + if (v1->lmm_magic == LOV_USER_MAGIC_V1) { + v1->lmm_magic = LOV_MAGIC_V1_DEF; + } else if (v1->lmm_magic == __swab32(LOV_USER_MAGIC_V1)) { + v1->lmm_magic = __swab32(LOV_MAGIC_V1_DEF); + } else if (v1->lmm_magic == LOV_USER_MAGIC_V3) { + v1->lmm_magic = LOV_MAGIC_V3_DEF; + } else if (v1->lmm_magic == __swab32(LOV_USER_MAGIC_V3)) { + v1->lmm_magic = __swab32(LOV_MAGIC_V3_DEF); + } + } } static int mdt_open_unpack(struct mdt_thread_info *info) { - struct md_ucred *uc = mdt_ucred(info); + struct lu_ucred *uc = mdt_ucred(info); struct mdt_rec_create *rec; struct lu_attr *attr = &info->mti_attr.ma_attr; - struct req_capsule *pill = &info->mti_pill; + struct req_capsule *pill = info->mti_pill; struct mdt_reint_record *rr = &info->mti_rr; struct ptlrpc_request *req = mdt_info_req(info); struct md_op_spec *sp = &info->mti_spec; ENTRY; - rec = req_capsule_client_get(pill, &RMF_REC_CREATE); + CLASSERT(sizeof(struct mdt_rec_create) == sizeof(struct mdt_rec_reint)); + rec = req_capsule_client_get(pill, &RMF_REC_REINT); if (rec == NULL) RETURN(-EFAULT); - uc->mu_fsuid = rec->cr_fsuid; - uc->mu_fsgid = rec->cr_fsgid; - uc->mu_cap = rec->cr_cap; - uc->mu_suppgids[0] = rec->cr_suppgid1; - uc->mu_suppgids[1] = rec->cr_suppgid2; + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->cr_fsuid; + uc->uc_fsgid = rec->cr_fsgid; + uc->uc_cap = rec->cr_cap; + uc->uc_suppgids[0] = rec->cr_suppgid1; + uc->uc_suppgids[1] = rec->cr_suppgid2; + uc->uc_umask = rec->cr_umask; rr->rr_fid1 = &rec->cr_fid1; rr->rr_fid2 = &rec->cr_fid2; @@ -1104,56 +1362,111 @@ static int mdt_open_unpack(struct mdt_thread_info *info) attr->la_valid = LA_MODE | LA_RDEV | LA_UID | LA_GID | LA_CTIME | LA_MTIME | LA_ATIME; memset(&info->mti_spec.u, 0, sizeof(info->mti_spec.u)); - info->mti_spec.sp_cr_flags = rec->cr_flags; - info->mti_replayepoch = rec->cr_ioepoch; + info->mti_spec.sp_cr_flags = get_mrc_cr_flags(rec); + /* Do not trigger ASSERTION if client miss to set such flags. */ + if (unlikely(info->mti_spec.sp_cr_flags == 0)) + RETURN(-EPROTO); - info->mti_spec.sp_ck_split = !!(rec->cr_bias & MDS_CHECK_SPLIT); info->mti_cross_ref = !!(rec->cr_bias & MDS_CROSS_REF); - if (req_capsule_get_size(pill, &RMF_CAPA1, RCL_CLIENT)) - mdt_set_capainfo(info, 0, rr->rr_fid1, - req_capsule_client_get(pill, &RMF_CAPA1)); - if ((lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY) && - (req_capsule_get_size(pill, &RMF_CAPA2, RCL_CLIENT))) { -#if 0 - mdt_set_capainfo(info, 1, rr->rr_fid2, - req_capsule_client_get(pill, &RMF_CAPA2)); -#else + mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, MNF_FIX_ANON); + + if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) { + rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA, + RCL_CLIENT); + if (rr->rr_eadatalen > 0) { + rr->rr_eadata = req_capsule_client_get(pill, + &RMF_EADATA); + sp->u.sp_ea.eadatalen = rr->rr_eadatalen; + sp->u.sp_ea.eadata = rr->rr_eadata; + sp->no_create = !!req_is_replay(req); + mdt_fix_lov_magic(info); + } + /* - * FIXME: capa in replay open request might have expired, - * bypass capa check. Security hole? + * Client default md_size may be 0 right after client start, + * until all osc are connected, set here just some reasonable + * value to prevent misbehavior. */ - mdt_set_capainfo(info, 0, rr->rr_fid1, BYPASS_CAPA); - mdt_set_capainfo(info, 1, rr->rr_fid2, BYPASS_CAPA); -#endif - } + if (rr->rr_eadatalen == 0 && + !(info->mti_spec.sp_cr_flags & MDS_OPEN_DELAY_CREATE)) + rr->rr_eadatalen = MIN_MD_SIZE; + } + + RETURN(0); +} + +static int mdt_setxattr_unpack(struct mdt_thread_info *info) +{ + struct mdt_reint_record *rr = &info->mti_rr; + struct lu_ucred *uc = mdt_ucred(info); + struct lu_attr *attr = &info->mti_attr.ma_attr; + struct req_capsule *pill = info->mti_pill; + struct mdt_rec_setxattr *rec; + int rc; + ENTRY; + - rr->rr_name = req_capsule_client_get(pill, &RMF_NAME); - if (rr->rr_name == NULL) + CLASSERT(sizeof(struct mdt_rec_setxattr) == + sizeof(struct mdt_rec_reint)); + + rec = req_capsule_client_get(pill, &RMF_REC_REINT); + if (rec == NULL) + RETURN(-EFAULT); + + /* This prior initialization is needed for old_init_ucred_reint() */ + uc->uc_fsuid = rec->sx_fsuid; + uc->uc_fsgid = rec->sx_fsgid; + uc->uc_cap = rec->sx_cap; + uc->uc_suppgids[0] = rec->sx_suppgid1; + uc->uc_suppgids[1] = -1; + + rr->rr_opcode = rec->sx_opcode; + rr->rr_fid1 = &rec->sx_fid; + attr->la_valid = rec->sx_valid; + attr->la_ctime = rec->sx_time; + attr->la_size = rec->sx_size; + attr->la_flags = rec->sx_flags; + + rc = mdt_name_unpack(pill, &RMF_NAME, &rr->rr_name, 0); + if (rc < 0) + RETURN(rc); + + if (req_capsule_field_present(pill, &RMF_EADATA, RCL_CLIENT)) { + rr->rr_eadatalen = req_capsule_get_size(pill, &RMF_EADATA, + RCL_CLIENT); + if (rr->rr_eadatalen > 0) { + rr->rr_eadata = req_capsule_client_get(pill, + &RMF_EADATA); + if (rr->rr_eadata == NULL) + RETURN(-EFAULT); + } else { + rr->rr_eadata = NULL; + } + } else if (!(attr->la_valid & OBD_MD_FLXATTRRM)) { + CDEBUG(D_INFO, "no xattr data supplied\n"); RETURN(-EFAULT); - rr->rr_namelen = req_capsule_get_size(pill, &RMF_NAME, RCL_CLIENT) - 1; - LASSERT(rr->rr_namelen > 0); - - sp->u.sp_ea.eadatalen = req_capsule_get_size(pill, &RMF_EADATA, - RCL_CLIENT); - if (sp->u.sp_ea.eadatalen) { - sp->u.sp_ea.eadata = req_capsule_client_get(pill, &RMF_EADATA); - if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY) - sp->u.sp_ea.no_lov_create = 1; } + if (mdt_dlmreq_unpack(info) < 0) + RETURN(-EPROTO); + RETURN(0); } + typedef int (*reint_unpacker)(struct mdt_thread_info *info); static reint_unpacker mdt_reint_unpackers[REINT_MAX] = { - [REINT_SETATTR] = mdt_setattr_unpack, - [REINT_CREATE] = mdt_create_unpack, - [REINT_LINK] = mdt_link_unpack, - [REINT_UNLINK] = mdt_unlink_unpack, - [REINT_RENAME] = mdt_rename_unpack, - [REINT_OPEN] = mdt_open_unpack + [REINT_SETATTR] = mdt_setattr_unpack, + [REINT_CREATE] = mdt_create_unpack, + [REINT_LINK] = mdt_link_unpack, + [REINT_UNLINK] = mdt_unlink_unpack, + [REINT_RENAME] = mdt_rename_unpack, + [REINT_OPEN] = mdt_open_unpack, + [REINT_SETXATTR] = mdt_setxattr_unpack, + [REINT_RMENTRY] = mdt_rmentry_unpack, + [REINT_MIGRATE] = mdt_rename_unpack, }; int mdt_reint_unpack(struct mdt_thread_info *info, __u32 op)