static inline int out_check_resent(const struct lu_env *env, struct dt_device *dt, struct dt_object *obj, struct ptlrpc_request *req, out_reconstruct_t reconstruct, struct object_update_reply *reply, int index) { if (likely(!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT))) return 0; if (req_xid_is_last(req)) { struct lsd_client_data *lcd; /* XXX this does not support mulitple transactions yet, i.e. * only 1 update RPC each time betwee MDTs */ lcd = req->rq_export->exp_target_data.ted_lcd; req->rq_transno = lcd->lcd_last_transno; req->rq_status = lcd->lcd_last_result; if (req->rq_status != 0) req->rq_transno = 0; lustre_msg_set_transno(req->rq_repmsg, req->rq_transno); lustre_msg_set_status(req->rq_repmsg, req->rq_status); DEBUG_REQ(D_RPCTRACE, req, "restoring transno "LPD64"status %d", req->rq_transno, req->rq_status); reconstruct(env, dt, obj, reply, index); return 1; } DEBUG_REQ(D_HA, req, "no reply for RESENT req (have "LPD64")", req->rq_export->exp_target_data.ted_lcd->lcd_last_xid); return 0; }
static int seq_handler(struct tgt_session_info *tsi) { struct lu_seq_range *out, *tmp; struct lu_site *site; int rc; __u32 *opc; ENTRY; LASSERT(!(lustre_msg_get_flags(tgt_ses_req(tsi)->rq_reqmsg) & MSG_REPLAY)); site = tsi->tsi_exp->exp_obd->obd_lu_dev->ld_site; LASSERT(site != NULL); opc = req_capsule_client_get(tsi->tsi_pill, &RMF_SEQ_OPC); if (opc != NULL) { out = req_capsule_server_get(tsi->tsi_pill, &RMF_SEQ_RANGE); if (out == NULL) RETURN(err_serious(-EPROTO)); tmp = req_capsule_client_get(tsi->tsi_pill, &RMF_SEQ_RANGE); /* seq client passed mdt id, we need to pass that using out * range parameter */ out->lsr_index = tmp->lsr_index; out->lsr_flags = tmp->lsr_flags; rc = seq_server_handle(site, tsi->tsi_env, *opc, out); } else { rc = err_serious(-EPROTO); } RETURN(rc); }
static void ptlrpc_at_set_reply(struct ptlrpc_request *req, int flags) { struct ptlrpc_service_part *svcpt = req->rq_rqbd->rqbd_svcpt; struct ptlrpc_service *svc = svcpt->scp_service; int service_time = max_t(int, cfs_time_current_sec() - req->rq_arrival_time.tv_sec, 1); if (!(flags & PTLRPC_REPLY_EARLY) && (req->rq_type != PTL_RPC_MSG_ERR) && (req->rq_reqmsg != NULL) && !(lustre_msg_get_flags(req->rq_reqmsg) & (MSG_RESENT | MSG_REPLAY | MSG_REQ_REPLAY_DONE | MSG_LOCK_REPLAY_DONE))) { /* early replies, errors and recovery requests don't count * toward our service time estimate */ int oldse = at_measured(&svcpt->scp_at_estimate, service_time); if (oldse != 0) { DEBUG_REQ(D_ADAPTTO, req, "svc %s changed estimate from %d to %d", svc->srv_name, oldse, at_get(&svcpt->scp_at_estimate)); } } /* Report actual service time for client latency calc */ lustre_msg_set_service_time(req->rq_repmsg, service_time); /* Report service time estimate for future client reqs, but report 0 * (to be ignored by client) if it's a error reply during recovery. * (bz15815) */ if (req->rq_type == PTL_RPC_MSG_ERR && (req->rq_export == NULL || req->rq_export->exp_obd->obd_recovering)) lustre_msg_set_timeout(req->rq_repmsg, 0); else lustre_msg_set_timeout(req->rq_repmsg, at_get(&svcpt->scp_at_estimate)); if (req->rq_reqmsg && !(lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT)) { CDEBUG(D_ADAPTTO, "No early reply support: flags=%#x " "req_flags=%#x magic=%d:%x/%x len=%d\n", flags, lustre_msg_get_flags(req->rq_reqmsg), lustre_msg_is_v1(req->rq_reqmsg), lustre_msg_get_magic(req->rq_reqmsg), lustre_msg_get_magic(req->rq_repmsg), req->rq_replen); } }
static inline int out_check_resent(const struct lu_env *env, struct dt_device *dt, struct dt_object *obj, struct ptlrpc_request *req, out_reconstruct_t reconstruct, struct update_reply *reply, int index) { if (likely(!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT))) return 0; if (req_xid_is_last(req)) { reconstruct(env, dt, obj, reply, index); return 1; } DEBUG_REQ(D_HA, req, "no reply for RESENT req (have "LPD64")", req->rq_export->exp_target_data.ted_lcd->lcd_last_xid); return 0; }
static int seq_req_handle(struct ptlrpc_request *req, const struct lu_env *env, struct seq_thread_info *info) { struct lu_seq_range *out, *tmp; struct lu_site *site; int rc = -EPROTO; __u32 *opc; ENTRY; LASSERT(!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)); site = req->rq_export->exp_obd->obd_lu_dev->ld_site; LASSERT(site != NULL); rc = req_capsule_server_pack(info->sti_pill); if (rc) RETURN(err_serious(rc)); opc = req_capsule_client_get(info->sti_pill, &RMF_SEQ_OPC); if (opc != NULL) { out = req_capsule_server_get(info->sti_pill, &RMF_SEQ_RANGE); if (out == NULL) RETURN(err_serious(-EPROTO)); tmp = req_capsule_client_get(info->sti_pill, &RMF_SEQ_RANGE); /* seq client passed mdt id, we need to pass that using out * range parameter */ out->lsr_index = tmp->lsr_index; out->lsr_flags = tmp->lsr_flags; rc = seq_server_handle(site, env, *opc, out); } else rc = err_serious(-EPROTO); RETURN(rc); }
/** * Send request \a request. * if \a noreply is set, don't expect any reply back and don't set up * reply buffers. * Returns 0 on success or error code. */ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) { int rc; int rc2; int mpflag = 0; struct ptlrpc_connection *connection; lnet_handle_me_t reply_me_h; lnet_md_t reply_md; struct obd_device *obd = request->rq_import->imp_obd; if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_DROP_RPC)) return 0; LASSERT(request->rq_type == PTL_RPC_MSG_REQUEST); LASSERT(request->rq_wait_ctx == 0); /* If this is a re-transmit, we're required to have disengaged * cleanly from the previous attempt */ LASSERT(!request->rq_receiving_reply); LASSERT(!((lustre_msg_get_flags(request->rq_reqmsg) & MSG_REPLAY) && (request->rq_import->imp_state == LUSTRE_IMP_FULL))); if (unlikely(obd != NULL && obd->obd_fail)) { CDEBUG(D_HA, "muting rpc for failed imp obd %s\n", obd->obd_name); /* this prevents us from waiting in ptlrpc_queue_wait */ spin_lock(&request->rq_lock); request->rq_err = 1; spin_unlock(&request->rq_lock); request->rq_status = -ENODEV; return -ENODEV; } connection = request->rq_import->imp_connection; lustre_msg_set_handle(request->rq_reqmsg, &request->rq_import->imp_remote_handle); lustre_msg_set_type(request->rq_reqmsg, PTL_RPC_MSG_REQUEST); lustre_msg_set_conn_cnt(request->rq_reqmsg, request->rq_import->imp_conn_cnt); lustre_msghdr_set_flags(request->rq_reqmsg, request->rq_import->imp_msghdr_flags); if (request->rq_resend) lustre_msg_add_flags(request->rq_reqmsg, MSG_RESENT); if (request->rq_memalloc) mpflag = cfs_memory_pressure_get_and_set(); rc = sptlrpc_cli_wrap_request(request); if (rc) goto out; /* bulk register should be done after wrap_request() */ if (request->rq_bulk != NULL) { rc = ptlrpc_register_bulk(request); if (rc != 0) goto out; } if (!noreply) { LASSERT(request->rq_replen != 0); if (request->rq_repbuf == NULL) { LASSERT(request->rq_repdata == NULL); LASSERT(request->rq_repmsg == NULL); rc = sptlrpc_cli_alloc_repbuf(request, request->rq_replen); if (rc) { /* this prevents us from looping in * ptlrpc_queue_wait */ spin_lock(&request->rq_lock); request->rq_err = 1; spin_unlock(&request->rq_lock); request->rq_status = rc; goto cleanup_bulk; } } else { request->rq_repdata = NULL; request->rq_repmsg = NULL; } rc = LNetMEAttach(request->rq_reply_portal,/*XXX FIXME bug 249*/ connection->c_peer, request->rq_xid, 0, LNET_UNLINK, LNET_INS_AFTER, &reply_me_h); if (rc != 0) { CERROR("LNetMEAttach failed: %d\n", rc); LASSERT(rc == -ENOMEM); rc = -ENOMEM; goto cleanup_bulk; } } spin_lock(&request->rq_lock); /* If the MD attach succeeds, there _will_ be a reply_in callback */ request->rq_receiving_reply = !noreply; request->rq_req_unlink = 1; /* We are responsible for unlinking the reply buffer */ request->rq_reply_unlink = !noreply; /* Clear any flags that may be present from previous sends. */ request->rq_replied = 0; request->rq_err = 0; request->rq_timedout = 0; request->rq_net_err = 0; request->rq_resend = 0; request->rq_restart = 0; request->rq_reply_truncate = 0; spin_unlock(&request->rq_lock); if (!noreply) { reply_md.start = request->rq_repbuf; reply_md.length = request->rq_repbuf_len; /* Allow multiple early replies */ reply_md.threshold = LNET_MD_THRESH_INF; /* Manage remote for early replies */ reply_md.options = PTLRPC_MD_OPTIONS | LNET_MD_OP_PUT | LNET_MD_MANAGE_REMOTE | LNET_MD_TRUNCATE; /* allow to make EOVERFLOW error */ reply_md.user_ptr = &request->rq_reply_cbid; reply_md.eq_handle = ptlrpc_eq_h; /* We must see the unlink callback to unset rq_reply_unlink, so we can't auto-unlink */ rc = LNetMDAttach(reply_me_h, reply_md, LNET_RETAIN, &request->rq_reply_md_h); if (rc != 0) { CERROR("LNetMDAttach failed: %d\n", rc); LASSERT(rc == -ENOMEM); spin_lock(&request->rq_lock); /* ...but the MD attach didn't succeed... */ request->rq_receiving_reply = 0; spin_unlock(&request->rq_lock); rc = -ENOMEM; goto cleanup_me; } CDEBUG(D_NET, "Setup reply buffer: %u bytes, xid %llu, portal %u\n", request->rq_repbuf_len, request->rq_xid, request->rq_reply_portal); } /* add references on request for request_out_callback */ ptlrpc_request_addref(request); if (obd != NULL && obd->obd_svc_stats != NULL) lprocfs_counter_add(obd->obd_svc_stats, PTLRPC_REQACTIVE_CNTR, atomic_read(&request->rq_import->imp_inflight)); OBD_FAIL_TIMEOUT(OBD_FAIL_PTLRPC_DELAY_SEND, request->rq_timeout + 5); ktime_get_real_ts64(&request->rq_arrival_time); request->rq_sent = ktime_get_real_seconds(); /* We give the server rq_timeout secs to process the req, and add the network latency for our local timeout. */ request->rq_deadline = request->rq_sent + request->rq_timeout + ptlrpc_at_get_net_latency(request); ptlrpc_pinger_sending_on_import(request->rq_import); DEBUG_REQ(D_INFO, request, "send flg=%x", lustre_msg_get_flags(request->rq_reqmsg)); rc = ptl_send_buf(&request->rq_req_md_h, request->rq_reqbuf, request->rq_reqdata_len, LNET_NOACK_REQ, &request->rq_req_cbid, connection, request->rq_request_portal, request->rq_xid, 0); if (rc == 0) goto out; ptlrpc_req_finished(request); if (noreply) goto out; cleanup_me: /* MEUnlink is safe; the PUT didn't even get off the ground, and * nobody apart from the PUT's target has the right nid+XID to * access the reply buffer. */ rc2 = LNetMEUnlink(reply_me_h); LASSERT(rc2 == 0); /* UNLINKED callback called synchronously */ LASSERT(!request->rq_receiving_reply); cleanup_bulk: /* We do sync unlink here as there was no real transfer here so * the chance to have long unlink to sluggish net is smaller here. */ ptlrpc_unregister_bulk(request, 0); out: if (request->rq_memalloc) cfs_memory_pressure_restore(mpflag); return rc; }
/* * Client's incoming reply callback */ void reply_in_callback(lnet_event_t *ev) { struct ptlrpc_cb_id *cbid = ev->md.user_ptr; struct ptlrpc_request *req = cbid->cbid_arg; DEBUG_REQ(D_NET, req, "type %d, status %d", ev->type, ev->status); LASSERT(ev->type == LNET_EVENT_PUT || ev->type == LNET_EVENT_UNLINK); LASSERT(ev->md.start == req->rq_repbuf); LASSERT(ev->offset + ev->mlength <= req->rq_repbuf_len); /* We've set LNET_MD_MANAGE_REMOTE for all outgoing requests for adaptive timeouts' early reply. */ LASSERT((ev->md.options & LNET_MD_MANAGE_REMOTE) != 0); spin_lock(&req->rq_lock); req->rq_receiving_reply = 0; req->rq_early = 0; if (ev->unlinked) req->rq_must_unlink = 0; if (ev->status) goto out_wake; if (ev->type == LNET_EVENT_UNLINK) { LASSERT(ev->unlinked); DEBUG_REQ(D_NET, req, "unlink"); goto out_wake; } if (ev->mlength < ev->rlength) { CDEBUG(D_RPCTRACE, "truncate req %p rpc %d - %d+%d\n", req, req->rq_replen, ev->rlength, ev->offset); req->rq_reply_truncate = 1; req->rq_replied = 1; req->rq_status = -EOVERFLOW; req->rq_nob_received = ev->rlength + ev->offset; goto out_wake; } if ((ev->offset == 0) && ((lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT))) { /* Early reply */ DEBUG_REQ(D_ADAPTTO, req, "Early reply received: mlen=%u offset=%d replen=%d " "replied=%d unlinked=%d", ev->mlength, ev->offset, req->rq_replen, req->rq_replied, ev->unlinked); req->rq_early_count++; /* number received, client side */ if (req->rq_replied) /* already got the real reply */ goto out_wake; req->rq_early = 1; req->rq_reply_off = ev->offset; req->rq_nob_received = ev->mlength; /* And we're still receiving */ req->rq_receiving_reply = 1; } else { /* Real reply */ req->rq_rep_swab_mask = 0; req->rq_replied = 1; req->rq_reply_off = ev->offset; req->rq_nob_received = ev->mlength; /* LNetMDUnlink can't be called under the LNET_LOCK, so we must unlink in ptlrpc_unregister_reply */ DEBUG_REQ(D_INFO, req, "reply in flags=%x mlen=%u offset=%d replen=%d", lustre_msg_get_flags(req->rq_reqmsg), ev->mlength, ev->offset, req->rq_replen); } req->rq_import->imp_last_reply_time = cfs_time_current_sec(); out_wake: /* NB don't unlock till after wakeup; req can disappear under us * since we don't have our own ref */ ptlrpc_client_wake_req(req); spin_unlock(&req->rq_lock); }
/** * Send request \a request. * if \a noreply is set, don't expect any reply back and don't set up * reply buffers. * Returns 0 on success or error code. */ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) { int rc; int rc2; int mpflag = 0; struct ptlrpc_connection *connection; lnet_handle_me_t reply_me_h; lnet_md_t reply_md; struct obd_import *imp = request->rq_import; struct obd_device *obd = imp->imp_obd; ENTRY; if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_DROP_RPC)) RETURN(0); LASSERT(request->rq_type == PTL_RPC_MSG_REQUEST); LASSERT(request->rq_wait_ctx == 0); /* If this is a re-transmit, we're required to have disengaged * cleanly from the previous attempt */ LASSERT(!request->rq_receiving_reply); LASSERT(!((lustre_msg_get_flags(request->rq_reqmsg) & MSG_REPLAY) && (imp->imp_state == LUSTRE_IMP_FULL))); if (unlikely(obd != NULL && obd->obd_fail)) { CDEBUG(D_HA, "muting rpc for failed imp obd %s\n", obd->obd_name); /* this prevents us from waiting in ptlrpc_queue_wait */ spin_lock(&request->rq_lock); request->rq_err = 1; spin_unlock(&request->rq_lock); request->rq_status = -ENODEV; RETURN(-ENODEV); } connection = imp->imp_connection; lustre_msg_set_handle(request->rq_reqmsg, &imp->imp_remote_handle); lustre_msg_set_type(request->rq_reqmsg, PTL_RPC_MSG_REQUEST); lustre_msg_set_conn_cnt(request->rq_reqmsg, imp->imp_conn_cnt); lustre_msghdr_set_flags(request->rq_reqmsg, imp->imp_msghdr_flags); /* If it's the first time to resend the request for EINPROGRESS, * we need to allocate a new XID (see after_reply()), it's different * from the resend for reply timeout. */ if (request->rq_nr_resend != 0 && list_empty(&request->rq_unreplied_list)) { __u64 min_xid = 0; /* resend for EINPROGRESS, allocate new xid to avoid reply * reconstruction */ spin_lock(&imp->imp_lock); ptlrpc_assign_next_xid_nolock(request); request->rq_mbits = request->rq_xid; min_xid = ptlrpc_known_replied_xid(imp); spin_unlock(&imp->imp_lock); lustre_msg_set_last_xid(request->rq_reqmsg, min_xid); DEBUG_REQ(D_RPCTRACE, request, "Allocating new xid for " "resend on EINPROGRESS"); } else if (request->rq_bulk != NULL) { ptlrpc_set_bulk_mbits(request); lustre_msg_set_mbits(request->rq_reqmsg, request->rq_mbits); } if (list_empty(&request->rq_unreplied_list) || request->rq_xid <= imp->imp_known_replied_xid) { DEBUG_REQ(D_ERROR, request, "xid: "LPU64", replied: "LPU64", " "list_empty:%d\n", request->rq_xid, imp->imp_known_replied_xid, list_empty(&request->rq_unreplied_list)); LBUG(); } /** For enabled AT all request should have AT_SUPPORT in the * FULL import state when OBD_CONNECT_AT is set */ LASSERT(AT_OFF || imp->imp_state != LUSTRE_IMP_FULL || (imp->imp_msghdr_flags & MSGHDR_AT_SUPPORT) || !(imp->imp_connect_data.ocd_connect_flags & OBD_CONNECT_AT)); if (request->rq_resend) { lustre_msg_add_flags(request->rq_reqmsg, MSG_RESENT); if (request->rq_resend_cb != NULL) request->rq_resend_cb(request, &request->rq_async_args); } if (request->rq_memalloc) mpflag = cfs_memory_pressure_get_and_set(); rc = sptlrpc_cli_wrap_request(request); if (rc == -ENOMEM) /* set rq_sent so that this request is treated * as a delayed send in the upper layers */ request->rq_sent = cfs_time_current_sec(); if (rc) GOTO(out, rc); /* bulk register should be done after wrap_request() */ if (request->rq_bulk != NULL) { rc = ptlrpc_register_bulk (request); if (rc != 0) GOTO(out, rc); } if (!noreply) { LASSERT (request->rq_replen != 0); if (request->rq_repbuf == NULL) { LASSERT(request->rq_repdata == NULL); LASSERT(request->rq_repmsg == NULL); rc = sptlrpc_cli_alloc_repbuf(request, request->rq_replen); if (rc) { /* this prevents us from looping in * ptlrpc_queue_wait */ spin_lock(&request->rq_lock); request->rq_err = 1; spin_unlock(&request->rq_lock); request->rq_status = rc; GOTO(cleanup_bulk, rc); } } else { request->rq_repdata = NULL; request->rq_repmsg = NULL; } rc = LNetMEAttach(request->rq_reply_portal,/*XXX FIXME bug 249*/ connection->c_peer, request->rq_xid, 0, LNET_UNLINK, LNET_INS_AFTER, &reply_me_h); if (rc != 0) { CERROR("LNetMEAttach failed: %d\n", rc); LASSERT (rc == -ENOMEM); GOTO(cleanup_bulk, rc = -ENOMEM); } } spin_lock(&request->rq_lock); /* We are responsible for unlinking the reply buffer */ request->rq_reply_unlinked = noreply; request->rq_receiving_reply = !noreply; /* Clear any flags that may be present from previous sends. */ request->rq_req_unlinked = 0; request->rq_replied = 0; request->rq_err = 0; request->rq_timedout = 0; request->rq_net_err = 0; request->rq_resend = 0; request->rq_restart = 0; request->rq_reply_truncated = 0; spin_unlock(&request->rq_lock); if (!noreply) { reply_md.start = request->rq_repbuf; reply_md.length = request->rq_repbuf_len; /* Allow multiple early replies */ reply_md.threshold = LNET_MD_THRESH_INF; /* Manage remote for early replies */ reply_md.options = PTLRPC_MD_OPTIONS | LNET_MD_OP_PUT | LNET_MD_MANAGE_REMOTE | LNET_MD_TRUNCATE; /* allow to make EOVERFLOW error */; reply_md.user_ptr = &request->rq_reply_cbid; reply_md.eq_handle = ptlrpc_eq_h; /* We must see the unlink callback to set rq_reply_unlinked, * so we can't auto-unlink */ rc = LNetMDAttach(reply_me_h, reply_md, LNET_RETAIN, &request->rq_reply_md_h); if (rc != 0) { CERROR("LNetMDAttach failed: %d\n", rc); LASSERT (rc == -ENOMEM); spin_lock(&request->rq_lock); /* ...but the MD attach didn't succeed... */ request->rq_receiving_reply = 0; spin_unlock(&request->rq_lock); GOTO(cleanup_me, rc = -ENOMEM); } CDEBUG(D_NET, "Setup reply buffer: %u bytes, xid "LPU64 ", portal %u\n", request->rq_repbuf_len, request->rq_xid, request->rq_reply_portal); } /* add references on request for request_out_callback */ ptlrpc_request_addref(request); if (obd != NULL && obd->obd_svc_stats != NULL) lprocfs_counter_add(obd->obd_svc_stats, PTLRPC_REQACTIVE_CNTR, atomic_read(&imp->imp_inflight)); OBD_FAIL_TIMEOUT(OBD_FAIL_PTLRPC_DELAY_SEND, request->rq_timeout + 5); do_gettimeofday(&request->rq_sent_tv); request->rq_sent = cfs_time_current_sec(); /* We give the server rq_timeout secs to process the req, and add the network latency for our local timeout. */ request->rq_deadline = request->rq_sent + request->rq_timeout + ptlrpc_at_get_net_latency(request); ptlrpc_pinger_sending_on_import(imp); DEBUG_REQ(D_INFO, request, "send flg=%x", lustre_msg_get_flags(request->rq_reqmsg)); rc = ptl_send_buf(&request->rq_req_md_h, request->rq_reqbuf, request->rq_reqdata_len, LNET_NOACK_REQ, &request->rq_req_cbid, connection, request->rq_request_portal, request->rq_xid, 0); if (likely(rc == 0)) GOTO(out, rc); request->rq_req_unlinked = 1; ptlrpc_req_finished(request); if (noreply) GOTO(out, rc); cleanup_me: /* MEUnlink is safe; the PUT didn't even get off the ground, and * nobody apart from the PUT's target has the right nid+XID to * access the reply buffer. */ rc2 = LNetMEUnlink(reply_me_h); LASSERT (rc2 == 0); /* UNLINKED callback called synchronously */ LASSERT(!request->rq_receiving_reply); cleanup_bulk: /* We do sync unlink here as there was no real transfer here so * the chance to have long unlink to sluggish net is smaller here. */ ptlrpc_unregister_bulk(request, 0); out: if (request->rq_memalloc) cfs_memory_pressure_restore(mpflag); return rc; }
int llog_origin_handle_cancel(struct ptlrpc_request *req) { struct obd_device *obd = req->rq_export->exp_obd; int num_cookies, rc = 0, err, i, failed = 0; struct obd_device *disk_obd; struct llog_cookie *logcookies; struct llog_ctxt *ctxt = NULL; struct lvfs_run_ctxt saved; struct llog_handle *cathandle; struct inode *inode; void *handle; ENTRY; logcookies = req_capsule_client_get(&req->rq_pill, &RMF_LOGCOOKIES); num_cookies = req_capsule_get_size(&req->rq_pill, &RMF_LOGCOOKIES, RCL_CLIENT) / sizeof(*logcookies); if (logcookies == NULL || num_cookies == 0) { DEBUG_REQ(D_HA, req, "No llog cookies sent"); RETURN(-EFAULT); } ctxt = llog_get_context(obd, logcookies->lgc_subsys); if (ctxt == NULL) RETURN(-ENODEV); disk_obd = ctxt->loc_exp->exp_obd; push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL); for (i = 0; i < num_cookies; i++, logcookies++) { cathandle = ctxt->loc_handle; LASSERT(cathandle != NULL); inode = cathandle->lgh_file->f_dentry->d_inode; handle = fsfilt_start_log(disk_obd, inode, FSFILT_OP_CANCEL_UNLINK, NULL, 1); if (IS_ERR(handle)) { CERROR("fsfilt_start_log() failed: %ld\n", PTR_ERR(handle)); GOTO(pop_ctxt, rc = PTR_ERR(handle)); } rc = llog_cat_cancel_records(cathandle, 1, logcookies); /* * Do not raise -ENOENT errors for resent rpcs. This rec already * might be killed. */ if (rc == -ENOENT && (lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT)) { /* * Do not change this message, reply-single.sh test_59b * expects to find this in log. */ CDEBUG(D_RPCTRACE, "RESENT cancel req %p - ignored\n", req); rc = 0; } else if (rc == 0) { CDEBUG(D_RPCTRACE, "Canceled %d llog-records\n", num_cookies); } err = fsfilt_commit(disk_obd, inode, handle, 0); if (err) { CERROR("Error committing transaction: %d\n", err); if (!rc) rc = err; failed++; GOTO(pop_ctxt, rc); } else if (rc) failed++; } GOTO(pop_ctxt, rc); pop_ctxt: pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL); if (rc) CERROR("Cancel %d of %d llog-records failed: %d\n", failed, num_cookies, rc); llog_ctxt_put(ctxt); return rc; }
/* * VBR: save parent version in reply and child version getting by its name. * Version of child is getting and checking during its lookup. If */ static int mdt_reint_unlink(struct mdt_thread_info *info, struct mdt_lock_handle *lhc) { struct mdt_reint_record *rr = &info->mti_rr; struct ptlrpc_request *req = mdt_info_req(info); struct md_attr *ma = &info->mti_attr; struct lu_fid *child_fid = &info->mti_tmp_fid1; struct mdt_object *mp; struct mdt_object *mc; struct mdt_lock_handle *parent_lh; struct mdt_lock_handle *child_lh; struct lu_name *lname; int rc; int no_name = 0; ENTRY; DEBUG_REQ(D_INODE, req, "unlink "DFID"/%s", PFID(rr->rr_fid1), rr->rr_name); if (info->mti_dlm_req) ldlm_request_cancel(req, info->mti_dlm_req, 0); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_REINT_UNLINK)) RETURN(err_serious(-ENOENT)); if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1)) RETURN(-EPERM); /* * step 1: Found the parent. */ mp = mdt_object_find(info->mti_env, info->mti_mdt, rr->rr_fid1); if (IS_ERR(mp)) { rc = PTR_ERR(mp); GOTO(out, rc); } parent_lh = &info->mti_lh[MDT_LH_PARENT]; lname = mdt_name(info->mti_env, (char *)rr->rr_name, rr->rr_namelen); if (mdt_object_remote(mp)) { mdt_lock_reg_init(parent_lh, LCK_EX); rc = mdt_remote_object_lock(info, mp, &parent_lh->mlh_rreg_lh, parent_lh->mlh_rreg_mode, MDS_INODELOCK_UPDATE); if (rc != ELDLM_OK) GOTO(put_parent, rc); } else { mdt_lock_pdo_init(parent_lh, LCK_PW, rr->rr_name, rr->rr_namelen); rc = mdt_object_lock(info, mp, parent_lh, MDS_INODELOCK_UPDATE, MDT_LOCAL_LOCK); if (rc) GOTO(put_parent, rc); rc = mdt_version_get_check_save(info, mp, 0); if (rc) GOTO(unlock_parent, rc); } /* step 2: find & lock the child */ /* lookup child object along with version checking */ fid_zero(child_fid); rc = mdt_lookup_version_check(info, mp, lname, child_fid, 1); if (rc != 0) { /* Name might not be able to find during resend of * remote unlink, considering following case. * dir_A is a remote directory, the name entry of * dir_A is on MDT0, the directory is on MDT1, * * 1. client sends unlink req to MDT1. * 2. MDT1 sends name delete update to MDT0. * 3. name entry is being deleted in MDT0 synchronously. * 4. MDT1 is restarted. * 5. client resends unlink req to MDT1. So it can not * find the name entry on MDT0 anymore. * In this case, MDT1 only needs to destory the local * directory. * */ if (mdt_object_remote(mp) && rc == -ENOENT && !fid_is_zero(rr->rr_fid2) && lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) { no_name = 1; *child_fid = *rr->rr_fid2; } else { GOTO(unlock_parent, rc); } } if (fid_is_obf(child_fid) || fid_is_dot_lustre(child_fid)) GOTO(unlock_parent, rc = -EPERM); mdt_reint_init_ma(info, ma); /* We will lock the child regardless it is local or remote. No harm. */ mc = mdt_object_find(info->mti_env, info->mti_mdt, child_fid); if (IS_ERR(mc)) GOTO(unlock_parent, rc = PTR_ERR(mc)); child_lh = &info->mti_lh[MDT_LH_CHILD]; mdt_lock_reg_init(child_lh, LCK_EX); if (mdt_object_remote(mc)) { struct mdt_body *repbody; if (!fid_is_zero(rr->rr_fid2)) { CDEBUG(D_INFO, "%s: name %s can not find "DFID"\n", mdt_obd_name(info->mti_mdt), (char *)rr->rr_name, PFID(mdt_object_fid(mc))); GOTO(put_child, rc = -ENOENT); } CDEBUG(D_INFO, "%s: name %s: "DFID" is another MDT\n", mdt_obd_name(info->mti_mdt), (char *)rr->rr_name, PFID(mdt_object_fid(mc))); if (!mdt_is_dne_client(req->rq_export)) /* Return -EIO for old client */ GOTO(put_child, rc = -EIO); if (info->mti_spec.sp_rm_entry) { struct lu_ucred *uc = mdt_ucred(info); if (!md_capable(uc, CFS_CAP_SYS_ADMIN)) { CERROR("%s: unlink remote entry is only " "permitted for administrator: rc = %d\n", mdt_obd_name(info->mti_mdt), -EPERM); GOTO(put_child, rc = -EPERM); } ma->ma_need = MA_INODE; ma->ma_valid = 0; mdt_set_capainfo(info, 1, child_fid, BYPASS_CAPA); rc = mdo_unlink(info->mti_env, mdt_object_child(mp), NULL, lname, ma, no_name); GOTO(put_child, rc); } /* Revoke the LOOKUP lock of the remote object granted by * this MDT. Since the unlink will happen on another MDT, * it will release the LOOKUP lock right away. Then What * would happen if another client try to grab the LOOKUP * lock at the same time with unlink XXX */ mdt_object_lock(info, mc, child_lh, MDS_INODELOCK_LOOKUP, MDT_CROSS_LOCK); repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY); LASSERT(repbody != NULL); repbody->fid1 = *mdt_object_fid(mc); repbody->valid |= (OBD_MD_FLID | OBD_MD_MDS); GOTO(unlock_child, rc = -EREMOTE); } else if (info->mti_spec.sp_rm_entry) { rc = -EPERM; CDEBUG(D_INFO, "%s: no rm_entry on local dir '%s': rc = %d\n", mdt_obd_name(info->mti_mdt), (char *)rr->rr_name, rc); GOTO(put_child, rc); } /* We used to acquire MDS_INODELOCK_FULL here but we can't do * this now because a running HSM restore on the child (unlink * victim) will hold the layout lock. See LU-4002. */ rc = mdt_object_lock(info, mc, child_lh, MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE, MDT_CROSS_LOCK); if (rc != 0) GOTO(put_child, rc); mdt_fail_write(info->mti_env, info->mti_mdt->mdt_bottom, OBD_FAIL_MDS_REINT_UNLINK_WRITE); /* save version when object is locked */ mdt_version_get_save(info, mc, 1); /* * Now we can only make sure we need MA_INODE, in mdd layer, will check * whether need MA_LOV and MA_COOKIE. */ ma->ma_need = MA_INODE; ma->ma_valid = 0; mdt_set_capainfo(info, 1, child_fid, BYPASS_CAPA); mutex_lock(&mc->mot_lov_mutex); rc = mdo_unlink(info->mti_env, mdt_object_child(mp), mdt_object_child(mc), lname, ma, no_name); mutex_unlock(&mc->mot_lov_mutex); if (rc == 0 && !lu_object_is_dying(&mc->mot_header)) rc = mdt_attr_get_complex(info, mc, ma); if (rc == 0) mdt_handle_last_unlink(info, mc, ma); if (ma->ma_valid & MA_INODE) { switch (ma->ma_attr.la_mode & S_IFMT) { case S_IFDIR: mdt_counter_incr(req, LPROC_MDT_RMDIR); break; case S_IFREG: case S_IFLNK: case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: mdt_counter_incr(req, LPROC_MDT_UNLINK); break; default: LASSERTF(0, "bad file type %o unlinking\n", ma->ma_attr.la_mode); } } EXIT; unlock_child: mdt_object_unlock(info, mc, child_lh, rc); put_child: mdt_object_put(info->mti_env, mc); unlock_parent: mdt_object_unlock(info, mp, parent_lh, rc); put_parent: mdt_object_put(info->mti_env, mp); out: return rc; }