static int mdt_setattr_unpack_rec(struct mdt_thread_info *info) { 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; ENTRY; 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); /* 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); /* If MDS_ATTR_xTIME is set without MDS_ATTR_xTIME_SET and * the client does not have OBD_CONNECT_FULL20, convert it * to LA_xTIME. LU-3036 */ if (!(exp_connect_flags(info->mti_exp) & OBD_CONNECT_FULL20)) { if (!(rec->sa_valid & MDS_ATTR_ATIME_SET) && (rec->sa_valid & MDS_ATTR_ATIME)) la->la_valid |= LA_ATIME; if (!(rec->sa_valid & MDS_ATTR_MTIME_SET) && (rec->sa_valid & MDS_ATTR_MTIME)) la->la_valid |= LA_MTIME; if (!(rec->sa_valid & MDS_ATTR_CTIME_SET) && (rec->sa_valid & MDS_ATTR_CTIME)) la->la_valid |= LA_CTIME; } 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 (rec->sa_bias & MDS_DATA_MODIFIED) ma->ma_attr_flags |= MDS_DATA_MODIFIED; else ma->ma_attr_flags &= ~MDS_DATA_MODIFIED; 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); }
static int mdt_create_pack_capa(struct mdt_thread_info *info, int rc, struct mdt_object *object, struct mdt_body *repbody) { ENTRY; /* for cross-ref mkdir, mds capa has been fetched from remote obj, then * we won't go to below*/ if (repbody->valid & OBD_MD_FLMDSCAPA) RETURN(rc); if (rc == 0 && info->mti_mdt->mdt_opts.mo_mds_capa && exp_connect_flags(info->mti_exp) & OBD_CONNECT_MDS_CAPA) { struct lustre_capa *capa; capa = req_capsule_server_get(info->mti_pill, &RMF_CAPA1); LASSERT(capa); capa->lc_opc = CAPA_OPC_MDS_DEFAULT; rc = mo_capa_get(info->mti_env, mdt_object_child(object), capa, 0); if (rc == 0) repbody->valid |= OBD_MD_FLMDSCAPA; } RETURN(rc); }
void mdt_set_capainfo(struct mdt_thread_info *info, int offset, const struct lu_fid *fid, struct lustre_capa *capa) { struct lu_capainfo *lci; LASSERT(offset >= 0 && offset < LU_CAPAINFO_MAX); if (!info->mti_mdt->mdt_lut.lut_mds_capa || !(exp_connect_flags(info->mti_exp) & OBD_CONNECT_MDS_CAPA)) return; lci = lu_capainfo_get(info->mti_env); LASSERT(lci); lci->lci_fid[offset] = *fid; lci->lci_capa[offset] = capa; }
/* if object is dying, pack the lov/llog data, * parameter info->mti_attr should be valid at this point! */ int mdt_handle_last_unlink(struct mdt_thread_info *info, struct mdt_object *mo, const struct md_attr *ma) { struct mdt_body *repbody; const struct lu_attr *la = &ma->ma_attr; int rc; ENTRY; 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) { CERROR("No need in LOV EA upon unlink\n"); dump_stack(); } repbody->eadatasize = 0; if (ma->ma_cookie_size && (ma->ma_valid & MA_COOKIE)) { repbody->aclsize = ma->ma_cookie_size; repbody->valid |= OBD_MD_FLCOOKIE; } if (info->mti_mdt->mdt_opts.mo_oss_capa && exp_connect_flags(info->mti_exp) & OBD_CONNECT_OSS_CAPA && repbody->valid & OBD_MD_FLEASIZE) { struct lustre_capa *capa; capa = req_capsule_server_get(info->mti_pill, &RMF_CAPA2); LASSERT(capa); capa->lc_opc = CAPA_OPC_OSS_DESTROY; rc = mo_capa_get(info->mti_env, mdt_object_child(mo), capa, 0); if (rc) RETURN(rc); repbody->valid |= OBD_MD_FLOSSCAPA; } RETURN(0); }
/** * Implementation of obd_ops::o_destroy_export. * * This function is called from class_export_destroy() to cleanup * the OFD-specific data for export being destroyed. * * \param[in] exp OBD export * * \retval 0 if successful * \retval negative value on error */ static int ofd_destroy_export(struct obd_export *exp) { struct ofd_device *ofd = ofd_exp(exp); if (exp->exp_filter_data.fed_pending) CERROR("%s: cli %s/%p has %lu pending on destroyed export" "\n", exp->exp_obd->obd_name, exp->exp_client_uuid.uuid, exp, exp->exp_filter_data.fed_pending); target_destroy_export(exp); if (unlikely(obd_uuid_equals(&exp->exp_obd->obd_uuid, &exp->exp_client_uuid))) return 0; ldlm_destroy_export(exp); tgt_client_free(exp); ofd_fmd_cleanup(exp); /* * discard grants once we're sure no more * interaction with the client is possible */ ofd_grant_discard(exp); ofd_fmd_cleanup(exp); if (exp_connect_flags(exp) & OBD_CONNECT_GRANT_SHRINK) { if (ofd->ofd_tot_granted_clients > 0) ofd->ofd_tot_granted_clients --; } if (!(exp->exp_flags & OBD_OPT_FORCE)) ofd_grant_sanity_check(exp->exp_obd, __FUNCTION__); LASSERT(list_empty(&exp->exp_filter_data.fed_mod_list)); return 0; }
/* return EADATA length to the caller. negative value means error */ static int mdt_getxattr_pack_reply(struct mdt_thread_info * info) { struct req_capsule *pill = info->mti_pill ; struct ptlrpc_request *req = mdt_info_req(info); char *xattr_name; __u64 valid; static const char user_string[] = "user."; int size, rc; ENTRY; if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETXATTR_PACK)) RETURN(-ENOMEM); valid = info->mti_body->valid & (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS); /* Determine how many bytes we need */ if (valid == OBD_MD_FLXATTR) { xattr_name = req_capsule_client_get(pill, &RMF_NAME); if (!xattr_name) RETURN(-EFAULT); if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR) && !strncmp(xattr_name, user_string, sizeof(user_string) - 1)) RETURN(-EOPNOTSUPP); size = mo_xattr_get(info->mti_env, mdt_object_child(info->mti_object), &LU_BUF_NULL, xattr_name); } else if (valid == OBD_MD_FLXATTRLS) { size = mo_xattr_list(info->mti_env, mdt_object_child(info->mti_object), &LU_BUF_NULL); } else if (valid == OBD_MD_FLXATTRALL) { /* N.B. eadatasize = 0 is not valid for FLXATTRALL */ /* We could calculate accurate sizes, but this would * introduce a lot of overhead, let's do it later... */ size = info->mti_body->eadatasize; req_capsule_set_size(pill, &RMF_EAVALS, RCL_SERVER, size); req_capsule_set_size(pill, &RMF_EAVALS_LENS, RCL_SERVER, size); } else { CDEBUG(D_INFO, "Valid bits: "LPX64"\n", info->mti_body->valid); RETURN(-EINVAL); } if (size == -ENODATA) { size = 0; } else if (size < 0) { CERROR("Error geting EA size: %d\n", size); RETURN(size); } req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER, info->mti_body->eadatasize == 0 ? 0 : size); rc = req_capsule_server_pack(pill); if (rc) { LASSERT(rc < 0); RETURN(rc); } RETURN(size); }
int mdt_reint_setxattr(struct mdt_thread_info *info, struct mdt_lock_handle *unused) { struct ptlrpc_request *req = mdt_info_req(info); struct lu_ucred *uc = lu_ucred(info->mti_env); struct mdt_lock_handle *lh; const struct lu_env *env = info->mti_env; struct lu_buf *buf = &info->mti_buf; struct mdt_reint_record *rr = &info->mti_rr; struct md_attr *ma = &info->mti_attr; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_object *obj; struct md_object *child; __u64 valid = attr->la_valid; const char *xattr_name = rr->rr_name.ln_name; int xattr_len = rr->rr_eadatalen; __u64 lockpart; int rc; posix_acl_xattr_header *new_xattr = NULL; __u32 remote = exp_connect_rmtclient(info->mti_exp); __u32 perm; ENTRY; CDEBUG(D_INODE, "setxattr for "DFID"\n", PFID(rr->rr_fid1)); if (info->mti_dlm_req) ldlm_request_cancel(req, info->mti_dlm_req, 0); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR)) RETURN(err_serious(-ENOMEM)); CDEBUG(D_INODE, "%s xattr %s\n", valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name); rc = mdt_init_ucred_reint(info); if (rc != 0) RETURN(rc); if (valid & OBD_MD_FLRMTRSETFACL) { if (unlikely(!remote)) GOTO(out, rc = err_serious(-EINVAL)); perm = mdt_identity_get_perm(uc->uc_identity, remote, req->rq_peer.nid); if (!(perm & CFS_RMTACL_PERM)) GOTO(out, rc = err_serious(-EPERM)); } if (strncmp(xattr_name, XATTR_USER_PREFIX, sizeof(XATTR_USER_PREFIX) - 1) == 0) { if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR)) GOTO(out, rc = -EOPNOTSUPP); } else if (strncmp(xattr_name, XATTR_TRUSTED_PREFIX, sizeof(XATTR_TRUSTED_PREFIX) - 1) == 0) { if (!md_capable(mdt_ucred(info), CFS_CAP_SYS_ADMIN)) GOTO(out, rc = -EPERM); if (strcmp(xattr_name, XATTR_NAME_LOV) == 0 || strcmp(xattr_name, XATTR_NAME_LMA) == 0 || strcmp(xattr_name, XATTR_NAME_LMV) == 0 || strcmp(xattr_name, XATTR_NAME_LINK) == 0 || strcmp(xattr_name, XATTR_NAME_FID) == 0 || strcmp(xattr_name, XATTR_NAME_VERSION) == 0 || strcmp(xattr_name, XATTR_NAME_SOM) == 0 || strcmp(xattr_name, XATTR_NAME_HSM) == 0 || strcmp(xattr_name, XATTR_NAME_LFSCK_NAMESPACE) == 0) GOTO(out, rc = 0); } else if ((valid & OBD_MD_FLXATTR) && (strcmp(xattr_name, XATTR_NAME_ACL_ACCESS) == 0 || strcmp(xattr_name, XATTR_NAME_ACL_DEFAULT) == 0)) { /* currently lustre limit acl access size */ if (xattr_len > LUSTRE_POSIX_ACL_MAX_SIZE) GOTO(out, rc = -ERANGE); } lockpart = MDS_INODELOCK_UPDATE; /* Revoke all clients' lookup lock, since the access * permissions for this inode is changed when ACL_ACCESS is * set. This isn't needed for ACL_DEFAULT, since that does * not change the access permissions of this inode, nor any * other existing inodes. It is setting the ACLs inherited * by new directories/files at create time. */ /* We need revoke both LOOKUP|PERM lock here, see mdt_attr_set. */ if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS)) lockpart |= MDS_INODELOCK_PERM | MDS_INODELOCK_LOOKUP; /* We need to take the lock on behalf of old clients so that newer * clients flush their xattr caches */ else lockpart |= MDS_INODELOCK_XATTR; lh = &info->mti_lh[MDT_LH_PARENT]; /* ACLs were sent to clients under LCK_CR locks, so taking LCK_EX * to cancel them. */ mdt_lock_reg_init(lh, LCK_EX); obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart); if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); tgt_vbr_obj_set(env, mdt_obj2dt(obj)); rc = mdt_version_get_check_save(info, obj, 0); if (rc) GOTO(out_unlock, rc); if (unlikely(!(valid & OBD_MD_FLCTIME))) { /* This isn't strictly an error, but all current clients * should set OBD_MD_FLCTIME when setting attributes. */ CWARN("%s: client miss to set OBD_MD_FLCTIME when " "setxattr %s: [object "DFID"] [valid "LPU64"]\n", mdt_obd_name(info->mti_mdt), xattr_name, PFID(rr->rr_fid1), valid); attr->la_ctime = cfs_time_current_sec(); } attr->la_valid = LA_CTIME; child = mdt_object_child(obj); if (valid & OBD_MD_FLXATTR) { char *xattr = (void *)rr->rr_eadata; if (xattr_len > 0) { int flags = 0; if (valid & OBD_MD_FLRMTLSETFACL) { if (unlikely(!remote)) GOTO(out_unlock, rc = -EINVAL); xattr_len = mdt_rmtlsetfacl(info, child, xattr_name, (ext_acl_xattr_header *)xattr, &new_xattr); if (xattr_len < 0) GOTO(out_unlock, rc = xattr_len); xattr = (char *)new_xattr; } if (attr->la_flags & XATTR_REPLACE) flags |= LU_XATTR_REPLACE; if (attr->la_flags & XATTR_CREATE) flags |= LU_XATTR_CREATE; mdt_fail_write(env, info->mti_mdt->mdt_bottom, OBD_FAIL_MDS_SETXATTR_WRITE); buf->lb_buf = xattr; buf->lb_len = xattr_len; rc = mo_xattr_set(env, child, buf, xattr_name, flags); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } } else if (valid & OBD_MD_FLXATTRRM) { rc = mo_xattr_del(env, child, xattr_name); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } else { CDEBUG(D_INFO, "valid bits: "LPX64"\n", valid); rc = -EINVAL; } if (rc == 0) mdt_counter_incr(req, LPROC_MDT_SETXATTR); EXIT; out_unlock: mdt_object_unlock_put(info, obj, lh, rc); if (unlikely(new_xattr != NULL)) lustre_posix_acl_xattr_free(new_xattr, xattr_len); out: mdt_exit_ucred(info); return rc; }
/* return EADATA length to the caller. negative value means error */ static int mdt_getxattr_pack_reply(struct mdt_thread_info * info) { struct req_capsule *pill = info->mti_pill; struct ptlrpc_request *req = mdt_info_req(info); const char *xattr_name; u64 valid; static const char user_string[] = "user."; int size; int rc = 0; int rc2; ENTRY; valid = info->mti_body->mbo_valid & (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS); /* Determine how many bytes we need */ if (valid == OBD_MD_FLXATTR) { xattr_name = req_capsule_client_get(pill, &RMF_NAME); if (!xattr_name) RETURN(-EFAULT); if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR) && !strncmp(xattr_name, user_string, sizeof(user_string) - 1)) RETURN(-EOPNOTSUPP); size = mo_xattr_get(info->mti_env, mdt_object_child(info->mti_object), &LU_BUF_NULL, xattr_name); if (size == -ENODATA) { /* XXX: Some client code will not handle -ENODATA * for XATTR_NAME_LOV (trusted.lov) properly. */ if (strcmp(xattr_name, XATTR_NAME_LOV) == 0) rc = 0; else rc = -ENODATA; size = 0; } } else if (valid == OBD_MD_FLXATTRLS) { xattr_name = "list"; size = mo_xattr_list(info->mti_env, mdt_object_child(info->mti_object), &LU_BUF_NULL); } else if (valid == OBD_MD_FLXATTRALL) { xattr_name = "all"; /* N.B. eadatasize = 0 is not valid for FLXATTRALL */ /* We could calculate accurate sizes, but this would * introduce a lot of overhead, let's do it later... */ size = info->mti_body->mbo_eadatasize; req_capsule_set_size(pill, &RMF_EAVALS, RCL_SERVER, size); req_capsule_set_size(pill, &RMF_EAVALS_LENS, RCL_SERVER, size); } else { CDEBUG(D_INFO, "Valid bits: %#llx\n", info->mti_body->mbo_valid); RETURN(-EINVAL); } if (size < 0) { if (size != -EOPNOTSUPP && size != -ENOENT) CERROR("%s: error geting EA size for '%s': rc = %d\n", mdt_obd_name(info->mti_mdt), xattr_name, size); RETURN(size); } if (req_capsule_has_field(pill, &RMF_ACL, RCL_SERVER)) req_capsule_set_size(pill, &RMF_ACL, RCL_SERVER, LUSTRE_POSIX_ACL_MAX_SIZE_OLD); req_capsule_set_size(pill, &RMF_EADATA, RCL_SERVER, info->mti_body->mbo_eadatasize == 0 ? 0 : size); rc2 = req_capsule_server_pack(pill); if (rc2 < 0) RETURN(rc2); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETXATTR_PACK)) RETURN(-ENOMEM); RETURN(rc < 0 ? rc : size); }
int mdt_reint_setxattr(struct mdt_thread_info *info, struct mdt_lock_handle *unused) { struct ptlrpc_request *req = mdt_info_req(info); struct mdt_lock_handle *lh; const struct lu_env *env = info->mti_env; struct lu_buf *buf = &info->mti_buf; struct mdt_reint_record *rr = &info->mti_rr; struct md_attr *ma = &info->mti_attr; struct lu_attr *attr = &info->mti_attr.ma_attr; struct mdt_object *obj; struct md_object *child; __u64 valid = attr->la_valid; const char *xattr_name = rr->rr_name.ln_name; int xattr_len = rr->rr_eadatalen; __u64 lockpart = MDS_INODELOCK_UPDATE; int rc; ENTRY; CDEBUG(D_INODE, "setxattr for "DFID": %s %s\n", PFID(rr->rr_fid1), valid & OBD_MD_FLXATTR ? "set" : "remove", xattr_name); if (info->mti_dlm_req) ldlm_request_cancel(req, info->mti_dlm_req, 0, LATF_SKIP); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_SETXATTR)) RETURN(err_serious(-ENOMEM)); rc = mdt_init_ucred_reint(info); if (rc != 0) RETURN(rc); if (strncmp(xattr_name, XATTR_USER_PREFIX, sizeof(XATTR_USER_PREFIX) - 1) == 0) { if (!(exp_connect_flags(req->rq_export) & OBD_CONNECT_XATTR)) GOTO(out, rc = -EOPNOTSUPP); } else if (strncmp(xattr_name, XATTR_TRUSTED_PREFIX, sizeof(XATTR_TRUSTED_PREFIX) - 1) == 0) { /* setxattr(LMV) with lum is used to shrink dir layout */ if (strcmp(xattr_name, XATTR_NAME_LMV) == 0) { __u32 *magic = rr->rr_eadata; /* we don't let to remove LMV? */ if (!rr->rr_eadata) GOTO(out, rc = 0); if (le32_to_cpu(*magic) == LMV_USER_MAGIC || le32_to_cpu(*magic) == LMV_USER_MAGIC_SPECIFIC) { rc = mdt_dir_layout_shrink(info); GOTO(out, rc); } } if (!md_capable(mdt_ucred(info), CFS_CAP_SYS_ADMIN)) GOTO(out, rc = -EPERM); if (strcmp(xattr_name, XATTR_NAME_LOV) == 0 || strcmp(xattr_name, XATTR_NAME_LMA) == 0 || strcmp(xattr_name, XATTR_NAME_LMV) == 0 || strcmp(xattr_name, XATTR_NAME_LINK) == 0 || strcmp(xattr_name, XATTR_NAME_FID) == 0 || strcmp(xattr_name, XATTR_NAME_VERSION) == 0 || strcmp(xattr_name, XATTR_NAME_SOM) == 0 || strcmp(xattr_name, XATTR_NAME_HSM) == 0 || strcmp(xattr_name, XATTR_NAME_LFSCK_NAMESPACE) == 0) GOTO(out, rc = 0); } else if ((valid & OBD_MD_FLXATTR) && (strcmp(xattr_name, XATTR_NAME_ACL_ACCESS) == 0 || strcmp(xattr_name, XATTR_NAME_ACL_DEFAULT) == 0)) { rc = mdt_nodemap_map_acl(info, rr->rr_eadata, xattr_len, xattr_name, NODEMAP_CLIENT_TO_FS); if (rc < 0) GOTO(out, rc); /* ACLs were mapped out, return an error so the user knows */ if (rc != xattr_len) GOTO(out, rc = -EPERM); } else if ((strlen(xattr_name) > strlen(XATTR_LUSTRE_LOV) + 1) && strncmp(xattr_name, XATTR_LUSTRE_LOV, strlen(XATTR_LUSTRE_LOV)) == 0) { if (strncmp(xattr_name, XATTR_LUSTRE_LOV".add", strlen(XATTR_LUSTRE_LOV".add")) && strncmp(xattr_name, XATTR_LUSTRE_LOV".set", strlen(XATTR_LUSTRE_LOV".set")) && strncmp(xattr_name, XATTR_LUSTRE_LOV".del", strlen(XATTR_LUSTRE_LOV".del"))) { CERROR("%s: invalid xattr name: %s\n", mdt_obd_name(info->mti_mdt), xattr_name); GOTO(out, rc = -EINVAL); } lockpart |= MDS_INODELOCK_LAYOUT; } /* Revoke all clients' lookup lock, since the access * permissions for this inode is changed when ACL_ACCESS is * set. This isn't needed for ACL_DEFAULT, since that does * not change the access permissions of this inode, nor any * other existing inodes. It is setting the ACLs inherited * by new directories/files at create time. */ /* We need revoke both LOOKUP|PERM lock here, see mdt_attr_set. */ if (!strcmp(xattr_name, XATTR_NAME_ACL_ACCESS)) lockpart |= MDS_INODELOCK_PERM | MDS_INODELOCK_LOOKUP; /* We need to take the lock on behalf of old clients so that newer * clients flush their xattr caches */ else lockpart |= MDS_INODELOCK_XATTR; lh = &info->mti_lh[MDT_LH_PARENT]; /* ACLs were sent to clients under LCK_CR locks, so taking LCK_EX * to cancel them. */ mdt_lock_reg_init(lh, LCK_EX); obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart); if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); tgt_vbr_obj_set(env, mdt_obj2dt(obj)); rc = mdt_version_get_check_save(info, obj, 0); if (rc) GOTO(out_unlock, rc); if (unlikely(!(valid & OBD_MD_FLCTIME))) { /* This isn't strictly an error, but all current clients * should set OBD_MD_FLCTIME when setting attributes. */ CWARN("%s: client miss to set OBD_MD_FLCTIME when " "setxattr %s: [object "DFID"] [valid %llu]\n", mdt_obd_name(info->mti_mdt), xattr_name, PFID(rr->rr_fid1), valid); attr->la_ctime = ktime_get_real_seconds(); } attr->la_valid = LA_CTIME; child = mdt_object_child(obj); if (valid & OBD_MD_FLXATTR) { int flags = 0; if (attr->la_flags & XATTR_REPLACE) flags |= LU_XATTR_REPLACE; if (attr->la_flags & XATTR_CREATE) flags |= LU_XATTR_CREATE; mdt_fail_write(env, info->mti_mdt->mdt_bottom, OBD_FAIL_MDS_SETXATTR_WRITE); buf->lb_buf = rr->rr_eadata; buf->lb_len = xattr_len; rc = mo_xattr_set(env, child, buf, xattr_name, flags); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } else if (valid & OBD_MD_FLXATTRRM) { rc = mo_xattr_del(env, child, xattr_name); /* update ctime after xattr changed */ if (rc == 0) { ma->ma_attr_flags |= MDS_PERM_BYPASS; mo_attr_set(env, child, ma); } } else { CDEBUG(D_INFO, "valid bits: %#llx\n", valid); rc = -EINVAL; } if (rc == 0) mdt_counter_incr(req, LPROC_MDT_SETXATTR); EXIT; out_unlock: mdt_object_unlock_put(info, obj, lh, rc); out: mdt_exit_ucred(info); return rc; }
/* * last_rcvd & last_committed update callbacks */ static int ofd_last_rcvd_update(struct ofd_thread_info *info, struct thandle *th) { struct ofd_device *ofd = ofd_exp(info->fti_exp); struct filter_export_data *fed; struct lsd_client_data *lcd; __s32 rc = th->th_result; __u64 *transno_p; loff_t off; int err; bool lw_client = false; ENTRY; LASSERT(ofd); LASSERT(info->fti_exp); if (exp_connect_flags(info->fti_exp) & OBD_CONNECT_LIGHTWEIGHT) lw_client = true; fed = &info->fti_exp->exp_filter_data; LASSERT(fed); lcd = fed->fed_ted.ted_lcd; /* if the export has already been disconnected, we have no last_rcvd * slot, update server data with latest transno then */ if (lcd == NULL) { CWARN("commit transaction for disconnected client %s: rc %d\n", info->fti_exp->exp_client_uuid.uuid, rc); err = tgt_server_data_write(info->fti_env, &ofd->ofd_lut, th); RETURN(err); } /* ofd connect may cause transaction before export has last_rcvd * slot */ if (fed->fed_ted.ted_lr_idx < 0 && !lw_client) RETURN(0); off = fed->fed_ted.ted_lr_off; transno_p = &lcd->lcd_last_transno; lcd->lcd_last_xid = info->fti_xid; /* * When we store zero transno in mcd we can lost last transno value * because mcd contains 0, but msd is not yet written * The server data should be updated also if the latest * transno is rewritten by zero. See the bug 11125 for details. */ if (info->fti_transno == 0 && *transno_p == ofd->ofd_lut.lut_last_transno) { spin_lock(&ofd->ofd_lut.lut_translock); ofd->ofd_lut.lut_lsd.lsd_last_transno = ofd->ofd_lut.lut_last_transno; spin_unlock(&ofd->ofd_lut.lut_translock); tgt_server_data_write(info->fti_env, &ofd->ofd_lut, th); } *transno_p = info->fti_transno; if (lw_client) { /* Although lightweight (LW) connections have no slot in * last_rcvd, we still want to maintain the in-memory * lsd_client_data structure in order to properly handle reply * reconstruction. */ struct lu_target *tg =&ofd->ofd_lut; bool update = false; err = 0; /* All operations performed by LW clients are synchronous and * we store the committed transno in the last_rcvd header */ spin_lock(&tg->lut_translock); if (info->fti_transno > tg->lut_lsd.lsd_last_transno) { tg->lut_lsd.lsd_last_transno = info->fti_transno; update = true; } spin_unlock(&tg->lut_translock); if (update) err = tgt_server_data_write(info->fti_env, tg, th); } else { LASSERT(fed->fed_ted.ted_lr_off > 0); err = tgt_client_data_write(info->fti_env, &ofd->ofd_lut, lcd, &off, th); } RETURN(err); }
static int mdt_reint_setattr(struct mdt_thread_info *info, struct mdt_lock_handle *lhc) { struct md_attr *ma = &info->mti_attr; struct mdt_reint_record *rr = &info->mti_rr; struct ptlrpc_request *req = mdt_info_req(info); struct mdt_export_data *med = &req->rq_export->exp_mdt_data; struct mdt_file_data *mfd; struct mdt_object *mo; struct mdt_body *repbody; int som_au, rc, rc2; ENTRY; DEBUG_REQ(D_INODE, req, "setattr "DFID" %x", PFID(rr->rr_fid1), (unsigned int)ma->ma_attr.la_valid); if (info->mti_dlm_req) ldlm_request_cancel(req, info->mti_dlm_req, 0); repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY); mo = mdt_object_find(info->mti_env, info->mti_mdt, rr->rr_fid1); if (IS_ERR(mo)) GOTO(out, rc = PTR_ERR(mo)); if (mdt_object_obf(mo)) GOTO(out_put, rc = -EPERM); /* start a log jounal handle if needed */ if (!(mdt_conn_flags(info) & OBD_CONNECT_SOM)) { if ((ma->ma_attr.la_valid & LA_SIZE) || (rr->rr_flags & MRF_OPEN_TRUNC)) { /* Check write access for the O_TRUNC case */ if (mdt_write_read(mo) < 0) GOTO(out_put, rc = -ETXTBSY); } } else if (info->mti_ioepoch && (info->mti_ioepoch->flags & MF_EPOCH_OPEN)) { /* Truncate case. IOEpoch is opened. */ rc = mdt_write_get(mo); if (rc) GOTO(out_put, rc); mfd = mdt_mfd_new(); if (mfd == NULL) { mdt_write_put(mo); GOTO(out_put, rc = -ENOMEM); } mdt_ioepoch_open(info, mo, 0); repbody->ioepoch = mo->mot_ioepoch; mdt_object_get(info->mti_env, mo); mdt_mfd_set_mode(mfd, MDS_FMODE_TRUNC); mfd->mfd_object = mo; mfd->mfd_xid = req->rq_xid; spin_lock(&med->med_open_lock); cfs_list_add(&mfd->mfd_list, &med->med_open_head); spin_unlock(&med->med_open_lock); repbody->handle.cookie = mfd->mfd_handle.h_cookie; } som_au = info->mti_ioepoch && info->mti_ioepoch->flags & MF_SOM_CHANGE; if (som_au) { /* SOM Attribute update case. Find the proper mfd and update * SOM attributes on the proper object. */ LASSERT(mdt_conn_flags(info) & OBD_CONNECT_SOM); LASSERT(info->mti_ioepoch); spin_lock(&med->med_open_lock); mfd = mdt_handle2mfd(info, &info->mti_ioepoch->handle); if (mfd == NULL) { spin_unlock(&med->med_open_lock); CDEBUG(D_INODE, "no handle for file close: " "fid = "DFID": cookie = "LPX64"\n", PFID(info->mti_rr.rr_fid1), info->mti_ioepoch->handle.cookie); GOTO(out_put, rc = -ESTALE); } LASSERT(mfd->mfd_mode == MDS_FMODE_SOM); LASSERT(!(info->mti_ioepoch->flags & MF_EPOCH_CLOSE)); class_handle_unhash(&mfd->mfd_handle); cfs_list_del_init(&mfd->mfd_list); spin_unlock(&med->med_open_lock); mdt_mfd_close(info, mfd); } else if ((ma->ma_valid & MA_INODE) && ma->ma_attr.la_valid) { LASSERT((ma->ma_valid & MA_LOV) == 0); rc = mdt_attr_set(info, mo, ma, rr->rr_flags); if (rc) GOTO(out_put, rc); } else if ((ma->ma_valid & MA_LOV) && (ma->ma_valid & MA_INODE)) { struct lu_buf *buf = &info->mti_buf; LASSERT(ma->ma_attr.la_valid == 0); buf->lb_buf = ma->ma_lmm; buf->lb_len = ma->ma_lmm_size; rc = mo_xattr_set(info->mti_env, mdt_object_child(mo), buf, XATTR_NAME_LOV, 0); if (rc) GOTO(out_put, rc); } else LBUG(); /* If file data is modified, add the dirty flag */ if (ma->ma_attr_flags & MDS_DATA_MODIFIED) rc = mdt_add_dirty_flag(info, mo, ma); ma->ma_need = MA_INODE; ma->ma_valid = 0; rc = mdt_attr_get_complex(info, mo, ma); if (rc != 0) GOTO(out_put, rc); mdt_pack_attr2body(info, repbody, &ma->ma_attr, mdt_object_fid(mo)); if (info->mti_mdt->mdt_opts.mo_oss_capa && exp_connect_flags(info->mti_exp) & OBD_CONNECT_OSS_CAPA && S_ISREG(lu_object_attr(&mo->mot_obj.mo_lu)) && (ma->ma_attr.la_valid & LA_SIZE) && !som_au) { struct lustre_capa *capa; capa = req_capsule_server_get(info->mti_pill, &RMF_CAPA2); LASSERT(capa); capa->lc_opc = CAPA_OPC_OSS_DEFAULT | CAPA_OPC_OSS_TRUNC; rc = mo_capa_get(info->mti_env, mdt_object_child(mo), capa, 0); if (rc) GOTO(out_put, rc); repbody->valid |= OBD_MD_FLOSSCAPA; } EXIT; out_put: mdt_object_put(info->mti_env, mo); out: if (rc == 0) mdt_counter_incr(req, LPROC_MDT_SETATTR); mdt_client_compatibility(info); rc2 = mdt_fix_reply(info); if (rc == 0) rc = rc2; return rc; }