/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
- * Author: Isaac Huang <isaac@clusterfs.com>
+ * 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.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * 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.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lnet/selftest/rpc.c
+ *
+ * Author: Isaac Huang <isaac@clusterfs.com>
*/
#define DEBUG_SUBSYSTEM S_LNET
-#include <libcfs/kp30.h>
-#include <libcfs/libcfs.h>
-#include <lnet/lib-lnet.h>
-
#include "selftest.h"
+#define SRPC_PEER_HASH_SIZE 101 /* # peer lists */
+
typedef enum {
SRPC_STATE_NONE,
SRPC_STATE_NI_INIT,
SRPC_STATE_STOPPING,
} srpc_state_t;
-#define SRPC_PEER_HASH_SIZE 101 /* # peer lists */
-#define SRPC_PEER_CREDITS 16 /* >= most LND's default peer credit */
-
struct smoketest_rpc {
spinlock_t rpc_glock; /* global lock */
srpc_service_t *rpc_services[SRPC_SERVICE_MAX_ID + 1];
__u64 rpc_matchbits; /* matchbits counter */
} srpc_data;
+static int srpc_peer_credits = 16;
+CFS_MODULE_PARM(srpc_peer_credits, "i", int, 0444,
+ "# in-flight RPCs per peer (16 by default)");
+
/* forward ref's */
int srpc_handle_rpc (swi_workitem_t *wi);
memset(peer, 0, sizeof(srpc_peer_t));
peer->stp_nid = nid;
- peer->stp_credits = SRPC_PEER_CREDITS;
+ peer->stp_credits = srpc_peer_credits;
spin_lock_init(&peer->stp_lock);
CFS_INIT_LIST_HEAD(&peer->stp_rpcq);
LASSERT (nid != LNET_NID_ANY);
- list_for_each_entry (peer, peer_list, stp_list) {
+ cfs_list_for_each_entry_typed (peer, peer_list,
+ srpc_peer_t, stp_list) {
if (peer->stp_nid == nid)
return peer;
}
static srpc_peer_t *
srpc_nid2peer (lnet_nid_t nid)
{
- srpc_peer_t *peer;
- srpc_peer_t *new_peer;
+ srpc_peer_t *peer;
+ srpc_peer_t *new_peer;
spin_lock(&srpc_data.rpc_glock);
peer = srpc_find_peer_locked(nid);
if (peer != NULL)
return peer;
-
+
new_peer = srpc_create_peer(nid);
spin_lock(&srpc_data.rpc_glock);
spin_unlock(&srpc_data.rpc_glock);
return NULL;
}
-
+
list_add_tail(&new_peer->stp_list, srpc_nid2peerlist(nid));
spin_unlock(&srpc_data.rpc_glock);
return new_peer;
rpc->srpc_reqstbuf = buffer;
rpc->srpc_peer = buffer->buf_peer;
rpc->srpc_self = buffer->buf_self;
- rpc->srpc_replymdh = LNET_INVALID_HANDLE;
+ LNetInvalidateHandle(&rpc->srpc_replymdh);
}
int
}
int
-srpc_post_active_rdma(int portal, __u64 matchbits, void *buf, int len,
+srpc_post_active_rdma(int portal, __u64 matchbits, void *buf, int len,
int options, lnet_process_id_t peer, lnet_nid_t self,
lnet_handle_md_t *mdh, srpc_event_t *ev)
{
/* this is kind of an abuse of the LNET_MD_OP_{PUT,GET} options.
* they're only meaningful for MDs attached to an ME (i.e. passive
* buffers... */
- if ((options & LNET_MD_OP_PUT) != 0) {
+ if ((options & LNET_MD_OP_PUT) != 0) {
rc = LNetPut(self, *mdh, LNET_NOACK_REQ, peer,
portal, matchbits, 0, 0);
} else {
- LASSERT ((options & LNET_MD_OP_GET) != 0);
+ LASSERT ((options & LNET_MD_OP_GET) != 0);
rc = LNetGet(self, *mdh, peer, portal, matchbits, 0);
}
else
portal = SRPC_FRAMEWORK_REQUEST_PORTAL;
- rc = srpc_post_active_rdma(portal, service, buf, len,
+ rc = srpc_post_active_rdma(portal, service, buf, len,
LNET_MD_OP_PUT, peer,
LNET_NID_ANY, mdh, ev);
return rc;
{
int rc;
int portal;
- lnet_process_id_t any = {.nid = LNET_NID_ANY,
- .pid = LNET_PID_ANY};
+ lnet_process_id_t any = {0};
+
+ any.nid = LNET_NID_ANY;
+ any.pid = LNET_PID_ANY;
if (service > SRPC_FRAMEWORK_SERVICE_MAX_ID)
portal = SRPC_REQUEST_PORTAL;
LASSERT (!sv->sv_shuttingdown);
- buf->buf_mdh = LNET_INVALID_HANDLE;
+ LNetInvalidateHandle(&buf->buf_mdh);
list_add(&buf->buf_list, &sv->sv_posted_msgq);
sv->sv_nposted_msg++;
spin_unlock(&sv->sv_lock);
spin_unlock(&sv->sv_lock);
LIBCFS_FREE(buf, sizeof(*buf));
spin_lock(&sv->sv_lock);
- return rc;
+ return rc;
}
int
sv->sv_shuttingdown = 1; /* i.e. no new active RPC */
/* schedule in-flight RPCs to notice the shutdown */
- list_for_each_entry (rpc, &sv->sv_active_rpcq, srpc_list) {
+ cfs_list_for_each_entry_typed (rpc, &sv->sv_active_rpcq,
+ srpc_server_rpc_t, srpc_list) {
swi_schedule_workitem(&rpc->srpc_wi);
}
/* OK to traverse sv_posted_msgq without lock, since no one
* touches sv_posted_msgq now */
- list_for_each_entry (buf, &sv->sv_posted_msgq, buf_list)
+ cfs_list_for_each_entry_typed (buf, &sv->sv_posted_msgq,
+ srpc_buffer_t, buf_list)
LNetMDUnlink(buf->buf_mdh);
return;
msg = &rpc->srpc_reqstbuf->buf_msg;
reply = &rpc->srpc_replymsg.msg_body.reply;
- if (msg->msg_version != SRPC_MSG_VERSION &&
- msg->msg_version != __swab32(SRPC_MSG_VERSION)) {
+ if (msg->msg_magic == 0) {
+ /* moaned already in srpc_lnet_ev_handler */
+ rc = EBADMSG;
+ } else if (msg->msg_version != SRPC_MSG_VERSION &&
+ msg->msg_version != __swab32(SRPC_MSG_VERSION)) {
CWARN ("Version mismatch: %u, %u expected, from %s\n",
msg->msg_version, SRPC_MSG_VERSION,
libcfs_id2str(rpc->srpc_peer));
}
}
case SWI_STATE_BULK_STARTED:
- LASSERT (rpc->srpc_bulk == NULL || ev->ev_fired);
+ /* we cannot LASSERT ev_fired right here because it
+ * may be set only upon an event with unlinked==1 */
if (rpc->srpc_bulk != NULL) {
rc = ev->ev_status;
rc = (*sv->sv_bulk_ready) (rpc, rc);
if (rc != 0) {
- srpc_server_rpc_done(rpc, rc);
- return 1;
+ if (ev->ev_fired) {
+ srpc_server_rpc_done(rpc, rc);
+ return 1;
+ }
+
+ rpc->srpc_status = rc;
+ wi->wi_state = SWI_STATE_BULK_ERRORED;
+ LNetMDUnlink(rpc->srpc_bulk->bk_mdh);
+ return 0; /* wait for UNLINK event */
}
}
+ LASSERT (rpc->srpc_bulk == NULL || ev->ev_fired);
+
wi->wi_state = SWI_STATE_REPLY_SUBMITTED;
rc = srpc_send_reply(rpc);
if (rc == 0)
wi->wi_state = SWI_STATE_DONE;
srpc_server_rpc_done(rpc, ev->ev_status);
return 1;
+
+ case SWI_STATE_BULK_ERRORED:
+ LASSERT (rpc->srpc_bulk != NULL && ev->ev_fired);
+ LASSERT (rpc->srpc_status != 0);
+
+ srpc_server_rpc_done(rpc, rpc->srpc_status);
+ return 1;
}
return 0;
CFS_INIT_LIST_HEAD(&timer->stt_list);
timer->stt_data = rpc;
timer->stt_func = srpc_client_rpc_expired;
- timer->stt_expires = cfs_time_add(rpc->crpc_timeout,
+ timer->stt_expires = cfs_time_add(rpc->crpc_timeout,
cfs_time_current_sec());
stt_add_timer(timer);
return;
}
-/*
+/*
* Called with rpc->crpc_lock held.
*
* Upon exit the RPC expiry timer is not queued and the handler is not
* running on any CPU. */
void
srpc_del_client_rpc_timer (srpc_client_rpc_t *rpc)
-{
+{
/* timer not planted or already exploded */
if (rpc->crpc_timeout == 0) return;
while (rpc->crpc_timeout != 0) {
spin_unlock(&rpc->crpc_lock);
- cfs_schedule();
+ cfs_schedule();
spin_lock(&rpc->crpc_lock);
}
* No one can schedule me now since:
* - RPC timer has been defused.
* - all LNet events have been fired.
- * - crpc_closed has been set, preventing srpc_abort_rpc from
+ * - crpc_closed has been set, preventing srpc_abort_rpc from
* scheduling me.
* Cancel pending schedules and prevent future schedule attempts:
*/
case SWI_STATE_REQUEST_SUBMITTED:
/* CAVEAT EMPTOR: rqtev, rpyev, and bulkev may come in any
- * order; however, they're processed in a strict order:
+ * order; however, they're processed in a strict order:
* rqt, rpy, and bulk. */
if (!rpc->crpc_reqstev.ev_fired) break;
rc = rpc->crpc_replyev.ev_status;
if (rc != 0) break;
- if ((reply->msg_type != type &&
+ if ((reply->msg_type != type &&
reply->msg_type != __swab32(type)) ||
(reply->msg_magic != SRPC_MSG_MAGIC &&
reply->msg_magic != __swab32(SRPC_MSG_MAGIC))) {
{
srpc_client_rpc_t *rpc;
- LIBCFS_ALLOC(rpc, offsetof(srpc_client_rpc_t,
+ LIBCFS_ALLOC(rpc, offsetof(srpc_client_rpc_t,
crpc_bulk.bk_iovs[nbulkiov]));
if (rpc == NULL)
return NULL;
}
/* when in kernel always called with LNET_LOCK() held, and in thread context */
-void
+void
srpc_lnet_ev_handler (lnet_event_t *ev)
{
srpc_event_t *rpcev = ev->md.user_ptr;
srpc_service_t *sv;
srpc_msg_t *msg;
srpc_msg_type_t type;
+ int fired_flag = 1;
LASSERT (!in_interrupt());
LASSERT (rpcev->ev_fired == 0);
rpcev->ev_fired = 1;
- rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ?
+ rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ?
-EINTR : ev->status;
swi_schedule_workitem(&crpc->crpc_wi);
LASSERT (sv->sv_nposted_msg >= 0);
if (sv->sv_shuttingdown) {
- /* Leave buffer on sv->sv_posted_msgq since
+ /* Leave buffer on sv->sv_posted_msgq since
* srpc_finish_service needs to traverse it. */
spin_unlock(&sv->sv_lock);
break;
type = srpc_service2request(sv->sv_id);
if (ev->status != 0 || ev->mlength != sizeof(*msg) ||
- (msg->msg_type != type &&
+ (msg->msg_type != type &&
msg->msg_type != __swab32(type)) ||
(msg->msg_magic != SRPC_MSG_MAGIC &&
msg->msg_magic != __swab32(SRPC_MSG_MAGIC))) {
ev->status, ev->mlength,
msg->msg_type, msg->msg_magic);
- /* NB might drop sv_lock in srpc_service_recycle_buffer,
- * sv_nposted_msg++ as an implicit reference to prevent
- * sv from disappearing under me */
- sv->sv_nposted_msg++;
- srpc_service_recycle_buffer(sv, buffer);
- sv->sv_nposted_msg--;
- spin_unlock(&sv->sv_lock);
-
- if (ev->status == 0) { /* status!=0 counted already */
- spin_lock(&srpc_data.rpc_glock);
- srpc_data.rpc_counters.errors++;
- spin_unlock(&srpc_data.rpc_glock);
- }
- break;
+ /* NB can't call srpc_service_recycle_buffer here since
+ * it may call LNetM[DE]Attach. The invalid magic tells
+ * srpc_handle_rpc to drop this RPC */
+ msg->msg_magic = 0;
}
if (!list_empty(&sv->sv_free_rpcq)) {
ev->type == LNET_EVENT_REPLY ||
ev->type == LNET_EVENT_UNLINK);
- if (ev->type == LNET_EVENT_SEND &&
- ev->status == 0 && !ev->unlinked)
- break; /* wait for the final LNET_EVENT_REPLY */
-
+ if (ev->type == LNET_EVENT_SEND && !ev->unlinked) {
+ if (ev->status == 0)
+ break; /* wait for the final LNET_EVENT_REPLY */
+ else
+ fired_flag = 0; /* LNET_EVENT_REPLY may arrive
+ (optimized GET case) */
+ }
case SRPC_BULK_PUT_SENT:
if (ev->status == 0 && ev->type != LNET_EVENT_UNLINK) {
spin_lock(&srpc_data.rpc_glock);
LASSERT (rpcev == &srpc->srpc_ev);
spin_lock(&sv->sv_lock);
- rpcev->ev_fired = 1;
- rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ?
+ if (fired_flag)
+ rpcev->ev_fired = 1;
+
+ rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ?
-EINTR : ev->status;
+
srpc_schedule_server_rpc(srpc);
spin_unlock(&sv->sv_lock);
break;
rc = LNetEQPoll(&srpc_data.rpc_lnet_eq, 1,
timeout * 1000, &ev, &i);
if (rc == 0) return 0;
-
+
LASSERT (rc == -EOVERFLOW || rc == 1);
-
+
/* We can't affort to miss any events... */
if (rc == -EOVERFLOW) {
CERROR ("Dropped an event!!!\n");
abort();
}
-
+
srpc_lnet_ev_handler(&ev);
return 1;
}
int i;
int rc;
+#ifndef __KERNEL__
+ char *s;
+
+ s = getenv("SRPC_PEER_CREDITS");
+ srpc_peer_credits = (s != NULL) ? atoi(s) : srpc_peer_credits;
+#endif
+
+ if (srpc_peer_credits <= 0) {
+ CERROR("Peer credits must be positive: %d\n", srpc_peer_credits);
+ return -EINVAL;
+ }
+
memset(&srpc_data, 0, sizeof(struct smoketest_rpc));
spin_lock_init(&srpc_data.rpc_glock);
#ifdef __KERNEL__
rc = LNetNIInit(LUSTRE_SRV_LNET_PID);
#else
- rc = LNetNIInit(getpid());
+ if (the_lnet.ln_server_mode_flag)
+ rc = LNetNIInit(LUSTRE_SRV_LNET_PID);
+ else
+ rc = LNetNIInit(getpid() | LNET_PID_USERFLAG);
#endif
if (rc < 0) {
CERROR ("LNetNIInit() has failed: %d\n", rc);
srpc_data.rpc_state = SRPC_STATE_NI_INIT;
- srpc_data.rpc_lnet_eq = LNET_EQ_NONE;
+ LNetInvalidateHandle(&srpc_data.rpc_lnet_eq);
#ifdef __KERNEL__
rc = LNetEQAlloc(16, srpc_lnet_ev_handler, &srpc_data.rpc_lnet_eq);
#else
LASSERT (list_empty(&peer->stp_rpcq));
LASSERT (list_empty(&peer->stp_ctl_rpcq));
- LASSERT (peer->stp_credits == SRPC_PEER_CREDITS);
+ LASSERT (peer->stp_credits == srpc_peer_credits);
LIBCFS_FREE(peer, sizeof(srpc_peer_t));
}