| /* |
| * GPL HEADER START |
| * |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * 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). |
| * |
| * You should have received a copy of the GNU General Public License |
| * version 2 along with this program; If not, see |
| * http://www.gnu.org/licenses/gpl-2.0.html |
| * |
| * GPL HEADER END |
| */ |
| /* |
| * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
| * Use is subject to license terms. |
| * |
| * Copyright (c) 2011, 2015, Intel Corporation. |
| */ |
| /* |
| * This file is part of Lustre, http://www.lustre.org/ |
| * Lustre is a trademark of Sun Microsystems, Inc. |
| */ |
| |
| #define DEBUG_SUBSYSTEM S_MDC |
| #include <lustre_net.h> |
| #include <uapi/linux/lustre/lustre_idl.h> |
| #include "mdc_internal.h" |
| |
| static void set_mrc_cr_flags(struct mdt_rec_create *mrc, u64 flags) |
| { |
| mrc->cr_flags_l = (u32)(flags & 0xFFFFFFFFUll); |
| mrc->cr_flags_h = (u32)(flags >> 32); |
| } |
| |
| static void __mdc_pack_body(struct mdt_body *b, __u32 suppgid) |
| { |
| b->mbo_suppgid = suppgid; |
| b->mbo_uid = from_kuid(&init_user_ns, current_uid()); |
| b->mbo_gid = from_kgid(&init_user_ns, current_gid()); |
| b->mbo_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
| b->mbo_fsgid = from_kgid(&init_user_ns, current_fsgid()); |
| b->mbo_capability = cfs_curproc_cap_pack(); |
| } |
| |
| void mdc_swap_layouts_pack(struct ptlrpc_request *req, |
| struct md_op_data *op_data) |
| { |
| struct mdt_body *b = req_capsule_client_get(&req->rq_pill, |
| &RMF_MDT_BODY); |
| |
| __mdc_pack_body(b, op_data->op_suppgids[0]); |
| b->mbo_fid1 = op_data->op_fid1; |
| b->mbo_fid2 = op_data->op_fid2; |
| b->mbo_valid |= OBD_MD_FLID; |
| } |
| |
| void mdc_pack_body(struct ptlrpc_request *req, const struct lu_fid *fid, |
| __u64 valid, size_t ea_size, __u32 suppgid, u32 flags) |
| { |
| struct mdt_body *b = req_capsule_client_get(&req->rq_pill, |
| &RMF_MDT_BODY); |
| b->mbo_valid = valid; |
| b->mbo_eadatasize = ea_size; |
| b->mbo_flags = flags; |
| __mdc_pack_body(b, suppgid); |
| if (fid) { |
| b->mbo_fid1 = *fid; |
| b->mbo_valid |= OBD_MD_FLID; |
| } |
| } |
| |
| /** |
| * Pack a name (path component) into a request |
| * |
| * \param[in] req request |
| * \param[in] field request field (usually RMF_NAME) |
| * \param[in] name path component |
| * \param[in] name_len length of path component |
| * |
| * \a field must be present in \a req and of size \a name_len + 1. |
| * |
| * \a name must be '\0' terminated of length \a name_len and represent |
| * a single path component (not contain '/'). |
| */ |
| static void mdc_pack_name(struct ptlrpc_request *req, |
| const struct req_msg_field *field, |
| const char *name, size_t name_len) |
| { |
| size_t buf_size; |
| size_t cpy_len; |
| char *buf; |
| |
| buf = req_capsule_client_get(&req->rq_pill, field); |
| buf_size = req_capsule_get_size(&req->rq_pill, field, RCL_CLIENT); |
| |
| LASSERT(name && name_len && buf && buf_size == name_len + 1); |
| |
| cpy_len = strlcpy(buf, name, buf_size); |
| |
| LASSERT(cpy_len == name_len && lu_name_is_valid_2(buf, cpy_len)); |
| } |
| |
| void mdc_readdir_pack(struct ptlrpc_request *req, __u64 pgoff, size_t size, |
| const struct lu_fid *fid) |
| { |
| struct mdt_body *b = req_capsule_client_get(&req->rq_pill, |
| &RMF_MDT_BODY); |
| b->mbo_fid1 = *fid; |
| b->mbo_valid |= OBD_MD_FLID; |
| b->mbo_size = pgoff; /* !! */ |
| b->mbo_nlink = size; /* !! */ |
| __mdc_pack_body(b, -1); |
| b->mbo_mode = LUDA_FID | LUDA_TYPE; |
| } |
| |
| /* packing of MDS records */ |
| void mdc_create_pack(struct ptlrpc_request *req, struct md_op_data *op_data, |
| const void *data, size_t datalen, umode_t mode, |
| uid_t uid, gid_t gid, cfs_cap_t cap_effective, __u64 rdev) |
| { |
| struct mdt_rec_create *rec; |
| char *tmp; |
| __u64 flags; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_create)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| rec->cr_opcode = REINT_CREATE; |
| rec->cr_fsuid = uid; |
| rec->cr_fsgid = gid; |
| rec->cr_cap = cap_effective; |
| rec->cr_fid1 = op_data->op_fid1; |
| rec->cr_fid2 = op_data->op_fid2; |
| rec->cr_mode = mode; |
| rec->cr_rdev = rdev; |
| rec->cr_time = op_data->op_mod_time; |
| rec->cr_suppgid1 = op_data->op_suppgids[0]; |
| rec->cr_suppgid2 = op_data->op_suppgids[1]; |
| flags = 0; |
| if (op_data->op_bias & MDS_CREATE_VOLATILE) |
| flags |= MDS_OPEN_VOLATILE; |
| set_mrc_cr_flags(rec, flags); |
| rec->cr_bias = op_data->op_bias; |
| rec->cr_umask = current_umask(); |
| |
| mdc_pack_name(req, &RMF_NAME, op_data->op_name, op_data->op_namelen); |
| if (data) { |
| tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA); |
| memcpy(tmp, data, datalen); |
| } |
| } |
| |
| static inline __u64 mds_pack_open_flags(__u64 flags) |
| { |
| __u64 cr_flags = (flags & (FMODE_READ | FMODE_WRITE | |
| MDS_OPEN_FL_INTERNAL)); |
| if (flags & O_CREAT) |
| cr_flags |= MDS_OPEN_CREAT; |
| if (flags & O_EXCL) |
| cr_flags |= MDS_OPEN_EXCL; |
| if (flags & O_TRUNC) |
| cr_flags |= MDS_OPEN_TRUNC; |
| if (flags & O_APPEND) |
| cr_flags |= MDS_OPEN_APPEND; |
| if (flags & O_SYNC) |
| cr_flags |= MDS_OPEN_SYNC; |
| if (flags & O_DIRECTORY) |
| cr_flags |= MDS_OPEN_DIRECTORY; |
| if (flags & __FMODE_EXEC) |
| cr_flags |= MDS_FMODE_EXEC; |
| if (cl_is_lov_delay_create(flags)) |
| cr_flags |= MDS_OPEN_DELAY_CREATE; |
| |
| if (flags & O_NONBLOCK) |
| cr_flags |= MDS_OPEN_NORESTORE; |
| |
| return cr_flags; |
| } |
| |
| /* packing of MDS records */ |
| void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data, |
| umode_t mode, __u64 rdev, __u64 flags, const void *lmm, |
| size_t lmmlen) |
| { |
| struct mdt_rec_create *rec; |
| char *tmp; |
| __u64 cr_flags; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_create)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| /* XXX do something about time, uid, gid */ |
| rec->cr_opcode = REINT_OPEN; |
| rec->cr_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
| rec->cr_fsgid = from_kgid(&init_user_ns, current_fsgid()); |
| rec->cr_cap = cfs_curproc_cap_pack(); |
| rec->cr_fid1 = op_data->op_fid1; |
| rec->cr_fid2 = op_data->op_fid2; |
| |
| rec->cr_mode = mode; |
| cr_flags = mds_pack_open_flags(flags); |
| rec->cr_rdev = rdev; |
| rec->cr_time = op_data->op_mod_time; |
| rec->cr_suppgid1 = op_data->op_suppgids[0]; |
| rec->cr_suppgid2 = op_data->op_suppgids[1]; |
| rec->cr_bias = op_data->op_bias; |
| rec->cr_umask = current_umask(); |
| rec->cr_old_handle = op_data->op_handle; |
| |
| if (op_data->op_name) { |
| mdc_pack_name(req, &RMF_NAME, op_data->op_name, |
| op_data->op_namelen); |
| |
| if (op_data->op_bias & MDS_CREATE_VOLATILE) |
| cr_flags |= MDS_OPEN_VOLATILE; |
| } |
| |
| if (lmm) { |
| cr_flags |= MDS_OPEN_HAS_EA; |
| tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA); |
| memcpy(tmp, lmm, lmmlen); |
| } |
| set_mrc_cr_flags(rec, cr_flags); |
| } |
| |
| static inline __u64 attr_pack(unsigned int ia_valid) |
| { |
| __u64 sa_valid = 0; |
| |
| if (ia_valid & ATTR_MODE) |
| sa_valid |= MDS_ATTR_MODE; |
| if (ia_valid & ATTR_UID) |
| sa_valid |= MDS_ATTR_UID; |
| if (ia_valid & ATTR_GID) |
| sa_valid |= MDS_ATTR_GID; |
| if (ia_valid & ATTR_SIZE) |
| sa_valid |= MDS_ATTR_SIZE; |
| if (ia_valid & ATTR_ATIME) |
| sa_valid |= MDS_ATTR_ATIME; |
| if (ia_valid & ATTR_MTIME) |
| sa_valid |= MDS_ATTR_MTIME; |
| if (ia_valid & ATTR_CTIME) |
| sa_valid |= MDS_ATTR_CTIME; |
| if (ia_valid & ATTR_ATIME_SET) |
| sa_valid |= MDS_ATTR_ATIME_SET; |
| if (ia_valid & ATTR_MTIME_SET) |
| sa_valid |= MDS_ATTR_MTIME_SET; |
| if (ia_valid & ATTR_FORCE) |
| sa_valid |= MDS_ATTR_FORCE; |
| if (ia_valid & ATTR_ATTR_FLAG) |
| sa_valid |= MDS_ATTR_ATTR_FLAG; |
| if (ia_valid & ATTR_KILL_SUID) |
| sa_valid |= MDS_ATTR_KILL_SUID; |
| if (ia_valid & ATTR_KILL_SGID) |
| sa_valid |= MDS_ATTR_KILL_SGID; |
| if (ia_valid & ATTR_CTIME_SET) |
| sa_valid |= MDS_ATTR_CTIME_SET; |
| if (ia_valid & ATTR_OPEN) |
| sa_valid |= MDS_ATTR_FROM_OPEN; |
| if (ia_valid & ATTR_BLOCKS) |
| sa_valid |= MDS_ATTR_BLOCKS; |
| if (ia_valid & MDS_OPEN_OWNEROVERRIDE) |
| /* NFSD hack (see bug 5781) */ |
| sa_valid |= MDS_OPEN_OWNEROVERRIDE; |
| return sa_valid; |
| } |
| |
| static void mdc_setattr_pack_rec(struct mdt_rec_setattr *rec, |
| struct md_op_data *op_data) |
| { |
| rec->sa_opcode = REINT_SETATTR; |
| rec->sa_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
| rec->sa_fsgid = from_kgid(&init_user_ns, current_fsgid()); |
| rec->sa_cap = cfs_curproc_cap_pack(); |
| rec->sa_suppgid = -1; |
| |
| rec->sa_fid = op_data->op_fid1; |
| rec->sa_valid = attr_pack(op_data->op_attr.ia_valid); |
| rec->sa_mode = op_data->op_attr.ia_mode; |
| rec->sa_uid = from_kuid(&init_user_ns, op_data->op_attr.ia_uid); |
| rec->sa_gid = from_kgid(&init_user_ns, op_data->op_attr.ia_gid); |
| rec->sa_size = op_data->op_attr.ia_size; |
| rec->sa_blocks = op_data->op_attr_blocks; |
| rec->sa_atime = LTIME_S(op_data->op_attr.ia_atime); |
| rec->sa_mtime = LTIME_S(op_data->op_attr.ia_mtime); |
| rec->sa_ctime = LTIME_S(op_data->op_attr.ia_ctime); |
| rec->sa_attr_flags = op_data->op_attr_flags; |
| if ((op_data->op_attr.ia_valid & ATTR_GID) && |
| in_group_p(op_data->op_attr.ia_gid)) |
| rec->sa_suppgid = |
| from_kgid(&init_user_ns, op_data->op_attr.ia_gid); |
| else |
| rec->sa_suppgid = op_data->op_suppgids[0]; |
| |
| rec->sa_bias = op_data->op_bias; |
| } |
| |
| static void mdc_ioepoch_pack(struct mdt_ioepoch *epoch, |
| struct md_op_data *op_data) |
| { |
| epoch->mio_handle = op_data->op_handle; |
| epoch->mio_unused1 = 0; |
| epoch->mio_unused2 = 0; |
| epoch->mio_padding = 0; |
| } |
| |
| void mdc_setattr_pack(struct ptlrpc_request *req, struct md_op_data *op_data, |
| void *ea, size_t ealen) |
| { |
| struct mdt_rec_setattr *rec; |
| struct lov_user_md *lum = NULL; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != |
| sizeof(struct mdt_rec_setattr)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| mdc_setattr_pack_rec(rec, op_data); |
| |
| if (ealen == 0) |
| return; |
| |
| lum = req_capsule_client_get(&req->rq_pill, &RMF_EADATA); |
| if (!ea) { /* Remove LOV EA */ |
| lum->lmm_magic = cpu_to_le32(LOV_USER_MAGIC_V1); |
| lum->lmm_stripe_size = 0; |
| lum->lmm_stripe_count = 0; |
| lum->lmm_stripe_offset = (typeof(lum->lmm_stripe_offset))(-1); |
| } else { |
| memcpy(lum, ea, ealen); |
| } |
| } |
| |
| void mdc_unlink_pack(struct ptlrpc_request *req, struct md_op_data *op_data) |
| { |
| struct mdt_rec_unlink *rec; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_unlink)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| rec->ul_opcode = op_data->op_cli_flags & CLI_RM_ENTRY ? |
| REINT_RMENTRY : REINT_UNLINK; |
| rec->ul_fsuid = op_data->op_fsuid; |
| rec->ul_fsgid = op_data->op_fsgid; |
| rec->ul_cap = op_data->op_cap; |
| rec->ul_mode = op_data->op_mode; |
| rec->ul_suppgid1 = op_data->op_suppgids[0]; |
| rec->ul_suppgid2 = -1; |
| rec->ul_fid1 = op_data->op_fid1; |
| rec->ul_fid2 = op_data->op_fid2; |
| rec->ul_time = op_data->op_mod_time; |
| rec->ul_bias = op_data->op_bias; |
| |
| mdc_pack_name(req, &RMF_NAME, op_data->op_name, op_data->op_namelen); |
| } |
| |
| void mdc_link_pack(struct ptlrpc_request *req, struct md_op_data *op_data) |
| { |
| struct mdt_rec_link *rec; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_link)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| rec->lk_opcode = REINT_LINK; |
| rec->lk_fsuid = op_data->op_fsuid; /* current->fsuid; */ |
| rec->lk_fsgid = op_data->op_fsgid; /* current->fsgid; */ |
| rec->lk_cap = op_data->op_cap; /* current->cap_effective; */ |
| rec->lk_suppgid1 = op_data->op_suppgids[0]; |
| rec->lk_suppgid2 = op_data->op_suppgids[1]; |
| rec->lk_fid1 = op_data->op_fid1; |
| rec->lk_fid2 = op_data->op_fid2; |
| rec->lk_time = op_data->op_mod_time; |
| rec->lk_bias = op_data->op_bias; |
| |
| mdc_pack_name(req, &RMF_NAME, op_data->op_name, op_data->op_namelen); |
| } |
| |
| static void mdc_intent_close_pack(struct ptlrpc_request *req, |
| struct md_op_data *op_data) |
| { |
| enum mds_op_bias bias = op_data->op_bias; |
| struct close_data *data; |
| struct ldlm_lock *lock; |
| |
| if (!(bias & (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP | |
| MDS_RENAME_MIGRATE))) |
| return; |
| |
| data = req_capsule_client_get(&req->rq_pill, &RMF_CLOSE_DATA); |
| LASSERT(data); |
| |
| lock = ldlm_handle2lock(&op_data->op_lease_handle); |
| if (lock) { |
| data->cd_handle = lock->l_remote_handle; |
| LDLM_LOCK_PUT(lock); |
| } |
| ldlm_cli_cancel(&op_data->op_lease_handle, LCF_LOCAL); |
| |
| data->cd_data_version = op_data->op_data_version; |
| data->cd_fid = op_data->op_fid2; |
| } |
| |
| void mdc_rename_pack(struct ptlrpc_request *req, struct md_op_data *op_data, |
| const char *old, size_t oldlen, |
| const char *new, size_t newlen) |
| { |
| struct mdt_rec_rename *rec; |
| |
| BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_rename)); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| /* XXX do something about time, uid, gid */ |
| rec->rn_opcode = op_data->op_cli_flags & CLI_MIGRATE ? |
| REINT_MIGRATE : REINT_RENAME; |
| rec->rn_opcode = REINT_RENAME; |
| rec->rn_fsuid = op_data->op_fsuid; |
| rec->rn_fsgid = op_data->op_fsgid; |
| rec->rn_cap = op_data->op_cap; |
| rec->rn_suppgid1 = op_data->op_suppgids[0]; |
| rec->rn_suppgid2 = op_data->op_suppgids[1]; |
| rec->rn_fid1 = op_data->op_fid1; |
| rec->rn_fid2 = op_data->op_fid2; |
| rec->rn_time = op_data->op_mod_time; |
| rec->rn_mode = op_data->op_mode; |
| rec->rn_bias = op_data->op_bias; |
| |
| mdc_pack_name(req, &RMF_NAME, old, oldlen); |
| |
| if (new) |
| mdc_pack_name(req, &RMF_SYMTGT, new, newlen); |
| |
| if (op_data->op_cli_flags & CLI_MIGRATE && |
| op_data->op_bias & MDS_RENAME_MIGRATE) { |
| struct mdt_ioepoch *epoch; |
| |
| mdc_intent_close_pack(req, op_data); |
| epoch = req_capsule_client_get(&req->rq_pill, &RMF_MDT_EPOCH); |
| mdc_ioepoch_pack(epoch, op_data); |
| } |
| } |
| |
| void mdc_getattr_pack(struct ptlrpc_request *req, __u64 valid, u32 flags, |
| struct md_op_data *op_data, size_t ea_size) |
| { |
| struct mdt_body *b = req_capsule_client_get(&req->rq_pill, |
| &RMF_MDT_BODY); |
| |
| b->mbo_valid = valid; |
| if (op_data->op_bias & MDS_CHECK_SPLIT) |
| b->mbo_valid |= OBD_MD_FLCKSPLIT; |
| if (op_data->op_bias & MDS_CROSS_REF) |
| b->mbo_valid |= OBD_MD_FLCROSSREF; |
| b->mbo_eadatasize = ea_size; |
| b->mbo_flags = flags; |
| __mdc_pack_body(b, op_data->op_suppgids[0]); |
| |
| b->mbo_fid1 = op_data->op_fid1; |
| b->mbo_fid2 = op_data->op_fid2; |
| b->mbo_valid |= OBD_MD_FLID; |
| |
| if (op_data->op_name) |
| mdc_pack_name(req, &RMF_NAME, op_data->op_name, |
| op_data->op_namelen); |
| } |
| |
| void mdc_close_pack(struct ptlrpc_request *req, struct md_op_data *op_data) |
| { |
| struct mdt_ioepoch *epoch; |
| struct mdt_rec_setattr *rec; |
| |
| epoch = req_capsule_client_get(&req->rq_pill, &RMF_MDT_EPOCH); |
| rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); |
| |
| mdc_setattr_pack_rec(rec, op_data); |
| /* |
| * The client will zero out local timestamps when losing the IBITS lock |
| * so any new RPC timestamps will update the client inode's timestamps. |
| * There was a defect on the server side which allowed the atime to be |
| * overwritten by a zeroed-out atime packed into the close RPC. |
| * |
| * Proactively clear the MDS_ATTR_ATIME flag in the RPC in this case |
| * to avoid zeroing the atime on old unpatched servers. See LU-8041. |
| */ |
| if (rec->sa_atime == 0) |
| rec->sa_valid &= ~MDS_ATTR_ATIME; |
| |
| mdc_ioepoch_pack(epoch, op_data); |
| mdc_intent_close_pack(req, op_data); |
| } |