diff options
Diffstat (limited to 'drivers/staging/lustre/lnet/selftest')
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/Makefile | 7 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/brw_test.c | 526 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/conctl.c | 799 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/conrpc.c | 1397 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/conrpc.h | 143 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/console.c | 2101 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/console.h | 244 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/framework.c | 1786 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/module.c | 165 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/ping_test.c | 228 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/rpc.c | 1682 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/rpc.h | 295 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/selftest.h | 623 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/timer.c | 244 | ||||
-rw-r--r-- | drivers/staging/lustre/lnet/selftest/timer.h | 50 |
15 files changed, 0 insertions, 10290 deletions
diff --git a/drivers/staging/lustre/lnet/selftest/Makefile b/drivers/staging/lustre/lnet/selftest/Makefile deleted file mode 100644 index 3ccc8966b566..000000000000 --- a/drivers/staging/lustre/lnet/selftest/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include -subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include - -obj-$(CONFIG_LNET_SELFTEST) := lnet_selftest.o - -lnet_selftest-y := console.o conrpc.o conctl.o framework.o timer.o rpc.o \ - module.o ping_test.o brw_test.o diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c deleted file mode 100644 index f1ee219bc8f3..000000000000 --- a/drivers/staging/lustre/lnet/selftest/brw_test.c +++ /dev/null @@ -1,526 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 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. - * - * lnet/selftest/brw_test.c - * - * Author: Isaac Huang <isaac@clusterfs.com> - */ - -#include "selftest.h" - -static int brw_srv_workitems = SFW_TEST_WI_MAX; -module_param(brw_srv_workitems, int, 0644); -MODULE_PARM_DESC(brw_srv_workitems, "# BRW server workitems"); - -static int brw_inject_errors; -module_param(brw_inject_errors, int, 0644); -MODULE_PARM_DESC(brw_inject_errors, "# data errors to inject randomly, zero by default"); - -#define BRW_POISON 0xbeefbeefbeefbeefULL -#define BRW_MAGIC 0xeeb0eeb1eeb2eeb3ULL -#define BRW_MSIZE sizeof(u64) - -static void -brw_client_fini(struct sfw_test_instance *tsi) -{ - struct srpc_bulk *bulk; - struct sfw_test_unit *tsu; - - LASSERT(tsi->tsi_is_client); - - list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) { - bulk = tsu->tsu_private; - if (!bulk) - continue; - - srpc_free_bulk(bulk); - tsu->tsu_private = NULL; - } -} - -static int -brw_client_init(struct sfw_test_instance *tsi) -{ - struct sfw_session *sn = tsi->tsi_batch->bat_session; - int flags; - int off; - int npg; - int len; - int opc; - struct srpc_bulk *bulk; - struct sfw_test_unit *tsu; - - LASSERT(sn); - LASSERT(tsi->tsi_is_client); - - if (!(sn->sn_features & LST_FEAT_BULK_LEN)) { - struct test_bulk_req *breq = &tsi->tsi_u.bulk_v0; - - opc = breq->blk_opc; - flags = breq->blk_flags; - npg = breq->blk_npg; - /* - * NB: this is not going to work for variable page size, - * but we have to keep it for compatibility - */ - len = npg * PAGE_SIZE; - off = 0; - } else { - struct test_bulk_req_v1 *breq = &tsi->tsi_u.bulk_v1; - - /* - * I should never get this step if it's unknown feature - * because make_session will reject unknown feature - */ - LASSERT(!(sn->sn_features & ~LST_FEATS_MASK)); - - opc = breq->blk_opc; - flags = breq->blk_flags; - len = breq->blk_len; - off = breq->blk_offset & ~PAGE_MASK; - npg = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - } - - if (off % BRW_MSIZE) - return -EINVAL; - - if (npg > LNET_MAX_IOV || npg <= 0) - return -EINVAL; - - if (opc != LST_BRW_READ && opc != LST_BRW_WRITE) - return -EINVAL; - - if (flags != LST_BRW_CHECK_NONE && - flags != LST_BRW_CHECK_FULL && flags != LST_BRW_CHECK_SIMPLE) - return -EINVAL; - - list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) { - bulk = srpc_alloc_bulk(lnet_cpt_of_nid(tsu->tsu_dest.nid), - off, npg, len, opc == LST_BRW_READ); - if (!bulk) { - brw_client_fini(tsi); - return -ENOMEM; - } - - tsu->tsu_private = bulk; - } - - return 0; -} - -static int brw_inject_one_error(void) -{ - struct timespec64 ts; - - if (brw_inject_errors <= 0) - return 0; - - ktime_get_ts64(&ts); - - if (!((ts.tv_nsec / NSEC_PER_USEC) & 1)) - return 0; - - return brw_inject_errors--; -} - -static void -brw_fill_page(struct page *pg, int off, int len, int pattern, __u64 magic) -{ - char *addr = page_address(pg) + off; - int i; - - LASSERT(addr); - LASSERT(!(off % BRW_MSIZE) && !(len % BRW_MSIZE)); - - if (pattern == LST_BRW_CHECK_NONE) - return; - - if (magic == BRW_MAGIC) - magic += brw_inject_one_error(); - - if (pattern == LST_BRW_CHECK_SIMPLE) { - memcpy(addr, &magic, BRW_MSIZE); - if (len > BRW_MSIZE) { - addr += PAGE_SIZE - BRW_MSIZE; - memcpy(addr, &magic, BRW_MSIZE); - } - return; - } - - if (pattern == LST_BRW_CHECK_FULL) { - for (i = 0; i < len; i += BRW_MSIZE) - memcpy(addr + i, &magic, BRW_MSIZE); - return; - } - - LBUG(); -} - -static int -brw_check_page(struct page *pg, int off, int len, int pattern, __u64 magic) -{ - char *addr = page_address(pg) + off; - __u64 data = 0; /* make compiler happy */ - int i; - - LASSERT(addr); - LASSERT(!(off % BRW_MSIZE) && !(len % BRW_MSIZE)); - - if (pattern == LST_BRW_CHECK_NONE) - return 0; - - if (pattern == LST_BRW_CHECK_SIMPLE) { - data = *((__u64 *)addr); - if (data != magic) - goto bad_data; - - if (len > BRW_MSIZE) { - addr += PAGE_SIZE - BRW_MSIZE; - data = *((__u64 *)addr); - if (data != magic) - goto bad_data; - } - return 0; - } - - if (pattern == LST_BRW_CHECK_FULL) { - for (i = 0; i < len; i += BRW_MSIZE) { - data = *(u64 *)(addr + i); - if (data != magic) - goto bad_data; - } - return 0; - } - - LBUG(); - -bad_data: - CERROR("Bad data in page %p: %#llx, %#llx expected\n", - pg, data, magic); - return 1; -} - -static void -brw_fill_bulk(struct srpc_bulk *bk, int pattern, __u64 magic) -{ - int i; - struct page *pg; - - for (i = 0; i < bk->bk_niov; i++) { - int off, len; - - pg = bk->bk_iovs[i].bv_page; - off = bk->bk_iovs[i].bv_offset; - len = bk->bk_iovs[i].bv_len; - brw_fill_page(pg, off, len, pattern, magic); - } -} - -static int -brw_check_bulk(struct srpc_bulk *bk, int pattern, __u64 magic) -{ - int i; - struct page *pg; - - for (i = 0; i < bk->bk_niov; i++) { - int off, len; - - pg = bk->bk_iovs[i].bv_page; - off = bk->bk_iovs[i].bv_offset; - len = bk->bk_iovs[i].bv_len; - if (brw_check_page(pg, off, len, pattern, magic)) { - CERROR("Bulk page %p (%d/%d) is corrupted!\n", - pg, i, bk->bk_niov); - return 1; - } - } - - return 0; -} - -static int -brw_client_prep_rpc(struct sfw_test_unit *tsu, struct lnet_process_id dest, - struct srpc_client_rpc **rpcpp) -{ - struct srpc_bulk *bulk = tsu->tsu_private; - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct sfw_session *sn = tsi->tsi_batch->bat_session; - struct srpc_client_rpc *rpc; - struct srpc_brw_reqst *req; - int flags; - int npg; - int len; - int opc; - int rc; - - LASSERT(sn); - LASSERT(bulk); - - if (!(sn->sn_features & LST_FEAT_BULK_LEN)) { - struct test_bulk_req *breq = &tsi->tsi_u.bulk_v0; - - opc = breq->blk_opc; - flags = breq->blk_flags; - npg = breq->blk_npg; - len = npg * PAGE_SIZE; - } else { - struct test_bulk_req_v1 *breq = &tsi->tsi_u.bulk_v1; - int off; - - /* - * I should never get this step if it's unknown feature - * because make_session will reject unknown feature - */ - LASSERT(!(sn->sn_features & ~LST_FEATS_MASK)); - - opc = breq->blk_opc; - flags = breq->blk_flags; - len = breq->blk_len; - off = breq->blk_offset; - npg = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - } - - rc = sfw_create_test_rpc(tsu, dest, sn->sn_features, npg, len, &rpc); - if (rc) - return rc; - - memcpy(&rpc->crpc_bulk, bulk, offsetof(struct srpc_bulk, bk_iovs[npg])); - if (opc == LST_BRW_WRITE) - brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_MAGIC); - else - brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_POISON); - - req = &rpc->crpc_reqstmsg.msg_body.brw_reqst; - req->brw_flags = flags; - req->brw_rw = opc; - req->brw_len = len; - - *rpcpp = rpc; - return 0; -} - -static void -brw_client_done_rpc(struct sfw_test_unit *tsu, struct srpc_client_rpc *rpc) -{ - __u64 magic = BRW_MAGIC; - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct sfw_session *sn = tsi->tsi_batch->bat_session; - struct srpc_msg *msg = &rpc->crpc_replymsg; - struct srpc_brw_reply *reply = &msg->msg_body.brw_reply; - struct srpc_brw_reqst *reqst = &rpc->crpc_reqstmsg.msg_body.brw_reqst; - - LASSERT(sn); - - if (rpc->crpc_status) { - CERROR("BRW RPC to %s failed with %d\n", - libcfs_id2str(rpc->crpc_dest), rpc->crpc_status); - if (!tsi->tsi_stopping) /* rpc could have been aborted */ - atomic_inc(&sn->sn_brw_errors); - return; - } - - if (msg->msg_magic != SRPC_MSG_MAGIC) { - __swab64s(&magic); - __swab32s(&reply->brw_status); - } - - CDEBUG(reply->brw_status ? D_WARNING : D_NET, - "BRW RPC to %s finished with brw_status: %d\n", - libcfs_id2str(rpc->crpc_dest), reply->brw_status); - - if (reply->brw_status) { - atomic_inc(&sn->sn_brw_errors); - rpc->crpc_status = -(int)reply->brw_status; - return; - } - - if (reqst->brw_rw == LST_BRW_WRITE) - return; - - if (brw_check_bulk(&rpc->crpc_bulk, reqst->brw_flags, magic)) { - CERROR("Bulk data from %s is corrupted!\n", - libcfs_id2str(rpc->crpc_dest)); - atomic_inc(&sn->sn_brw_errors); - rpc->crpc_status = -EBADMSG; - } -} - -static void -brw_server_rpc_done(struct srpc_server_rpc *rpc) -{ - struct srpc_bulk *blk = rpc->srpc_bulk; - - if (!blk) - return; - - if (rpc->srpc_status) - CERROR("Bulk transfer %s %s has failed: %d\n", - blk->bk_sink ? "from" : "to", - libcfs_id2str(rpc->srpc_peer), rpc->srpc_status); - else - CDEBUG(D_NET, "Transferred %d pages bulk data %s %s\n", - blk->bk_niov, blk->bk_sink ? "from" : "to", - libcfs_id2str(rpc->srpc_peer)); - - sfw_free_pages(rpc); -} - -static int -brw_bulk_ready(struct srpc_server_rpc *rpc, int status) -{ - __u64 magic = BRW_MAGIC; - struct srpc_brw_reply *reply = &rpc->srpc_replymsg.msg_body.brw_reply; - struct srpc_brw_reqst *reqst; - struct srpc_msg *reqstmsg; - - LASSERT(rpc->srpc_bulk); - LASSERT(rpc->srpc_reqstbuf); - - reqstmsg = &rpc->srpc_reqstbuf->buf_msg; - reqst = &reqstmsg->msg_body.brw_reqst; - - if (status) { - CERROR("BRW bulk %s failed for RPC from %s: %d\n", - reqst->brw_rw == LST_BRW_READ ? "READ" : "WRITE", - libcfs_id2str(rpc->srpc_peer), status); - return -EIO; - } - - if (reqst->brw_rw == LST_BRW_READ) - return 0; - - if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) - __swab64s(&magic); - - if (brw_check_bulk(rpc->srpc_bulk, reqst->brw_flags, magic)) { - CERROR("Bulk data from %s is corrupted!\n", - libcfs_id2str(rpc->srpc_peer)); - reply->brw_status = EBADMSG; - } - - return 0; -} - -static int -brw_server_handle(struct srpc_server_rpc *rpc) -{ - struct srpc_service *sv = rpc->srpc_scd->scd_svc; - struct srpc_msg *replymsg = &rpc->srpc_replymsg; - struct srpc_msg *reqstmsg = &rpc->srpc_reqstbuf->buf_msg; - struct srpc_brw_reply *reply = &replymsg->msg_body.brw_reply; - struct srpc_brw_reqst *reqst = &reqstmsg->msg_body.brw_reqst; - int npg; - int rc; - - LASSERT(sv->sv_id == SRPC_SERVICE_BRW); - - if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) { - LASSERT(reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC)); - - __swab32s(&reqst->brw_rw); - __swab32s(&reqst->brw_len); - __swab32s(&reqst->brw_flags); - __swab64s(&reqst->brw_rpyid); - __swab64s(&reqst->brw_bulkid); - } - LASSERT(reqstmsg->msg_type == (__u32)srpc_service2request(sv->sv_id)); - - reply->brw_status = 0; - rpc->srpc_done = brw_server_rpc_done; - - if ((reqst->brw_rw != LST_BRW_READ && reqst->brw_rw != LST_BRW_WRITE) || - (reqst->brw_flags != LST_BRW_CHECK_NONE && - reqst->brw_flags != LST_BRW_CHECK_FULL && - reqst->brw_flags != LST_BRW_CHECK_SIMPLE)) { - reply->brw_status = EINVAL; - return 0; - } - - if (reqstmsg->msg_ses_feats & ~LST_FEATS_MASK) { - replymsg->msg_ses_feats = LST_FEATS_MASK; - reply->brw_status = EPROTO; - return 0; - } - - if (!(reqstmsg->msg_ses_feats & LST_FEAT_BULK_LEN)) { - /* compat with old version */ - if (reqst->brw_len & ~PAGE_MASK) { - reply->brw_status = EINVAL; - return 0; - } - npg = reqst->brw_len >> PAGE_SHIFT; - - } else { - npg = (reqst->brw_len + PAGE_SIZE - 1) >> PAGE_SHIFT; - } - - replymsg->msg_ses_feats = reqstmsg->msg_ses_feats; - - if (!reqst->brw_len || npg > LNET_MAX_IOV) { - reply->brw_status = EINVAL; - return 0; - } - - rc = sfw_alloc_pages(rpc, rpc->srpc_scd->scd_cpt, npg, - reqst->brw_len, - reqst->brw_rw == LST_BRW_WRITE); - if (rc) - return rc; - - if (reqst->brw_rw == LST_BRW_READ) - brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_MAGIC); - else - brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_POISON); - - return 0; -} - -struct sfw_test_client_ops brw_test_client; - -void brw_init_test_client(void) -{ - brw_test_client.tso_init = brw_client_init; - brw_test_client.tso_fini = brw_client_fini; - brw_test_client.tso_prep_rpc = brw_client_prep_rpc; - brw_test_client.tso_done_rpc = brw_client_done_rpc; -}; - -struct srpc_service brw_test_service; - -void brw_init_test_service(void) -{ - brw_test_service.sv_id = SRPC_SERVICE_BRW; - brw_test_service.sv_name = "brw_test"; - brw_test_service.sv_handler = brw_server_handle; - brw_test_service.sv_bulk_ready = brw_bulk_ready; - brw_test_service.sv_wi_total = brw_srv_workitems; -} diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c deleted file mode 100644 index a2d8092bdeb7..000000000000 --- a/drivers/staging/lustre/lnet/selftest/conctl.c +++ /dev/null @@ -1,799 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/conctl.c - * - * IOC handle in kernel - * - * Author: Liang Zhen <liangzhen@clusterfs.com> - */ - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-lnet.h> -#include <uapi/linux/lnet/lnetst.h> -#include "console.h" - -static int -lst_session_new_ioctl(struct lstio_session_new_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int rc; - - if (!args->lstio_ses_idp || /* address for output sid */ - !args->lstio_ses_key || /* no key is specified */ - !args->lstio_ses_namep || /* session name */ - args->lstio_ses_nmlen <= 0 || - args->lstio_ses_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_ses_namep, - args->lstio_ses_nmlen)) { - return -EFAULT; - } - - name[args->lstio_ses_nmlen] = 0; - - rc = lstcon_session_new(name, - args->lstio_ses_key, - args->lstio_ses_feats, - args->lstio_ses_timeout, - args->lstio_ses_force, - args->lstio_ses_idp); - - return rc; -} - -static int -lst_session_end_ioctl(struct lstio_session_end_args *args) -{ - if (args->lstio_ses_key != console_session.ses_key) - return -EACCES; - - return lstcon_session_end(); -} - -static int -lst_session_info_ioctl(struct lstio_session_info_args *args) -{ - /* no checking of key */ - - if (!args->lstio_ses_idp || /* address for output sid */ - !args->lstio_ses_keyp || /* address for output key */ - !args->lstio_ses_featp || /* address for output features */ - !args->lstio_ses_ndinfo || /* address for output ndinfo */ - !args->lstio_ses_namep || /* address for output name */ - args->lstio_ses_nmlen <= 0 || - args->lstio_ses_nmlen > LST_NAME_SIZE) - return -EINVAL; - - return lstcon_session_info(args->lstio_ses_idp, - args->lstio_ses_keyp, - args->lstio_ses_featp, - args->lstio_ses_ndinfo, - args->lstio_ses_namep, - args->lstio_ses_nmlen); -} - -static int -lst_debug_ioctl(struct lstio_debug_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int client = 1; - int rc; - - if (args->lstio_dbg_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_dbg_resultp) - return -EINVAL; - - if (args->lstio_dbg_namep && /* name of batch/group */ - (args->lstio_dbg_nmlen <= 0 || - args->lstio_dbg_nmlen > LST_NAME_SIZE)) - return -EINVAL; - - if (args->lstio_dbg_namep) { - - if (copy_from_user(name, args->lstio_dbg_namep, - args->lstio_dbg_nmlen)) - return -EFAULT; - - name[args->lstio_dbg_nmlen] = 0; - } - - rc = -EINVAL; - - switch (args->lstio_dbg_type) { - case LST_OPC_SESSION: - rc = lstcon_session_debug(args->lstio_dbg_timeout, - args->lstio_dbg_resultp); - break; - - case LST_OPC_BATCHSRV: - client = 0; - /* fall through */ - case LST_OPC_BATCHCLI: - if (!args->lstio_dbg_namep) - goto out; - - rc = lstcon_batch_debug(args->lstio_dbg_timeout, - name, client, args->lstio_dbg_resultp); - break; - - case LST_OPC_GROUP: - if (!args->lstio_dbg_namep) - goto out; - - rc = lstcon_group_debug(args->lstio_dbg_timeout, - name, args->lstio_dbg_resultp); - break; - - case LST_OPC_NODES: - if (args->lstio_dbg_count <= 0 || - !args->lstio_dbg_idsp) - goto out; - - rc = lstcon_nodes_debug(args->lstio_dbg_timeout, - args->lstio_dbg_count, - args->lstio_dbg_idsp, - args->lstio_dbg_resultp); - break; - - default: - break; - } - -out: - return rc; -} - -static int -lst_group_add_ioctl(struct lstio_group_add_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int rc; - - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_grp_namep, - args->lstio_grp_nmlen)) - return -EFAULT; - - name[args->lstio_grp_nmlen] = 0; - - rc = lstcon_group_add(name); - - return rc; -} - -static int -lst_group_del_ioctl(struct lstio_group_del_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_grp_namep, - args->lstio_grp_nmlen)) - return -EFAULT; - - name[args->lstio_grp_nmlen] = 0; - - rc = lstcon_group_del(name); - - return rc; -} - -static int -lst_group_update_ioctl(struct lstio_group_update_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_grp_resultp || - !args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_grp_namep, - args->lstio_grp_nmlen)) - return -EFAULT; - - name[args->lstio_grp_nmlen] = 0; - - switch (args->lstio_grp_opc) { - case LST_GROUP_CLEAN: - rc = lstcon_group_clean(name, args->lstio_grp_args); - break; - - case LST_GROUP_REFRESH: - rc = lstcon_group_refresh(name, args->lstio_grp_resultp); - break; - - case LST_GROUP_RMND: - if (args->lstio_grp_count <= 0 || - !args->lstio_grp_idsp) { - rc = -EINVAL; - break; - } - rc = lstcon_nodes_remove(name, args->lstio_grp_count, - args->lstio_grp_idsp, - args->lstio_grp_resultp); - break; - - default: - rc = -EINVAL; - break; - } - - return rc; -} - -static int -lst_nodes_add_ioctl(struct lstio_group_nodes_args *args) -{ - unsigned int feats; - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_grp_idsp || /* array of ids */ - args->lstio_grp_count <= 0 || - !args->lstio_grp_resultp || - !args->lstio_grp_featp || - !args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_grp_namep, - args->lstio_grp_nmlen)) - return -EFAULT; - - name[args->lstio_grp_nmlen] = 0; - - rc = lstcon_nodes_add(name, args->lstio_grp_count, - args->lstio_grp_idsp, &feats, - args->lstio_grp_resultp); - - if (!rc && - copy_to_user(args->lstio_grp_featp, &feats, sizeof(feats))) { - return -EINVAL; - } - - return rc; -} - -static int -lst_group_list_ioctl(struct lstio_group_list_args *args) -{ - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (args->lstio_grp_idx < 0 || - !args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - return lstcon_group_list(args->lstio_grp_idx, - args->lstio_grp_nmlen, - args->lstio_grp_namep); -} - -static int -lst_group_info_ioctl(struct lstio_group_info_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int ndent; - int index; - int rc; - - if (args->lstio_grp_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_grp_namep || - args->lstio_grp_nmlen <= 0 || - args->lstio_grp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (!args->lstio_grp_entp && /* output: group entry */ - !args->lstio_grp_dentsp) /* output: node entry */ - return -EINVAL; - - if (args->lstio_grp_dentsp) { /* have node entry */ - if (!args->lstio_grp_idxp || /* node index */ - !args->lstio_grp_ndentp) /* # of node entry */ - return -EINVAL; - - if (copy_from_user(&ndent, args->lstio_grp_ndentp, - sizeof(ndent)) || - copy_from_user(&index, args->lstio_grp_idxp, - sizeof(index))) - return -EFAULT; - - if (ndent <= 0 || index < 0) - return -EINVAL; - } - - if (copy_from_user(name, args->lstio_grp_namep, - args->lstio_grp_nmlen)) - return -EFAULT; - - name[args->lstio_grp_nmlen] = 0; - - rc = lstcon_group_info(name, args->lstio_grp_entp, - &index, &ndent, args->lstio_grp_dentsp); - - if (rc) - return rc; - - if (args->lstio_grp_dentsp && - (copy_to_user(args->lstio_grp_idxp, &index, sizeof(index)) || - copy_to_user(args->lstio_grp_ndentp, &ndent, sizeof(ndent)))) - return -EFAULT; - - return 0; -} - -static int -lst_batch_add_ioctl(struct lstio_batch_add_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_bat_namep || - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_bat_namep, - args->lstio_bat_nmlen)) - return -EFAULT; - - name[args->lstio_bat_nmlen] = 0; - - rc = lstcon_batch_add(name); - - return rc; -} - -static int -lst_batch_run_ioctl(struct lstio_batch_run_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_bat_namep || - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_bat_namep, - args->lstio_bat_nmlen)) - return -EFAULT; - - name[args->lstio_bat_nmlen] = 0; - - rc = lstcon_batch_run(name, args->lstio_bat_timeout, - args->lstio_bat_resultp); - - return rc; -} - -static int -lst_batch_stop_ioctl(struct lstio_batch_stop_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_bat_resultp || - !args->lstio_bat_namep || - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (copy_from_user(name, args->lstio_bat_namep, - args->lstio_bat_nmlen)) - return -EFAULT; - - name[args->lstio_bat_nmlen] = 0; - - rc = lstcon_batch_stop(name, args->lstio_bat_force, - args->lstio_bat_resultp); - - return rc; -} - -static int -lst_batch_query_ioctl(struct lstio_batch_query_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int rc; - - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_bat_resultp || - !args->lstio_bat_namep || - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (args->lstio_bat_testidx < 0) - return -EINVAL; - - if (copy_from_user(name, args->lstio_bat_namep, - args->lstio_bat_nmlen)) - return -EFAULT; - - name[args->lstio_bat_nmlen] = 0; - - rc = lstcon_test_batch_query(name, - args->lstio_bat_testidx, - args->lstio_bat_client, - args->lstio_bat_timeout, - args->lstio_bat_resultp); - - return rc; -} - -static int -lst_batch_list_ioctl(struct lstio_batch_list_args *args) -{ - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (args->lstio_bat_idx < 0 || - !args->lstio_bat_namep || - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - return lstcon_batch_list(args->lstio_bat_idx, - args->lstio_bat_nmlen, - args->lstio_bat_namep); -} - -static int -lst_batch_info_ioctl(struct lstio_batch_info_args *args) -{ - char name[LST_NAME_SIZE + 1]; - int rc; - int index; - int ndent; - - if (args->lstio_bat_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_bat_namep || /* batch name */ - args->lstio_bat_nmlen <= 0 || - args->lstio_bat_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (!args->lstio_bat_entp && /* output: batch entry */ - !args->lstio_bat_dentsp) /* output: node entry */ - return -EINVAL; - - if (args->lstio_bat_dentsp) { /* have node entry */ - if (!args->lstio_bat_idxp || /* node index */ - !args->lstio_bat_ndentp) /* # of node entry */ - return -EINVAL; - - if (copy_from_user(&index, args->lstio_bat_idxp, - sizeof(index)) || - copy_from_user(&ndent, args->lstio_bat_ndentp, - sizeof(ndent))) - return -EFAULT; - - if (ndent <= 0 || index < 0) - return -EINVAL; - } - - if (copy_from_user(name, args->lstio_bat_namep, - args->lstio_bat_nmlen)) - return -EFAULT; - - name[args->lstio_bat_nmlen] = 0; - - rc = lstcon_batch_info(name, args->lstio_bat_entp, - args->lstio_bat_server, args->lstio_bat_testidx, - &index, &ndent, args->lstio_bat_dentsp); - - if (rc) - return rc; - - if (args->lstio_bat_dentsp && - (copy_to_user(args->lstio_bat_idxp, &index, sizeof(index)) || - copy_to_user(args->lstio_bat_ndentp, &ndent, sizeof(ndent)))) - rc = -EFAULT; - - return rc; -} - -static int -lst_stat_query_ioctl(struct lstio_stat_args *args) -{ - int rc; - char name[LST_NAME_SIZE + 1]; - - /* TODO: not finished */ - if (args->lstio_sta_key != console_session.ses_key) - return -EACCES; - - if (!args->lstio_sta_resultp) - return -EINVAL; - - if (args->lstio_sta_idsp) { - if (args->lstio_sta_count <= 0) - return -EINVAL; - - rc = lstcon_nodes_stat(args->lstio_sta_count, - args->lstio_sta_idsp, - args->lstio_sta_timeout, - args->lstio_sta_resultp); - } else if (args->lstio_sta_namep) { - if (args->lstio_sta_nmlen <= 0 || - args->lstio_sta_nmlen > LST_NAME_SIZE) - return -EINVAL; - - rc = copy_from_user(name, args->lstio_sta_namep, - args->lstio_sta_nmlen); - if (!rc) - rc = lstcon_group_stat(name, args->lstio_sta_timeout, - args->lstio_sta_resultp); - else - rc = -EFAULT; - } else { - rc = -EINVAL; - } - - return rc; -} - -static int lst_test_add_ioctl(struct lstio_test_args *args) -{ - char batch_name[LST_NAME_SIZE + 1]; - char src_name[LST_NAME_SIZE + 1]; - char dst_name[LST_NAME_SIZE + 1]; - void *param = NULL; - int ret = 0; - int rc = -ENOMEM; - - if (!args->lstio_tes_resultp || - !args->lstio_tes_retp || - !args->lstio_tes_bat_name || /* no specified batch */ - args->lstio_tes_bat_nmlen <= 0 || - args->lstio_tes_bat_nmlen > LST_NAME_SIZE || - !args->lstio_tes_sgrp_name || /* no source group */ - args->lstio_tes_sgrp_nmlen <= 0 || - args->lstio_tes_sgrp_nmlen > LST_NAME_SIZE || - !args->lstio_tes_dgrp_name || /* no target group */ - args->lstio_tes_dgrp_nmlen <= 0 || - args->lstio_tes_dgrp_nmlen > LST_NAME_SIZE) - return -EINVAL; - - if (!args->lstio_tes_loop || /* negative is infinite */ - args->lstio_tes_concur <= 0 || - args->lstio_tes_dist <= 0 || - args->lstio_tes_span <= 0) - return -EINVAL; - - /* have parameter, check if parameter length is valid */ - if (args->lstio_tes_param && - (args->lstio_tes_param_len <= 0 || - args->lstio_tes_param_len > - PAGE_SIZE - sizeof(struct lstcon_test))) - return -EINVAL; - - /* Enforce zero parameter length if there's no parameter */ - if (!args->lstio_tes_param && args->lstio_tes_param_len) - return -EINVAL; - - if (args->lstio_tes_param) { - param = memdup_user(args->lstio_tes_param, - args->lstio_tes_param_len); - if (IS_ERR(param)) - return PTR_ERR(param); - } - - rc = -EFAULT; - if (copy_from_user(batch_name, args->lstio_tes_bat_name, - args->lstio_tes_bat_nmlen) || - copy_from_user(src_name, args->lstio_tes_sgrp_name, - args->lstio_tes_sgrp_nmlen) || - copy_from_user(dst_name, args->lstio_tes_dgrp_name, - args->lstio_tes_dgrp_nmlen)) - goto out; - - rc = lstcon_test_add(batch_name, args->lstio_tes_type, - args->lstio_tes_loop, args->lstio_tes_concur, - args->lstio_tes_dist, args->lstio_tes_span, - src_name, dst_name, param, - args->lstio_tes_param_len, - &ret, args->lstio_tes_resultp); - - if (!rc && ret) - rc = (copy_to_user(args->lstio_tes_retp, &ret, - sizeof(ret))) ? -EFAULT : 0; -out: - kfree(param); - - return rc; -} - -int -lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr) -{ - char *buf; - struct libcfs_ioctl_data *data; - int opc; - int rc; - - if (cmd != IOC_LIBCFS_LNETST) - return -EINVAL; - - data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr); - - opc = data->ioc_u32[0]; - - if (data->ioc_plen1 > PAGE_SIZE) - return -EINVAL; - - buf = kmalloc(data->ioc_plen1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* copy in parameter */ - if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { - kfree(buf); - return -EFAULT; - } - - mutex_lock(&console_session.ses_mutex); - - console_session.ses_laststamp = ktime_get_real_seconds(); - - if (console_session.ses_shutdown) { - rc = -ESHUTDOWN; - goto out; - } - - if (console_session.ses_expired) - lstcon_session_end(); - - if (opc != LSTIO_SESSION_NEW && - console_session.ses_state == LST_SESSION_NONE) { - CDEBUG(D_NET, "LST no active session\n"); - rc = -ESRCH; - goto out; - } - - memset(&console_session.ses_trans_stat, 0, sizeof(struct lstcon_trans_stat)); - - switch (opc) { - case LSTIO_SESSION_NEW: - rc = lst_session_new_ioctl((struct lstio_session_new_args *)buf); - break; - case LSTIO_SESSION_END: - rc = lst_session_end_ioctl((struct lstio_session_end_args *)buf); - break; - case LSTIO_SESSION_INFO: - rc = lst_session_info_ioctl((struct lstio_session_info_args *)buf); - break; - case LSTIO_DEBUG: - rc = lst_debug_ioctl((struct lstio_debug_args *)buf); - break; - case LSTIO_GROUP_ADD: - rc = lst_group_add_ioctl((struct lstio_group_add_args *)buf); - break; - case LSTIO_GROUP_DEL: - rc = lst_group_del_ioctl((struct lstio_group_del_args *)buf); - break; - case LSTIO_GROUP_UPDATE: - rc = lst_group_update_ioctl((struct lstio_group_update_args *)buf); - break; - case LSTIO_NODES_ADD: - rc = lst_nodes_add_ioctl((struct lstio_group_nodes_args *)buf); - break; - case LSTIO_GROUP_LIST: - rc = lst_group_list_ioctl((struct lstio_group_list_args *)buf); - break; - case LSTIO_GROUP_INFO: - rc = lst_group_info_ioctl((struct lstio_group_info_args *)buf); - break; - case LSTIO_BATCH_ADD: - rc = lst_batch_add_ioctl((struct lstio_batch_add_args *)buf); - break; - case LSTIO_BATCH_START: - rc = lst_batch_run_ioctl((struct lstio_batch_run_args *)buf); - break; - case LSTIO_BATCH_STOP: - rc = lst_batch_stop_ioctl((struct lstio_batch_stop_args *)buf); - break; - case LSTIO_BATCH_QUERY: - rc = lst_batch_query_ioctl((struct lstio_batch_query_args *)buf); - break; - case LSTIO_BATCH_LIST: - rc = lst_batch_list_ioctl((struct lstio_batch_list_args *)buf); - break; - case LSTIO_BATCH_INFO: - rc = lst_batch_info_ioctl((struct lstio_batch_info_args *)buf); - break; - case LSTIO_TEST_ADD: - rc = lst_test_add_ioctl((struct lstio_test_args *)buf); - break; - case LSTIO_STAT_QUERY: - rc = lst_stat_query_ioctl((struct lstio_stat_args *)buf); - break; - default: - rc = -EINVAL; - } - - if (copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat, - sizeof(struct lstcon_trans_stat))) - rc = -EFAULT; -out: - mutex_unlock(&console_session.ses_mutex); - - kfree(buf); - - return rc; -} diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c deleted file mode 100644 index 6dcc966b293b..000000000000 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ /dev/null @@ -1,1397 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/conctl.c - * - * Console framework rpcs - * - * Author: Liang Zhen <liang@whamcloud.com> - */ - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-lnet.h> -#include "timer.h" -#include "conrpc.h" -#include "console.h" - -void lstcon_rpc_stat_reply(struct lstcon_rpc_trans *, struct srpc_msg *, - struct lstcon_node *, struct lstcon_trans_stat *); - -static void -lstcon_rpc_done(struct srpc_client_rpc *rpc) -{ - struct lstcon_rpc *crpc = (struct lstcon_rpc *)rpc->crpc_priv; - - LASSERT(crpc && rpc == crpc->crp_rpc); - LASSERT(crpc->crp_posted && !crpc->crp_finished); - - spin_lock(&rpc->crpc_lock); - - if (!crpc->crp_trans) { - /* - * Orphan RPC is not in any transaction, - * I'm just a poor body and nobody loves me - */ - spin_unlock(&rpc->crpc_lock); - - /* release it */ - lstcon_rpc_put(crpc); - return; - } - - /* not an orphan RPC */ - crpc->crp_finished = 1; - - if (!crpc->crp_stamp) { - /* not aborted */ - LASSERT(!crpc->crp_status); - - crpc->crp_stamp = cfs_time_current(); - crpc->crp_status = rpc->crpc_status; - } - - /* wakeup (transaction)thread if I'm the last RPC in the transaction */ - if (atomic_dec_and_test(&crpc->crp_trans->tas_remaining)) - wake_up(&crpc->crp_trans->tas_waitq); - - spin_unlock(&rpc->crpc_lock); -} - -static int -lstcon_rpc_init(struct lstcon_node *nd, int service, unsigned int feats, - int bulk_npg, int bulk_len, int embedded, - struct lstcon_rpc *crpc) -{ - crpc->crp_rpc = sfw_create_rpc(nd->nd_id, service, - feats, bulk_npg, bulk_len, - lstcon_rpc_done, (void *)crpc); - if (!crpc->crp_rpc) - return -ENOMEM; - - crpc->crp_trans = NULL; - crpc->crp_node = nd; - crpc->crp_posted = 0; - crpc->crp_finished = 0; - crpc->crp_unpacked = 0; - crpc->crp_status = 0; - crpc->crp_stamp = 0; - crpc->crp_embedded = embedded; - INIT_LIST_HEAD(&crpc->crp_link); - - atomic_inc(&console_session.ses_rpc_counter); - - return 0; -} - -static int -lstcon_rpc_prep(struct lstcon_node *nd, int service, unsigned int feats, - int bulk_npg, int bulk_len, struct lstcon_rpc **crpcpp) -{ - struct lstcon_rpc *crpc = NULL; - int rc; - - spin_lock(&console_session.ses_rpc_lock); - - crpc = list_first_entry_or_null(&console_session.ses_rpc_freelist, - struct lstcon_rpc, crp_link); - if (crpc) - list_del_init(&crpc->crp_link); - - spin_unlock(&console_session.ses_rpc_lock); - - if (!crpc) { - crpc = kzalloc(sizeof(*crpc), GFP_NOFS); - if (!crpc) - return -ENOMEM; - } - - rc = lstcon_rpc_init(nd, service, feats, bulk_npg, bulk_len, 0, crpc); - if (!rc) { - *crpcpp = crpc; - return 0; - } - - kfree(crpc); - - return rc; -} - -void -lstcon_rpc_put(struct lstcon_rpc *crpc) -{ - struct srpc_bulk *bulk = &crpc->crp_rpc->crpc_bulk; - int i; - - LASSERT(list_empty(&crpc->crp_link)); - - for (i = 0; i < bulk->bk_niov; i++) { - if (!bulk->bk_iovs[i].bv_page) - continue; - - __free_page(bulk->bk_iovs[i].bv_page); - } - - srpc_client_rpc_decref(crpc->crp_rpc); - - if (crpc->crp_embedded) { - /* embedded RPC, don't recycle it */ - memset(crpc, 0, sizeof(*crpc)); - crpc->crp_embedded = 1; - - } else { - spin_lock(&console_session.ses_rpc_lock); - - list_add(&crpc->crp_link, - &console_session.ses_rpc_freelist); - - spin_unlock(&console_session.ses_rpc_lock); - } - - /* RPC is not alive now */ - atomic_dec(&console_session.ses_rpc_counter); -} - -static void -lstcon_rpc_post(struct lstcon_rpc *crpc) -{ - struct lstcon_rpc_trans *trans = crpc->crp_trans; - - LASSERT(trans); - - atomic_inc(&trans->tas_remaining); - crpc->crp_posted = 1; - - sfw_post_rpc(crpc->crp_rpc); -} - -static char * -lstcon_rpc_trans_name(int transop) -{ - if (transop == LST_TRANS_SESNEW) - return "SESNEW"; - - if (transop == LST_TRANS_SESEND) - return "SESEND"; - - if (transop == LST_TRANS_SESQRY) - return "SESQRY"; - - if (transop == LST_TRANS_SESPING) - return "SESPING"; - - if (transop == LST_TRANS_TSBCLIADD) - return "TSBCLIADD"; - - if (transop == LST_TRANS_TSBSRVADD) - return "TSBSRVADD"; - - if (transop == LST_TRANS_TSBRUN) - return "TSBRUN"; - - if (transop == LST_TRANS_TSBSTOP) - return "TSBSTOP"; - - if (transop == LST_TRANS_TSBCLIQRY) - return "TSBCLIQRY"; - - if (transop == LST_TRANS_TSBSRVQRY) - return "TSBSRVQRY"; - - if (transop == LST_TRANS_STATQRY) - return "STATQRY"; - - return "Unknown"; -} - -int -lstcon_rpc_trans_prep(struct list_head *translist, int transop, - struct lstcon_rpc_trans **transpp) -{ - struct lstcon_rpc_trans *trans; - - if (translist) { - list_for_each_entry(trans, translist, tas_link) { - /* - * Can't enqueue two private transaction on - * the same object - */ - if ((trans->tas_opc & transop) == LST_TRANS_PRIVATE) - return -EPERM; - } - } - - /* create a trans group */ - trans = kzalloc(sizeof(*trans), GFP_NOFS); - if (!trans) - return -ENOMEM; - - trans->tas_opc = transop; - - if (!translist) - INIT_LIST_HEAD(&trans->tas_olink); - else - list_add_tail(&trans->tas_olink, translist); - - list_add_tail(&trans->tas_link, &console_session.ses_trans_list); - - INIT_LIST_HEAD(&trans->tas_rpcs_list); - atomic_set(&trans->tas_remaining, 0); - init_waitqueue_head(&trans->tas_waitq); - - spin_lock(&console_session.ses_rpc_lock); - trans->tas_features = console_session.ses_features; - spin_unlock(&console_session.ses_rpc_lock); - - *transpp = trans; - return 0; -} - -void -lstcon_rpc_trans_addreq(struct lstcon_rpc_trans *trans, struct lstcon_rpc *crpc) -{ - list_add_tail(&crpc->crp_link, &trans->tas_rpcs_list); - crpc->crp_trans = trans; -} - -void -lstcon_rpc_trans_abort(struct lstcon_rpc_trans *trans, int error) -{ - struct srpc_client_rpc *rpc; - struct lstcon_rpc *crpc; - struct lstcon_node *nd; - - list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { - rpc = crpc->crp_rpc; - - spin_lock(&rpc->crpc_lock); - - if (!crpc->crp_posted || /* not posted */ - crpc->crp_stamp) { /* rpc done or aborted already */ - if (!crpc->crp_stamp) { - crpc->crp_stamp = cfs_time_current(); - crpc->crp_status = -EINTR; - } - spin_unlock(&rpc->crpc_lock); - continue; - } - - crpc->crp_stamp = cfs_time_current(); - crpc->crp_status = error; - - spin_unlock(&rpc->crpc_lock); - - sfw_abort_rpc(rpc); - - if (error != -ETIMEDOUT) - continue; - - nd = crpc->crp_node; - if (cfs_time_after(nd->nd_stamp, crpc->crp_stamp)) - continue; - - nd->nd_stamp = crpc->crp_stamp; - nd->nd_state = LST_NODE_DOWN; - } -} - -static int -lstcon_rpc_trans_check(struct lstcon_rpc_trans *trans) -{ - if (console_session.ses_shutdown && - !list_empty(&trans->tas_olink)) /* Not an end session RPC */ - return 1; - - return !atomic_read(&trans->tas_remaining) ? 1 : 0; -} - -int -lstcon_rpc_trans_postwait(struct lstcon_rpc_trans *trans, int timeout) -{ - struct lstcon_rpc *crpc; - int rc; - - if (list_empty(&trans->tas_rpcs_list)) - return 0; - - if (timeout < LST_TRANS_MIN_TIMEOUT) - timeout = LST_TRANS_MIN_TIMEOUT; - - CDEBUG(D_NET, "Transaction %s started\n", - lstcon_rpc_trans_name(trans->tas_opc)); - - /* post all requests */ - list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { - LASSERT(!crpc->crp_posted); - - lstcon_rpc_post(crpc); - } - - mutex_unlock(&console_session.ses_mutex); - - rc = wait_event_interruptible_timeout(trans->tas_waitq, - lstcon_rpc_trans_check(trans), - timeout * HZ); - rc = (rc > 0) ? 0 : ((rc < 0) ? -EINTR : -ETIMEDOUT); - - mutex_lock(&console_session.ses_mutex); - - if (console_session.ses_shutdown) - rc = -ESHUTDOWN; - - if (rc || atomic_read(&trans->tas_remaining)) { - /* treat short timeout as canceled */ - if (rc == -ETIMEDOUT && timeout < LST_TRANS_MIN_TIMEOUT * 2) - rc = -EINTR; - - lstcon_rpc_trans_abort(trans, rc); - } - - CDEBUG(D_NET, "Transaction %s stopped: %d\n", - lstcon_rpc_trans_name(trans->tas_opc), rc); - - lstcon_rpc_trans_stat(trans, lstcon_trans_stat()); - - return rc; -} - -static int -lstcon_rpc_get_reply(struct lstcon_rpc *crpc, struct srpc_msg **msgpp) -{ - struct lstcon_node *nd = crpc->crp_node; - struct srpc_client_rpc *rpc = crpc->crp_rpc; - struct srpc_generic_reply *rep; - - LASSERT(nd && rpc); - LASSERT(crpc->crp_stamp); - - if (crpc->crp_status) { - *msgpp = NULL; - return crpc->crp_status; - } - - *msgpp = &rpc->crpc_replymsg; - if (!crpc->crp_unpacked) { - sfw_unpack_message(*msgpp); - crpc->crp_unpacked = 1; - } - - if (cfs_time_after(nd->nd_stamp, crpc->crp_stamp)) - return 0; - - nd->nd_stamp = crpc->crp_stamp; - rep = &(*msgpp)->msg_body.reply; - - if (rep->sid.ses_nid == LNET_NID_ANY) - nd->nd_state = LST_NODE_UNKNOWN; - else if (lstcon_session_match(rep->sid)) - nd->nd_state = LST_NODE_ACTIVE; - else - nd->nd_state = LST_NODE_BUSY; - - return 0; -} - -void -lstcon_rpc_trans_stat(struct lstcon_rpc_trans *trans, struct lstcon_trans_stat *stat) -{ - struct lstcon_rpc *crpc; - struct srpc_msg *rep; - int error; - - LASSERT(stat); - - memset(stat, 0, sizeof(*stat)); - - list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { - lstcon_rpc_stat_total(stat, 1); - - LASSERT(crpc->crp_stamp); - - error = lstcon_rpc_get_reply(crpc, &rep); - if (error) { - lstcon_rpc_stat_failure(stat, 1); - if (!stat->trs_rpc_errno) - stat->trs_rpc_errno = -error; - - continue; - } - - lstcon_rpc_stat_success(stat, 1); - - lstcon_rpc_stat_reply(trans, rep, crpc->crp_node, stat); - } - - if (trans->tas_opc == LST_TRANS_SESNEW && !stat->trs_fwk_errno) { - stat->trs_fwk_errno = - lstcon_session_feats_check(trans->tas_features); - } - - CDEBUG(D_NET, "transaction %s : success %d, failure %d, total %d, RPC error(%d), Framework error(%d)\n", - lstcon_rpc_trans_name(trans->tas_opc), - lstcon_rpc_stat_success(stat, 0), - lstcon_rpc_stat_failure(stat, 0), - lstcon_rpc_stat_total(stat, 0), - stat->trs_rpc_errno, stat->trs_fwk_errno); -} - -int -lstcon_rpc_trans_interpreter(struct lstcon_rpc_trans *trans, - struct list_head __user *head_up, - lstcon_rpc_readent_func_t readent) -{ - struct list_head tmp; - struct list_head __user *next; - struct lstcon_rpc_ent *ent; - struct srpc_generic_reply *rep; - struct lstcon_rpc *crpc; - struct srpc_msg *msg; - struct lstcon_node *nd; - long dur; - struct timeval tv; - int error; - - LASSERT(head_up); - - next = head_up; - - list_for_each_entry(crpc, &trans->tas_rpcs_list, crp_link) { - if (copy_from_user(&tmp, next, - sizeof(struct list_head))) - return -EFAULT; - - next = tmp.next; - if (next == head_up) - return 0; - - ent = list_entry(next, struct lstcon_rpc_ent, rpe_link); - - LASSERT(crpc->crp_stamp); - - error = lstcon_rpc_get_reply(crpc, &msg); - - nd = crpc->crp_node; - - dur = (long)cfs_time_sub(crpc->crp_stamp, - (unsigned long)console_session.ses_id.ses_stamp); - jiffies_to_timeval(dur, &tv); - - if (copy_to_user(&ent->rpe_peer, &nd->nd_id, - sizeof(struct lnet_process_id)) || - copy_to_user(&ent->rpe_stamp, &tv, sizeof(tv)) || - copy_to_user(&ent->rpe_state, &nd->nd_state, - sizeof(nd->nd_state)) || - copy_to_user(&ent->rpe_rpc_errno, &error, - sizeof(error))) - return -EFAULT; - - if (error) - continue; - - /* RPC is done */ - rep = (struct srpc_generic_reply *)&msg->msg_body.reply; - - if (copy_to_user(&ent->rpe_sid, &rep->sid, sizeof(rep->sid)) || - copy_to_user(&ent->rpe_fwk_errno, &rep->status, - sizeof(rep->status))) - return -EFAULT; - - if (!readent) - continue; - - error = readent(trans->tas_opc, msg, ent); - if (error) - return error; - } - - return 0; -} - -void -lstcon_rpc_trans_destroy(struct lstcon_rpc_trans *trans) -{ - struct srpc_client_rpc *rpc; - struct lstcon_rpc *crpc; - struct lstcon_rpc *tmp; - int count = 0; - - list_for_each_entry_safe(crpc, tmp, &trans->tas_rpcs_list, crp_link) { - rpc = crpc->crp_rpc; - - spin_lock(&rpc->crpc_lock); - - /* free it if not posted or finished already */ - if (!crpc->crp_posted || crpc->crp_finished) { - spin_unlock(&rpc->crpc_lock); - - list_del_init(&crpc->crp_link); - lstcon_rpc_put(crpc); - - continue; - } - - /* - * rpcs can be still not callbacked (even LNetMDUnlink is - * called) because huge timeout for inaccessible network, - * don't make user wait for them, just abandon them, they - * will be recycled in callback - */ - LASSERT(crpc->crp_status); - - crpc->crp_node = NULL; - crpc->crp_trans = NULL; - list_del_init(&crpc->crp_link); - count++; - - spin_unlock(&rpc->crpc_lock); - - atomic_dec(&trans->tas_remaining); - } - - LASSERT(!atomic_read(&trans->tas_remaining)); - - list_del(&trans->tas_link); - if (!list_empty(&trans->tas_olink)) - list_del(&trans->tas_olink); - - CDEBUG(D_NET, "Transaction %s destroyed with %d pending RPCs\n", - lstcon_rpc_trans_name(trans->tas_opc), count); - - kfree(trans); -} - -int -lstcon_sesrpc_prep(struct lstcon_node *nd, int transop, - unsigned int feats, struct lstcon_rpc **crpc) -{ - struct srpc_mksn_reqst *msrq; - struct srpc_rmsn_reqst *rsrq; - int rc; - - switch (transop) { - case LST_TRANS_SESNEW: - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_MAKE_SESSION, - feats, 0, 0, crpc); - if (rc) - return rc; - - msrq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.mksn_reqst; - msrq->mksn_sid = console_session.ses_id; - msrq->mksn_force = console_session.ses_force; - strlcpy(msrq->mksn_name, console_session.ses_name, - sizeof(msrq->mksn_name)); - break; - - case LST_TRANS_SESEND: - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_REMOVE_SESSION, - feats, 0, 0, crpc); - if (rc) - return rc; - - rsrq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.rmsn_reqst; - rsrq->rmsn_sid = console_session.ses_id; - break; - - default: - LBUG(); - } - - return 0; -} - -int -lstcon_dbgrpc_prep(struct lstcon_node *nd, unsigned int feats, - struct lstcon_rpc **crpc) -{ - struct srpc_debug_reqst *drq; - int rc; - - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_DEBUG, feats, 0, 0, crpc); - if (rc) - return rc; - - drq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.dbg_reqst; - - drq->dbg_sid = console_session.ses_id; - drq->dbg_flags = 0; - - return rc; -} - -int -lstcon_batrpc_prep(struct lstcon_node *nd, int transop, unsigned int feats, - struct lstcon_tsb_hdr *tsb, struct lstcon_rpc **crpc) -{ - struct lstcon_batch *batch; - struct srpc_batch_reqst *brq; - int rc; - - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_BATCH, feats, 0, 0, crpc); - if (rc) - return rc; - - brq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.bat_reqst; - - brq->bar_sid = console_session.ses_id; - brq->bar_bid = tsb->tsb_id; - brq->bar_testidx = tsb->tsb_index; - brq->bar_opc = transop == LST_TRANS_TSBRUN ? SRPC_BATCH_OPC_RUN : - (transop == LST_TRANS_TSBSTOP ? SRPC_BATCH_OPC_STOP : - SRPC_BATCH_OPC_QUERY); - - if (transop != LST_TRANS_TSBRUN && - transop != LST_TRANS_TSBSTOP) - return 0; - - LASSERT(!tsb->tsb_index); - - batch = (struct lstcon_batch *)tsb; - brq->bar_arg = batch->bat_arg; - - return 0; -} - -int -lstcon_statrpc_prep(struct lstcon_node *nd, unsigned int feats, - struct lstcon_rpc **crpc) -{ - struct srpc_stat_reqst *srq; - int rc; - - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_QUERY_STAT, feats, 0, 0, crpc); - if (rc) - return rc; - - srq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.stat_reqst; - - srq->str_sid = console_session.ses_id; - srq->str_type = 0; /* XXX remove it */ - - return 0; -} - -static struct lnet_process_id_packed * -lstcon_next_id(int idx, int nkiov, struct bio_vec *kiov) -{ - struct lnet_process_id_packed *pid; - int i; - - i = idx / SFW_ID_PER_PAGE; - - LASSERT(i < nkiov); - - pid = (struct lnet_process_id_packed *)page_address(kiov[i].bv_page); - - return &pid[idx % SFW_ID_PER_PAGE]; -} - -static int -lstcon_dstnodes_prep(struct lstcon_group *grp, int idx, - int dist, int span, int nkiov, struct bio_vec *kiov) -{ - struct lnet_process_id_packed *pid; - struct lstcon_ndlink *ndl; - struct lstcon_node *nd; - int start; - int end; - int i = 0; - - LASSERT(dist >= 1); - LASSERT(span >= 1); - LASSERT(grp->grp_nnode >= 1); - - if (span > grp->grp_nnode) - return -EINVAL; - - start = ((idx / dist) * span) % grp->grp_nnode; - end = ((idx / dist) * span + span - 1) % grp->grp_nnode; - - list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link) { - nd = ndl->ndl_node; - if (i < start) { - i++; - continue; - } - - if (i > (end >= start ? end : grp->grp_nnode)) - break; - - pid = lstcon_next_id((i - start), nkiov, kiov); - pid->nid = nd->nd_id.nid; - pid->pid = nd->nd_id.pid; - i++; - } - - if (start <= end) /* done */ - return 0; - - list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link) { - if (i > grp->grp_nnode + end) - break; - - nd = ndl->ndl_node; - pid = lstcon_next_id((i - start), nkiov, kiov); - pid->nid = nd->nd_id.nid; - pid->pid = nd->nd_id.pid; - i++; - } - - return 0; -} - -static int -lstcon_pingrpc_prep(struct lst_test_ping_param *param, struct srpc_test_reqst *req) -{ - struct test_ping_req *prq = &req->tsr_u.ping; - - prq->png_size = param->png_size; - prq->png_flags = param->png_flags; - /* TODO dest */ - return 0; -} - -static int -lstcon_bulkrpc_v0_prep(struct lst_test_bulk_param *param, - struct srpc_test_reqst *req) -{ - struct test_bulk_req *brq = &req->tsr_u.bulk_v0; - - brq->blk_opc = param->blk_opc; - brq->blk_npg = DIV_ROUND_UP(param->blk_size, PAGE_SIZE); - brq->blk_flags = param->blk_flags; - - return 0; -} - -static int -lstcon_bulkrpc_v1_prep(struct lst_test_bulk_param *param, bool is_client, - struct srpc_test_reqst *req) -{ - struct test_bulk_req_v1 *brq = &req->tsr_u.bulk_v1; - - brq->blk_opc = param->blk_opc; - brq->blk_flags = param->blk_flags; - brq->blk_len = param->blk_size; - brq->blk_offset = is_client ? param->blk_cli_off : param->blk_srv_off; - - return 0; -} - -int -lstcon_testrpc_prep(struct lstcon_node *nd, int transop, unsigned int feats, - struct lstcon_test *test, struct lstcon_rpc **crpc) -{ - struct lstcon_group *sgrp = test->tes_src_grp; - struct lstcon_group *dgrp = test->tes_dst_grp; - struct srpc_test_reqst *trq; - struct srpc_bulk *bulk; - int i; - int npg = 0; - int nob = 0; - int rc = 0; - - if (transop == LST_TRANS_TSBCLIADD) { - npg = sfw_id_pages(test->tes_span); - nob = !(feats & LST_FEAT_BULK_LEN) ? - npg * PAGE_SIZE : - sizeof(struct lnet_process_id_packed) * test->tes_span; - } - - rc = lstcon_rpc_prep(nd, SRPC_SERVICE_TEST, feats, npg, nob, crpc); - if (rc) - return rc; - - trq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.tes_reqst; - - if (transop == LST_TRANS_TSBSRVADD) { - int ndist = DIV_ROUND_UP(sgrp->grp_nnode, test->tes_dist); - int nspan = DIV_ROUND_UP(dgrp->grp_nnode, test->tes_span); - int nmax = DIV_ROUND_UP(ndist, nspan); - - trq->tsr_ndest = 0; - trq->tsr_loop = nmax * test->tes_dist * test->tes_concur; - } else { - bulk = &(*crpc)->crp_rpc->crpc_bulk; - - for (i = 0; i < npg; i++) { - int len; - - LASSERT(nob > 0); - - len = !(feats & LST_FEAT_BULK_LEN) ? - PAGE_SIZE : - min_t(int, nob, PAGE_SIZE); - nob -= len; - - bulk->bk_iovs[i].bv_offset = 0; - bulk->bk_iovs[i].bv_len = len; - bulk->bk_iovs[i].bv_page = alloc_page(GFP_KERNEL); - - if (!bulk->bk_iovs[i].bv_page) { - lstcon_rpc_put(*crpc); - return -ENOMEM; - } - } - - bulk->bk_sink = 0; - - LASSERT(transop == LST_TRANS_TSBCLIADD); - - rc = lstcon_dstnodes_prep(test->tes_dst_grp, - test->tes_cliidx++, - test->tes_dist, - test->tes_span, - npg, &bulk->bk_iovs[0]); - if (rc) { - lstcon_rpc_put(*crpc); - return rc; - } - - trq->tsr_ndest = test->tes_span; - trq->tsr_loop = test->tes_loop; - } - - trq->tsr_sid = console_session.ses_id; - trq->tsr_bid = test->tes_hdr.tsb_id; - trq->tsr_concur = test->tes_concur; - trq->tsr_is_client = (transop == LST_TRANS_TSBCLIADD) ? 1 : 0; - trq->tsr_stop_onerr = !!test->tes_stop_onerr; - - switch (test->tes_type) { - case LST_TEST_PING: - trq->tsr_service = SRPC_SERVICE_PING; - rc = lstcon_pingrpc_prep((struct lst_test_ping_param *) - &test->tes_param[0], trq); - break; - - case LST_TEST_BULK: - trq->tsr_service = SRPC_SERVICE_BRW; - if (!(feats & LST_FEAT_BULK_LEN)) { - rc = lstcon_bulkrpc_v0_prep((struct lst_test_bulk_param *) - &test->tes_param[0], trq); - } else { - rc = lstcon_bulkrpc_v1_prep((struct lst_test_bulk_param *) - &test->tes_param[0], - trq->tsr_is_client, trq); - } - - break; - default: - LBUG(); - break; - } - - return rc; -} - -static int -lstcon_sesnew_stat_reply(struct lstcon_rpc_trans *trans, - struct lstcon_node *nd, struct srpc_msg *reply) -{ - struct srpc_mksn_reply *mksn_rep = &reply->msg_body.mksn_reply; - int status = mksn_rep->mksn_status; - - if (!status && - (reply->msg_ses_feats & ~LST_FEATS_MASK)) { - mksn_rep->mksn_status = EPROTO; - status = EPROTO; - } - - if (status == EPROTO) { - CNETERR("session protocol error from %s: %u\n", - libcfs_nid2str(nd->nd_id.nid), - reply->msg_ses_feats); - } - - if (status) - return status; - - if (!trans->tas_feats_updated) { - spin_lock(&console_session.ses_rpc_lock); - if (!trans->tas_feats_updated) { /* recheck with lock */ - trans->tas_feats_updated = 1; - trans->tas_features = reply->msg_ses_feats; - } - spin_unlock(&console_session.ses_rpc_lock); - } - - if (reply->msg_ses_feats != trans->tas_features) { - CNETERR("Framework features %x from %s is different with features on this transaction: %x\n", - reply->msg_ses_feats, libcfs_nid2str(nd->nd_id.nid), - trans->tas_features); - mksn_rep->mksn_status = EPROTO; - status = EPROTO; - } - - if (!status) { - /* session timeout on remote node */ - nd->nd_timeout = mksn_rep->mksn_timeout; - } - - return status; -} - -void -lstcon_rpc_stat_reply(struct lstcon_rpc_trans *trans, struct srpc_msg *msg, - struct lstcon_node *nd, struct lstcon_trans_stat *stat) -{ - struct srpc_rmsn_reply *rmsn_rep; - struct srpc_debug_reply *dbg_rep; - struct srpc_batch_reply *bat_rep; - struct srpc_test_reply *test_rep; - struct srpc_stat_reply *stat_rep; - int rc = 0; - - switch (trans->tas_opc) { - case LST_TRANS_SESNEW: - rc = lstcon_sesnew_stat_reply(trans, nd, msg); - if (!rc) { - lstcon_sesop_stat_success(stat, 1); - return; - } - - lstcon_sesop_stat_failure(stat, 1); - break; - - case LST_TRANS_SESEND: - rmsn_rep = &msg->msg_body.rmsn_reply; - /* ESRCH is not an error for end session */ - if (!rmsn_rep->rmsn_status || - rmsn_rep->rmsn_status == ESRCH) { - lstcon_sesop_stat_success(stat, 1); - return; - } - - lstcon_sesop_stat_failure(stat, 1); - rc = rmsn_rep->rmsn_status; - break; - - case LST_TRANS_SESQRY: - case LST_TRANS_SESPING: - dbg_rep = &msg->msg_body.dbg_reply; - - if (dbg_rep->dbg_status == ESRCH) { - lstcon_sesqry_stat_unknown(stat, 1); - return; - } - - if (lstcon_session_match(dbg_rep->dbg_sid)) - lstcon_sesqry_stat_active(stat, 1); - else - lstcon_sesqry_stat_busy(stat, 1); - return; - - case LST_TRANS_TSBRUN: - case LST_TRANS_TSBSTOP: - bat_rep = &msg->msg_body.bat_reply; - - if (!bat_rep->bar_status) { - lstcon_tsbop_stat_success(stat, 1); - return; - } - - if (bat_rep->bar_status == EPERM && - trans->tas_opc == LST_TRANS_TSBSTOP) { - lstcon_tsbop_stat_success(stat, 1); - return; - } - - lstcon_tsbop_stat_failure(stat, 1); - rc = bat_rep->bar_status; - break; - - case LST_TRANS_TSBCLIQRY: - case LST_TRANS_TSBSRVQRY: - bat_rep = &msg->msg_body.bat_reply; - - if (bat_rep->bar_active) - lstcon_tsbqry_stat_run(stat, 1); - else - lstcon_tsbqry_stat_idle(stat, 1); - - if (!bat_rep->bar_status) - return; - - lstcon_tsbqry_stat_failure(stat, 1); - rc = bat_rep->bar_status; - break; - - case LST_TRANS_TSBCLIADD: - case LST_TRANS_TSBSRVADD: - test_rep = &msg->msg_body.tes_reply; - - if (!test_rep->tsr_status) { - lstcon_tsbop_stat_success(stat, 1); - return; - } - - lstcon_tsbop_stat_failure(stat, 1); - rc = test_rep->tsr_status; - break; - - case LST_TRANS_STATQRY: - stat_rep = &msg->msg_body.stat_reply; - - if (!stat_rep->str_status) { - lstcon_statqry_stat_success(stat, 1); - return; - } - - lstcon_statqry_stat_failure(stat, 1); - rc = stat_rep->str_status; - break; - - default: - LBUG(); - } - - if (!stat->trs_fwk_errno) - stat->trs_fwk_errno = rc; -} - -int -lstcon_rpc_trans_ndlist(struct list_head *ndlist, - struct list_head *translist, int transop, - void *arg, lstcon_rpc_cond_func_t condition, - struct lstcon_rpc_trans **transpp) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_ndlink *ndl; - struct lstcon_node *nd; - struct lstcon_rpc *rpc; - unsigned int feats; - int rc; - - /* Creating session RPG for list of nodes */ - - rc = lstcon_rpc_trans_prep(translist, transop, &trans); - if (rc) { - CERROR("Can't create transaction %d: %d\n", transop, rc); - return rc; - } - - feats = trans->tas_features; - list_for_each_entry(ndl, ndlist, ndl_link) { - rc = !condition ? 1 : - condition(transop, ndl->ndl_node, arg); - - if (!rc) - continue; - - if (rc < 0) { - CDEBUG(D_NET, "Condition error while creating RPC for transaction %d: %d\n", - transop, rc); - break; - } - - nd = ndl->ndl_node; - - switch (transop) { - case LST_TRANS_SESNEW: - case LST_TRANS_SESEND: - rc = lstcon_sesrpc_prep(nd, transop, feats, &rpc); - break; - case LST_TRANS_SESQRY: - case LST_TRANS_SESPING: - rc = lstcon_dbgrpc_prep(nd, feats, &rpc); - break; - case LST_TRANS_TSBCLIADD: - case LST_TRANS_TSBSRVADD: - rc = lstcon_testrpc_prep(nd, transop, feats, - (struct lstcon_test *)arg, - &rpc); - break; - case LST_TRANS_TSBRUN: - case LST_TRANS_TSBSTOP: - case LST_TRANS_TSBCLIQRY: - case LST_TRANS_TSBSRVQRY: - rc = lstcon_batrpc_prep(nd, transop, feats, - (struct lstcon_tsb_hdr *)arg, - &rpc); - break; - case LST_TRANS_STATQRY: - rc = lstcon_statrpc_prep(nd, feats, &rpc); - break; - default: - rc = -EINVAL; - break; - } - - if (rc) { - CERROR("Failed to create RPC for transaction %s: %d\n", - lstcon_rpc_trans_name(transop), rc); - break; - } - - lstcon_rpc_trans_addreq(trans, rpc); - } - - if (!rc) { - *transpp = trans; - return 0; - } - - lstcon_rpc_trans_destroy(trans); - - return rc; -} - -static void -lstcon_rpc_pinger(void *arg) -{ - struct stt_timer *ptimer = (struct stt_timer *)arg; - struct lstcon_rpc_trans *trans; - struct lstcon_rpc *crpc; - struct srpc_msg *rep; - struct srpc_debug_reqst *drq; - struct lstcon_ndlink *ndl; - struct lstcon_node *nd; - int intv; - int count = 0; - int rc; - - /* - * RPC pinger is a special case of transaction, - * it's called by timer at 8 seconds interval. - */ - mutex_lock(&console_session.ses_mutex); - - if (console_session.ses_shutdown || console_session.ses_expired) { - mutex_unlock(&console_session.ses_mutex); - return; - } - - if (!console_session.ses_expired && - ktime_get_real_seconds() - console_session.ses_laststamp > - (time64_t)console_session.ses_timeout) - console_session.ses_expired = 1; - - trans = console_session.ses_ping; - - LASSERT(trans); - - list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link) { - nd = ndl->ndl_node; - - if (console_session.ses_expired) { - /* idle console, end session on all nodes */ - if (nd->nd_state != LST_NODE_ACTIVE) - continue; - - rc = lstcon_sesrpc_prep(nd, LST_TRANS_SESEND, - trans->tas_features, &crpc); - if (rc) { - CERROR("Out of memory\n"); - break; - } - - lstcon_rpc_trans_addreq(trans, crpc); - lstcon_rpc_post(crpc); - - continue; - } - - crpc = &nd->nd_ping; - - if (crpc->crp_rpc) { - LASSERT(crpc->crp_trans == trans); - LASSERT(!list_empty(&crpc->crp_link)); - - spin_lock(&crpc->crp_rpc->crpc_lock); - - LASSERT(crpc->crp_posted); - - if (!crpc->crp_finished) { - /* in flight */ - spin_unlock(&crpc->crp_rpc->crpc_lock); - continue; - } - - spin_unlock(&crpc->crp_rpc->crpc_lock); - - lstcon_rpc_get_reply(crpc, &rep); - - list_del_init(&crpc->crp_link); - - lstcon_rpc_put(crpc); - } - - if (nd->nd_state != LST_NODE_ACTIVE) - continue; - - intv = (jiffies - nd->nd_stamp) / msecs_to_jiffies(MSEC_PER_SEC); - if (intv < nd->nd_timeout / 2) - continue; - - rc = lstcon_rpc_init(nd, SRPC_SERVICE_DEBUG, - trans->tas_features, 0, 0, 1, crpc); - if (rc) { - CERROR("Out of memory\n"); - break; - } - - drq = &crpc->crp_rpc->crpc_reqstmsg.msg_body.dbg_reqst; - - drq->dbg_sid = console_session.ses_id; - drq->dbg_flags = 0; - - lstcon_rpc_trans_addreq(trans, crpc); - lstcon_rpc_post(crpc); - - count++; - } - - if (console_session.ses_expired) { - mutex_unlock(&console_session.ses_mutex); - return; - } - - CDEBUG(D_NET, "Ping %d nodes in session\n", count); - - ptimer->stt_expires = ktime_get_real_seconds() + LST_PING_INTERVAL; - stt_add_timer(ptimer); - - mutex_unlock(&console_session.ses_mutex); -} - -int -lstcon_rpc_pinger_start(void) -{ - struct stt_timer *ptimer; - int rc; - - LASSERT(list_empty(&console_session.ses_rpc_freelist)); - LASSERT(!atomic_read(&console_session.ses_rpc_counter)); - - rc = lstcon_rpc_trans_prep(NULL, LST_TRANS_SESPING, - &console_session.ses_ping); - if (rc) { - CERROR("Failed to create console pinger\n"); - return rc; - } - - ptimer = &console_session.ses_ping_timer; - ptimer->stt_expires = ktime_get_real_seconds() + LST_PING_INTERVAL; - - stt_add_timer(ptimer); - - return 0; -} - -void -lstcon_rpc_pinger_stop(void) -{ - LASSERT(console_session.ses_shutdown); - - stt_del_timer(&console_session.ses_ping_timer); - - lstcon_rpc_trans_abort(console_session.ses_ping, -ESHUTDOWN); - lstcon_rpc_trans_stat(console_session.ses_ping, lstcon_trans_stat()); - lstcon_rpc_trans_destroy(console_session.ses_ping); - - memset(lstcon_trans_stat(), 0, sizeof(struct lstcon_trans_stat)); - - console_session.ses_ping = NULL; -} - -void -lstcon_rpc_cleanup_wait(void) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_rpc *crpc; - struct lstcon_rpc *temp; - struct list_head *pacer; - struct list_head zlist; - - /* Called with hold of global mutex */ - - LASSERT(console_session.ses_shutdown); - - while (!list_empty(&console_session.ses_trans_list)) { - list_for_each(pacer, &console_session.ses_trans_list) { - trans = list_entry(pacer, struct lstcon_rpc_trans, - tas_link); - - CDEBUG(D_NET, "Session closed, wakeup transaction %s\n", - lstcon_rpc_trans_name(trans->tas_opc)); - - wake_up(&trans->tas_waitq); - } - - mutex_unlock(&console_session.ses_mutex); - - CWARN("Session is shutting down, waiting for termination of transactions\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - - mutex_lock(&console_session.ses_mutex); - } - - spin_lock(&console_session.ses_rpc_lock); - - lst_wait_until(!atomic_read(&console_session.ses_rpc_counter), - console_session.ses_rpc_lock, - "Network is not accessible or target is down, waiting for %d console RPCs to being recycled\n", - atomic_read(&console_session.ses_rpc_counter)); - - list_add(&zlist, &console_session.ses_rpc_freelist); - list_del_init(&console_session.ses_rpc_freelist); - - spin_unlock(&console_session.ses_rpc_lock); - - list_for_each_entry_safe(crpc, temp, &zlist, crp_link) { - list_del(&crpc->crp_link); - kfree(crpc); - } -} - -int -lstcon_rpc_module_init(void) -{ - INIT_LIST_HEAD(&console_session.ses_ping_timer.stt_list); - console_session.ses_ping_timer.stt_func = lstcon_rpc_pinger; - console_session.ses_ping_timer.stt_data = &console_session.ses_ping_timer; - - console_session.ses_ping = NULL; - - spin_lock_init(&console_session.ses_rpc_lock); - atomic_set(&console_session.ses_rpc_counter, 0); - INIT_LIST_HEAD(&console_session.ses_rpc_freelist); - - return 0; -} - -void -lstcon_rpc_module_fini(void) -{ - LASSERT(list_empty(&console_session.ses_rpc_freelist)); - LASSERT(!atomic_read(&console_session.ses_rpc_counter)); -} diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h deleted file mode 100644 index 374a5f31ef6f..000000000000 --- a/drivers/staging/lustre/lnet/selftest/conrpc.h +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * /lnet/selftest/conrpc.h - * - * Console rpc - * - * Author: Liang Zhen <liang@whamcloud.com> - */ - -#ifndef __LST_CONRPC_H__ -#define __LST_CONRPC_H__ - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-types.h> -#include <uapi/linux/lnet/lnetst.h> -#include "rpc.h" -#include "selftest.h" - -/* Console rpc and rpc transaction */ -#define LST_TRANS_TIMEOUT 30 -#define LST_TRANS_MIN_TIMEOUT 3 - -#define LST_VALIDATE_TIMEOUT(t) min(max(t, LST_TRANS_MIN_TIMEOUT), LST_TRANS_TIMEOUT) - -#define LST_PING_INTERVAL 8 - -struct lstcon_rpc_trans; -struct lstcon_tsb_hdr; -struct lstcon_test; -struct lstcon_node; - -struct lstcon_rpc { - struct list_head crp_link; /* chain on rpc transaction */ - struct srpc_client_rpc *crp_rpc; /* client rpc */ - struct lstcon_node *crp_node; /* destination node */ - struct lstcon_rpc_trans *crp_trans; /* conrpc transaction */ - - unsigned int crp_posted:1; /* rpc is posted */ - unsigned int crp_finished:1; /* rpc is finished */ - unsigned int crp_unpacked:1; /* reply is unpacked */ - /** RPC is embedded in other structure and can't free it */ - unsigned int crp_embedded:1; - int crp_status; /* console rpc errors */ - unsigned long crp_stamp; /* replied time stamp */ -}; - -struct lstcon_rpc_trans { - struct list_head tas_olink; /* link chain on owner list */ - struct list_head tas_link; /* link chain on global list */ - int tas_opc; /* operation code of transaction */ - unsigned int tas_feats_updated; /* features mask is uptodate */ - unsigned int tas_features; /* test features mask */ - wait_queue_head_t tas_waitq; /* wait queue head */ - atomic_t tas_remaining; /* # of un-scheduled rpcs */ - struct list_head tas_rpcs_list; /* queued requests */ -}; - -#define LST_TRANS_PRIVATE 0x1000 - -#define LST_TRANS_SESNEW (LST_TRANS_PRIVATE | 0x01) -#define LST_TRANS_SESEND (LST_TRANS_PRIVATE | 0x02) -#define LST_TRANS_SESQRY 0x03 -#define LST_TRANS_SESPING 0x04 - -#define LST_TRANS_TSBCLIADD (LST_TRANS_PRIVATE | 0x11) -#define LST_TRANS_TSBSRVADD (LST_TRANS_PRIVATE | 0x12) -#define LST_TRANS_TSBRUN (LST_TRANS_PRIVATE | 0x13) -#define LST_TRANS_TSBSTOP (LST_TRANS_PRIVATE | 0x14) -#define LST_TRANS_TSBCLIQRY 0x15 -#define LST_TRANS_TSBSRVQRY 0x16 - -#define LST_TRANS_STATQRY 0x21 - -typedef int (*lstcon_rpc_cond_func_t)(int, struct lstcon_node *, void *); -typedef int (*lstcon_rpc_readent_func_t)(int, struct srpc_msg *, - struct lstcon_rpc_ent __user *); - -int lstcon_sesrpc_prep(struct lstcon_node *nd, int transop, - unsigned int version, struct lstcon_rpc **crpc); -int lstcon_dbgrpc_prep(struct lstcon_node *nd, - unsigned int version, struct lstcon_rpc **crpc); -int lstcon_batrpc_prep(struct lstcon_node *nd, int transop, - unsigned int version, struct lstcon_tsb_hdr *tsb, - struct lstcon_rpc **crpc); -int lstcon_testrpc_prep(struct lstcon_node *nd, int transop, - unsigned int version, struct lstcon_test *test, - struct lstcon_rpc **crpc); -int lstcon_statrpc_prep(struct lstcon_node *nd, unsigned int version, - struct lstcon_rpc **crpc); -void lstcon_rpc_put(struct lstcon_rpc *crpc); -int lstcon_rpc_trans_prep(struct list_head *translist, - int transop, struct lstcon_rpc_trans **transpp); -int lstcon_rpc_trans_ndlist(struct list_head *ndlist, - struct list_head *translist, int transop, - void *arg, lstcon_rpc_cond_func_t condition, - struct lstcon_rpc_trans **transpp); -void lstcon_rpc_trans_stat(struct lstcon_rpc_trans *trans, - struct lstcon_trans_stat *stat); -int lstcon_rpc_trans_interpreter(struct lstcon_rpc_trans *trans, - struct list_head __user *head_up, - lstcon_rpc_readent_func_t readent); -void lstcon_rpc_trans_abort(struct lstcon_rpc_trans *trans, int error); -void lstcon_rpc_trans_destroy(struct lstcon_rpc_trans *trans); -void lstcon_rpc_trans_addreq(struct lstcon_rpc_trans *trans, - struct lstcon_rpc *req); -int lstcon_rpc_trans_postwait(struct lstcon_rpc_trans *trans, int timeout); -int lstcon_rpc_pinger_start(void); -void lstcon_rpc_pinger_stop(void); -void lstcon_rpc_cleanup_wait(void); -int lstcon_rpc_module_init(void); -void lstcon_rpc_module_fini(void); - -#endif diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c deleted file mode 100644 index 1acd5cb324b1..000000000000 --- a/drivers/staging/lustre/lnet/selftest/console.c +++ /dev/null @@ -1,2101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/conctl.c - * - * Infrastructure of LST console - * - * Author: Liang Zhen <liangzhen@clusterfs.com> - */ - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-lnet.h> -#include "console.h" -#include "conrpc.h" - -#define LST_NODE_STATE_COUNTER(nd, p) \ -do { \ - if ((nd)->nd_state == LST_NODE_ACTIVE) \ - (p)->nle_nactive++; \ - else if ((nd)->nd_state == LST_NODE_BUSY) \ - (p)->nle_nbusy++; \ - else if ((nd)->nd_state == LST_NODE_DOWN) \ - (p)->nle_ndown++; \ - else \ - (p)->nle_nunknown++; \ - (p)->nle_nnode++; \ -} while (0) - -struct lstcon_session console_session; - -static void -lstcon_node_get(struct lstcon_node *nd) -{ - LASSERT(nd->nd_ref >= 1); - - nd->nd_ref++; -} - -static int -lstcon_node_find(struct lnet_process_id id, struct lstcon_node **ndpp, - int create) -{ - struct lstcon_ndlink *ndl; - unsigned int idx = LNET_NIDADDR(id.nid) % LST_GLOBAL_HASHSIZE; - - LASSERT(id.nid != LNET_NID_ANY); - - list_for_each_entry(ndl, &console_session.ses_ndl_hash[idx], - ndl_hlink) { - if (ndl->ndl_node->nd_id.nid != id.nid || - ndl->ndl_node->nd_id.pid != id.pid) - continue; - - lstcon_node_get(ndl->ndl_node); - *ndpp = ndl->ndl_node; - return 0; - } - - if (!create) - return -ENOENT; - - *ndpp = kzalloc(sizeof(**ndpp) + sizeof(*ndl), GFP_KERNEL); - if (!*ndpp) - return -ENOMEM; - - ndl = (struct lstcon_ndlink *)(*ndpp + 1); - - ndl->ndl_node = *ndpp; - - ndl->ndl_node->nd_ref = 1; - ndl->ndl_node->nd_id = id; - ndl->ndl_node->nd_stamp = cfs_time_current(); - ndl->ndl_node->nd_state = LST_NODE_UNKNOWN; - ndl->ndl_node->nd_timeout = 0; - memset(&ndl->ndl_node->nd_ping, 0, sizeof(struct lstcon_rpc)); - - /* - * queued in global hash & list, no refcount is taken by - * global hash & list, if caller release his refcount, - * node will be released - */ - list_add_tail(&ndl->ndl_hlink, &console_session.ses_ndl_hash[idx]); - list_add_tail(&ndl->ndl_link, &console_session.ses_ndl_list); - - return 0; -} - -static void -lstcon_node_put(struct lstcon_node *nd) -{ - struct lstcon_ndlink *ndl; - - LASSERT(nd->nd_ref > 0); - - if (--nd->nd_ref > 0) - return; - - ndl = (struct lstcon_ndlink *)(nd + 1); - - LASSERT(!list_empty(&ndl->ndl_link)); - LASSERT(!list_empty(&ndl->ndl_hlink)); - - /* remove from session */ - list_del(&ndl->ndl_link); - list_del(&ndl->ndl_hlink); - - kfree(nd); -} - -static int -lstcon_ndlink_find(struct list_head *hash, struct lnet_process_id id, - struct lstcon_ndlink **ndlpp, int create) -{ - unsigned int idx = LNET_NIDADDR(id.nid) % LST_NODE_HASHSIZE; - struct lstcon_ndlink *ndl; - struct lstcon_node *nd; - int rc; - - if (id.nid == LNET_NID_ANY) - return -EINVAL; - - /* search in hash */ - list_for_each_entry(ndl, &hash[idx], ndl_hlink) { - if (ndl->ndl_node->nd_id.nid != id.nid || - ndl->ndl_node->nd_id.pid != id.pid) - continue; - - *ndlpp = ndl; - return 0; - } - - if (!create) - return -ENOENT; - - /* find or create in session hash */ - rc = lstcon_node_find(id, &nd, (create == 1) ? 1 : 0); - if (rc) - return rc; - - ndl = kzalloc(sizeof(struct lstcon_ndlink), GFP_NOFS); - if (!ndl) { - lstcon_node_put(nd); - return -ENOMEM; - } - - *ndlpp = ndl; - - ndl->ndl_node = nd; - INIT_LIST_HEAD(&ndl->ndl_link); - list_add_tail(&ndl->ndl_hlink, &hash[idx]); - - return 0; -} - -static void -lstcon_ndlink_release(struct lstcon_ndlink *ndl) -{ - LASSERT(list_empty(&ndl->ndl_link)); - LASSERT(!list_empty(&ndl->ndl_hlink)); - - list_del(&ndl->ndl_hlink); /* delete from hash */ - lstcon_node_put(ndl->ndl_node); - - kfree(ndl); -} - -static int -lstcon_group_alloc(char *name, struct lstcon_group **grpp) -{ - struct lstcon_group *grp; - int i; - - grp = kmalloc(offsetof(struct lstcon_group, - grp_ndl_hash[LST_NODE_HASHSIZE]), - GFP_KERNEL); - if (!grp) - return -ENOMEM; - - grp->grp_ref = 1; - if (name) { - if (strlen(name) > sizeof(grp->grp_name) - 1) { - kfree(grp); - return -E2BIG; - } - strncpy(grp->grp_name, name, sizeof(grp->grp_name)); - } - - INIT_LIST_HEAD(&grp->grp_link); - INIT_LIST_HEAD(&grp->grp_ndl_list); - INIT_LIST_HEAD(&grp->grp_trans_list); - - for (i = 0; i < LST_NODE_HASHSIZE; i++) - INIT_LIST_HEAD(&grp->grp_ndl_hash[i]); - - *grpp = grp; - - return 0; -} - -static void -lstcon_group_addref(struct lstcon_group *grp) -{ - grp->grp_ref++; -} - -static void lstcon_group_ndlink_release(struct lstcon_group *, - struct lstcon_ndlink *); - -static void -lstcon_group_drain(struct lstcon_group *grp, int keep) -{ - struct lstcon_ndlink *ndl; - struct lstcon_ndlink *tmp; - - list_for_each_entry_safe(ndl, tmp, &grp->grp_ndl_list, ndl_link) { - if (!(ndl->ndl_node->nd_state & keep)) - lstcon_group_ndlink_release(grp, ndl); - } -} - -static void -lstcon_group_decref(struct lstcon_group *grp) -{ - int i; - - if (--grp->grp_ref > 0) - return; - - if (!list_empty(&grp->grp_link)) - list_del(&grp->grp_link); - - lstcon_group_drain(grp, 0); - - for (i = 0; i < LST_NODE_HASHSIZE; i++) - LASSERT(list_empty(&grp->grp_ndl_hash[i])); - - kfree(grp); -} - -static int -lstcon_group_find(const char *name, struct lstcon_group **grpp) -{ - struct lstcon_group *grp; - - list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) { - if (strncmp(grp->grp_name, name, LST_NAME_SIZE)) - continue; - - lstcon_group_addref(grp); /* +1 ref for caller */ - *grpp = grp; - return 0; - } - - return -ENOENT; -} - -static int -lstcon_group_ndlink_find(struct lstcon_group *grp, struct lnet_process_id id, - struct lstcon_ndlink **ndlpp, int create) -{ - int rc; - - rc = lstcon_ndlink_find(&grp->grp_ndl_hash[0], id, ndlpp, create); - if (rc) - return rc; - - if (!list_empty(&(*ndlpp)->ndl_link)) - return 0; - - list_add_tail(&(*ndlpp)->ndl_link, &grp->grp_ndl_list); - grp->grp_nnode++; - - return 0; -} - -static void -lstcon_group_ndlink_release(struct lstcon_group *grp, struct lstcon_ndlink *ndl) -{ - list_del_init(&ndl->ndl_link); - lstcon_ndlink_release(ndl); - grp->grp_nnode--; -} - -static void -lstcon_group_ndlink_move(struct lstcon_group *old, - struct lstcon_group *new, struct lstcon_ndlink *ndl) -{ - unsigned int idx = LNET_NIDADDR(ndl->ndl_node->nd_id.nid) % - LST_NODE_HASHSIZE; - - list_del(&ndl->ndl_hlink); - list_del(&ndl->ndl_link); - old->grp_nnode--; - - list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]); - list_add_tail(&ndl->ndl_link, &new->grp_ndl_list); - new->grp_nnode++; -} - -static void -lstcon_group_move(struct lstcon_group *old, struct lstcon_group *new) -{ - struct lstcon_ndlink *ndl; - - while (!list_empty(&old->grp_ndl_list)) { - ndl = list_entry(old->grp_ndl_list.next, - struct lstcon_ndlink, ndl_link); - lstcon_group_ndlink_move(old, new, ndl); - } -} - -static int -lstcon_sesrpc_condition(int transop, struct lstcon_node *nd, void *arg) -{ - struct lstcon_group *grp = (struct lstcon_group *)arg; - - switch (transop) { - case LST_TRANS_SESNEW: - if (nd->nd_state == LST_NODE_ACTIVE) - return 0; - break; - - case LST_TRANS_SESEND: - if (nd->nd_state != LST_NODE_ACTIVE) - return 0; - - if (grp && nd->nd_ref > 1) - return 0; - break; - - case LST_TRANS_SESQRY: - break; - - default: - LBUG(); - } - - return 1; -} - -static int -lstcon_sesrpc_readent(int transop, struct srpc_msg *msg, - struct lstcon_rpc_ent __user *ent_up) -{ - struct srpc_debug_reply *rep; - - switch (transop) { - case LST_TRANS_SESNEW: - case LST_TRANS_SESEND: - return 0; - - case LST_TRANS_SESQRY: - rep = &msg->msg_body.dbg_reply; - - if (copy_to_user(&ent_up->rpe_priv[0], - &rep->dbg_timeout, sizeof(int)) || - copy_to_user(&ent_up->rpe_payload[0], - &rep->dbg_name, LST_NAME_SIZE)) - return -EFAULT; - - return 0; - - default: - LBUG(); - } - - return 0; -} - -static int -lstcon_group_nodes_add(struct lstcon_group *grp, - int count, struct lnet_process_id __user *ids_up, - unsigned int *featp, - struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_ndlink *ndl; - struct lstcon_group *tmp; - struct lnet_process_id id; - int i; - int rc; - - rc = lstcon_group_alloc(NULL, &tmp); - if (rc) { - CERROR("Out of memory\n"); - return -ENOMEM; - } - - for (i = 0 ; i < count; i++) { - if (copy_from_user(&id, &ids_up[i], sizeof(id))) { - rc = -EFAULT; - break; - } - - /* skip if it's in this group already */ - rc = lstcon_group_ndlink_find(grp, id, &ndl, 0); - if (!rc) - continue; - - /* add to tmp group */ - rc = lstcon_group_ndlink_find(tmp, id, &ndl, 1); - if (rc) { - CERROR("Can't create ndlink, out of memory\n"); - break; - } - } - - if (rc) { - lstcon_group_decref(tmp); - return rc; - } - - rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list, - &tmp->grp_trans_list, LST_TRANS_SESNEW, - tmp, lstcon_sesrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - lstcon_group_decref(tmp); - return rc; - } - - /* post all RPCs */ - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, - lstcon_sesrpc_readent); - *featp = trans->tas_features; - - /* destroy all RPGs */ - lstcon_rpc_trans_destroy(trans); - - lstcon_group_move(tmp, grp); - lstcon_group_decref(tmp); - - return rc; -} - -static int -lstcon_group_nodes_remove(struct lstcon_group *grp, - int count, struct lnet_process_id __user *ids_up, - struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_ndlink *ndl; - struct lstcon_group *tmp; - struct lnet_process_id id; - int rc; - int i; - - /* End session and remove node from the group */ - - rc = lstcon_group_alloc(NULL, &tmp); - if (rc) { - CERROR("Out of memory\n"); - return -ENOMEM; - } - - for (i = 0; i < count; i++) { - if (copy_from_user(&id, &ids_up[i], sizeof(id))) { - rc = -EFAULT; - goto error; - } - - /* move node to tmp group */ - if (!lstcon_group_ndlink_find(grp, id, &ndl, 0)) - lstcon_group_ndlink_move(grp, tmp, ndl); - } - - rc = lstcon_rpc_trans_ndlist(&tmp->grp_ndl_list, - &tmp->grp_trans_list, LST_TRANS_SESEND, - tmp, lstcon_sesrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - goto error; - } - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL); - - lstcon_rpc_trans_destroy(trans); - /* release nodes anyway, because we can't rollback status */ - lstcon_group_decref(tmp); - - return rc; -error: - lstcon_group_move(tmp, grp); - lstcon_group_decref(tmp); - - return rc; -} - -int -lstcon_group_add(char *name) -{ - struct lstcon_group *grp; - int rc; - - rc = lstcon_group_find(name, &grp) ? 0 : -EEXIST; - if (rc) { - /* find a group with same name */ - lstcon_group_decref(grp); - return rc; - } - - rc = lstcon_group_alloc(name, &grp); - if (rc) { - CERROR("Can't allocate descriptor for group %s\n", name); - return -ENOMEM; - } - - list_add_tail(&grp->grp_link, &console_session.ses_grp_list); - - return rc; -} - -int -lstcon_nodes_add(char *name, int count, struct lnet_process_id __user *ids_up, - unsigned int *featp, struct list_head __user *result_up) -{ - struct lstcon_group *grp; - int rc; - - LASSERT(count > 0); - LASSERT(ids_up); - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group %s\n", name); - return rc; - } - - if (grp->grp_ref > 2) { - /* referred by other threads or test */ - CDEBUG(D_NET, "Group %s is busy\n", name); - lstcon_group_decref(grp); - - return -EBUSY; - } - - rc = lstcon_group_nodes_add(grp, count, ids_up, featp, result_up); - - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_group_del(char *name) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_group *grp; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group: %s\n", name); - return rc; - } - - if (grp->grp_ref > 2) { - /* referred by others threads or test */ - CDEBUG(D_NET, "Group %s is busy\n", name); - lstcon_group_decref(grp); - return -EBUSY; - } - - rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list, - &grp->grp_trans_list, LST_TRANS_SESEND, - grp, lstcon_sesrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - lstcon_group_decref(grp); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - lstcon_rpc_trans_destroy(trans); - - lstcon_group_decref(grp); - /* - * -ref for session, it's destroyed, - * status can't be rolled back, destroy group anyway - */ - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_group_clean(char *name, int args) -{ - struct lstcon_group *grp = NULL; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group %s\n", name); - return rc; - } - - if (grp->grp_ref > 2) { - /* referred by test */ - CDEBUG(D_NET, "Group %s is busy\n", name); - lstcon_group_decref(grp); - return -EBUSY; - } - - args = (LST_NODE_ACTIVE | LST_NODE_BUSY | - LST_NODE_DOWN | LST_NODE_UNKNOWN) & ~args; - - lstcon_group_drain(grp, args); - - lstcon_group_decref(grp); - /* release empty group */ - if (list_empty(&grp->grp_ndl_list)) - lstcon_group_decref(grp); - - return 0; -} - -int -lstcon_nodes_remove(char *name, int count, - struct lnet_process_id __user *ids_up, - struct list_head __user *result_up) -{ - struct lstcon_group *grp = NULL; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group: %s\n", name); - return rc; - } - - if (grp->grp_ref > 2) { - /* referred by test */ - CDEBUG(D_NET, "Group %s is busy\n", name); - lstcon_group_decref(grp); - return -EBUSY; - } - - rc = lstcon_group_nodes_remove(grp, count, ids_up, result_up); - - lstcon_group_decref(grp); - /* release empty group */ - if (list_empty(&grp->grp_ndl_list)) - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_group_refresh(char *name, struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_group *grp; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group: %s\n", name); - return rc; - } - - if (grp->grp_ref > 2) { - /* referred by test */ - CDEBUG(D_NET, "Group %s is busy\n", name); - lstcon_group_decref(grp); - return -EBUSY; - } - - /* re-invite all inactive nodes int the group */ - rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list, - &grp->grp_trans_list, LST_TRANS_SESNEW, - grp, lstcon_sesrpc_condition, &trans); - if (rc) { - /* local error, return */ - CDEBUG(D_NET, "Can't create transaction: %d\n", rc); - lstcon_group_decref(grp); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL); - - lstcon_rpc_trans_destroy(trans); - /* -ref for me */ - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_group_list(int index, int len, char __user *name_up) -{ - struct lstcon_group *grp; - - LASSERT(index >= 0); - LASSERT(name_up); - - list_for_each_entry(grp, &console_session.ses_grp_list, grp_link) { - if (!index--) { - return copy_to_user(name_up, grp->grp_name, len) ? - -EFAULT : 0; - } - } - - return -ENOENT; -} - -static int -lstcon_nodes_getent(struct list_head *head, int *index_p, - int *count_p, struct lstcon_node_ent __user *dents_up) -{ - struct lstcon_ndlink *ndl; - struct lstcon_node *nd; - int count = 0; - int index = 0; - - LASSERT(index_p && count_p); - LASSERT(dents_up); - LASSERT(*index_p >= 0); - LASSERT(*count_p > 0); - - list_for_each_entry(ndl, head, ndl_link) { - if (index++ < *index_p) - continue; - - if (count >= *count_p) - break; - - nd = ndl->ndl_node; - if (copy_to_user(&dents_up[count].nde_id, - &nd->nd_id, sizeof(nd->nd_id)) || - copy_to_user(&dents_up[count].nde_state, - &nd->nd_state, sizeof(nd->nd_state))) - return -EFAULT; - - count++; - } - - if (index <= *index_p) - return -ENOENT; - - *count_p = count; - *index_p = index; - - return 0; -} - -int -lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gents_p, - int *index_p, int *count_p, - struct lstcon_node_ent __user *dents_up) -{ - struct lstcon_ndlist_ent *gentp; - struct lstcon_group *grp; - struct lstcon_ndlink *ndl; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group %s\n", name); - return rc; - } - - if (dents_up) { - /* verbose query */ - rc = lstcon_nodes_getent(&grp->grp_ndl_list, - index_p, count_p, dents_up); - lstcon_group_decref(grp); - - return rc; - } - - /* non-verbose query */ - gentp = kzalloc(sizeof(struct lstcon_ndlist_ent), GFP_NOFS); - if (!gentp) { - CERROR("Can't allocate ndlist_ent\n"); - lstcon_group_decref(grp); - - return -ENOMEM; - } - - list_for_each_entry(ndl, &grp->grp_ndl_list, ndl_link) - LST_NODE_STATE_COUNTER(ndl->ndl_node, gentp); - - rc = copy_to_user(gents_p, gentp, - sizeof(struct lstcon_ndlist_ent)) ? -EFAULT : 0; - - kfree(gentp); - - lstcon_group_decref(grp); - - return rc; -} - -static int -lstcon_batch_find(const char *name, struct lstcon_batch **batpp) -{ - struct lstcon_batch *bat; - - list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) { - if (!strncmp(bat->bat_name, name, LST_NAME_SIZE)) { - *batpp = bat; - return 0; - } - } - - return -ENOENT; -} - -int -lstcon_batch_add(char *name) -{ - struct lstcon_batch *bat; - int i; - int rc; - - rc = !lstcon_batch_find(name, &bat) ? -EEXIST : 0; - if (rc) { - CDEBUG(D_NET, "Batch %s already exists\n", name); - return rc; - } - - bat = kzalloc(sizeof(struct lstcon_batch), GFP_NOFS); - if (!bat) { - CERROR("Can't allocate descriptor for batch %s\n", name); - return -ENOMEM; - } - - bat->bat_cli_hash = kmalloc(sizeof(struct list_head) * LST_NODE_HASHSIZE, - GFP_KERNEL); - if (!bat->bat_cli_hash) { - CERROR("Can't allocate hash for batch %s\n", name); - kfree(bat); - - return -ENOMEM; - } - - bat->bat_srv_hash = kmalloc(sizeof(struct list_head) * LST_NODE_HASHSIZE, - GFP_KERNEL); - if (!bat->bat_srv_hash) { - CERROR("Can't allocate hash for batch %s\n", name); - kfree(bat->bat_cli_hash); - kfree(bat); - - return -ENOMEM; - } - - if (strlen(name) > sizeof(bat->bat_name) - 1) { - kfree(bat->bat_srv_hash); - kfree(bat->bat_cli_hash); - kfree(bat); - return -E2BIG; - } - strncpy(bat->bat_name, name, sizeof(bat->bat_name)); - bat->bat_hdr.tsb_index = 0; - bat->bat_hdr.tsb_id.bat_id = ++console_session.ses_id_cookie; - - bat->bat_ntest = 0; - bat->bat_state = LST_BATCH_IDLE; - - INIT_LIST_HEAD(&bat->bat_cli_list); - INIT_LIST_HEAD(&bat->bat_srv_list); - INIT_LIST_HEAD(&bat->bat_test_list); - INIT_LIST_HEAD(&bat->bat_trans_list); - - for (i = 0; i < LST_NODE_HASHSIZE; i++) { - INIT_LIST_HEAD(&bat->bat_cli_hash[i]); - INIT_LIST_HEAD(&bat->bat_srv_hash[i]); - } - - list_add_tail(&bat->bat_link, &console_session.ses_bat_list); - - return rc; -} - -int -lstcon_batch_list(int index, int len, char __user *name_up) -{ - struct lstcon_batch *bat; - - LASSERT(name_up); - LASSERT(index >= 0); - - list_for_each_entry(bat, &console_session.ses_bat_list, bat_link) { - if (!index--) { - return copy_to_user(name_up, bat->bat_name, len) ? - -EFAULT : 0; - } - } - - return -ENOENT; -} - -int -lstcon_batch_info(char *name, struct lstcon_test_batch_ent __user *ent_up, - int server, int testidx, int *index_p, int *ndent_p, - struct lstcon_node_ent __user *dents_up) -{ - struct lstcon_test_batch_ent *entp; - struct list_head *clilst; - struct list_head *srvlst; - struct lstcon_test *test = NULL; - struct lstcon_batch *bat; - struct lstcon_ndlink *ndl; - int rc; - - rc = lstcon_batch_find(name, &bat); - if (rc) { - CDEBUG(D_NET, "Can't find batch %s\n", name); - return -ENOENT; - } - - if (testidx > 0) { - /* query test, test index start from 1 */ - list_for_each_entry(test, &bat->bat_test_list, tes_link) { - if (testidx-- == 1) - break; - } - - if (testidx > 0) { - CDEBUG(D_NET, "Can't find specified test in batch\n"); - return -ENOENT; - } - } - - clilst = !test ? &bat->bat_cli_list : - &test->tes_src_grp->grp_ndl_list; - srvlst = !test ? &bat->bat_srv_list : - &test->tes_dst_grp->grp_ndl_list; - - if (dents_up) { - rc = lstcon_nodes_getent((server ? srvlst : clilst), - index_p, ndent_p, dents_up); - return rc; - } - - /* non-verbose query */ - entp = kzalloc(sizeof(struct lstcon_test_batch_ent), GFP_NOFS); - if (!entp) - return -ENOMEM; - - if (!test) { - entp->u.tbe_batch.bae_ntest = bat->bat_ntest; - entp->u.tbe_batch.bae_state = bat->bat_state; - } else { - entp->u.tbe_test.tse_type = test->tes_type; - entp->u.tbe_test.tse_loop = test->tes_loop; - entp->u.tbe_test.tse_concur = test->tes_concur; - } - - list_for_each_entry(ndl, clilst, ndl_link) - LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_cli_nle); - - list_for_each_entry(ndl, srvlst, ndl_link) - LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_srv_nle); - - rc = copy_to_user(ent_up, entp, - sizeof(struct lstcon_test_batch_ent)) ? -EFAULT : 0; - - kfree(entp); - - return rc; -} - -static int -lstcon_batrpc_condition(int transop, struct lstcon_node *nd, void *arg) -{ - switch (transop) { - case LST_TRANS_TSBRUN: - if (nd->nd_state != LST_NODE_ACTIVE) - return -ENETDOWN; - break; - - case LST_TRANS_TSBSTOP: - if (nd->nd_state != LST_NODE_ACTIVE) - return 0; - break; - - case LST_TRANS_TSBCLIQRY: - case LST_TRANS_TSBSRVQRY: - break; - } - - return 1; -} - -static int -lstcon_batch_op(struct lstcon_batch *bat, int transop, - struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - int rc; - - rc = lstcon_rpc_trans_ndlist(&bat->bat_cli_list, - &bat->bat_trans_list, transop, - bat, lstcon_batrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, NULL); - - lstcon_rpc_trans_destroy(trans); - - return rc; -} - -int -lstcon_batch_run(char *name, int timeout, struct list_head __user *result_up) -{ - struct lstcon_batch *bat; - int rc; - - if (lstcon_batch_find(name, &bat)) { - CDEBUG(D_NET, "Can't find batch %s\n", name); - return -ENOENT; - } - - bat->bat_arg = timeout; - - rc = lstcon_batch_op(bat, LST_TRANS_TSBRUN, result_up); - - /* mark batch as running if it's started in any node */ - if (lstcon_tsbop_stat_success(lstcon_trans_stat(), 0)) - bat->bat_state = LST_BATCH_RUNNING; - - return rc; -} - -int -lstcon_batch_stop(char *name, int force, struct list_head __user *result_up) -{ - struct lstcon_batch *bat; - int rc; - - if (lstcon_batch_find(name, &bat)) { - CDEBUG(D_NET, "Can't find batch %s\n", name); - return -ENOENT; - } - - bat->bat_arg = force; - - rc = lstcon_batch_op(bat, LST_TRANS_TSBSTOP, result_up); - - /* mark batch as stopped if all RPCs finished */ - if (!lstcon_tsbop_stat_failure(lstcon_trans_stat(), 0)) - bat->bat_state = LST_BATCH_IDLE; - - return rc; -} - -static void -lstcon_batch_destroy(struct lstcon_batch *bat) -{ - struct lstcon_ndlink *ndl; - struct lstcon_test *test; - int i; - - list_del(&bat->bat_link); - - while (!list_empty(&bat->bat_test_list)) { - test = list_entry(bat->bat_test_list.next, - struct lstcon_test, tes_link); - LASSERT(list_empty(&test->tes_trans_list)); - - list_del(&test->tes_link); - - lstcon_group_decref(test->tes_src_grp); - lstcon_group_decref(test->tes_dst_grp); - - kfree(test); - } - - LASSERT(list_empty(&bat->bat_trans_list)); - - while (!list_empty(&bat->bat_cli_list)) { - ndl = list_entry(bat->bat_cli_list.next, - struct lstcon_ndlink, ndl_link); - list_del_init(&ndl->ndl_link); - - lstcon_ndlink_release(ndl); - } - - while (!list_empty(&bat->bat_srv_list)) { - ndl = list_entry(bat->bat_srv_list.next, - struct lstcon_ndlink, ndl_link); - list_del_init(&ndl->ndl_link); - - lstcon_ndlink_release(ndl); - } - - for (i = 0; i < LST_NODE_HASHSIZE; i++) { - LASSERT(list_empty(&bat->bat_cli_hash[i])); - LASSERT(list_empty(&bat->bat_srv_hash[i])); - } - - kfree(bat->bat_cli_hash); - kfree(bat->bat_srv_hash); - kfree(bat); -} - -static int -lstcon_testrpc_condition(int transop, struct lstcon_node *nd, void *arg) -{ - struct lstcon_test *test; - struct lstcon_batch *batch; - struct lstcon_ndlink *ndl; - struct list_head *hash; - struct list_head *head; - - test = (struct lstcon_test *)arg; - LASSERT(test); - - batch = test->tes_batch; - LASSERT(batch); - - if (test->tes_oneside && - transop == LST_TRANS_TSBSRVADD) - return 0; - - if (nd->nd_state != LST_NODE_ACTIVE) - return -ENETDOWN; - - if (transop == LST_TRANS_TSBCLIADD) { - hash = batch->bat_cli_hash; - head = &batch->bat_cli_list; - - } else { - LASSERT(transop == LST_TRANS_TSBSRVADD); - - hash = batch->bat_srv_hash; - head = &batch->bat_srv_list; - } - - LASSERT(nd->nd_id.nid != LNET_NID_ANY); - - if (lstcon_ndlink_find(hash, nd->nd_id, &ndl, 1)) - return -ENOMEM; - - if (list_empty(&ndl->ndl_link)) - list_add_tail(&ndl->ndl_link, head); - - return 1; -} - -static int -lstcon_test_nodes_add(struct lstcon_test *test, - struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_group *grp; - int transop; - int rc; - - LASSERT(test->tes_src_grp); - LASSERT(test->tes_dst_grp); - - transop = LST_TRANS_TSBSRVADD; - grp = test->tes_dst_grp; -again: - rc = lstcon_rpc_trans_ndlist(&grp->grp_ndl_list, - &test->tes_trans_list, transop, - test, lstcon_testrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - if (lstcon_trans_stat()->trs_rpc_errno || - lstcon_trans_stat()->trs_fwk_errno) { - lstcon_rpc_trans_interpreter(trans, result_up, NULL); - - lstcon_rpc_trans_destroy(trans); - /* return if any error */ - CDEBUG(D_NET, "Failed to add test %s, RPC error %d, framework error %d\n", - transop == LST_TRANS_TSBCLIADD ? "client" : "server", - lstcon_trans_stat()->trs_rpc_errno, - lstcon_trans_stat()->trs_fwk_errno); - - return rc; - } - - lstcon_rpc_trans_destroy(trans); - - if (transop == LST_TRANS_TSBCLIADD) - return rc; - - transop = LST_TRANS_TSBCLIADD; - grp = test->tes_src_grp; - test->tes_cliidx = 0; - - /* requests to test clients */ - goto again; -} - -static int -lstcon_verify_batch(const char *name, struct lstcon_batch **batch) -{ - int rc; - - rc = lstcon_batch_find(name, batch); - if (rc) { - CDEBUG(D_NET, "Can't find batch %s\n", name); - return rc; - } - - if ((*batch)->bat_state != LST_BATCH_IDLE) { - CDEBUG(D_NET, "Can't change running batch %s\n", name); - return -EINVAL; - } - - return 0; -} - -static int -lstcon_verify_group(const char *name, struct lstcon_group **grp) -{ - int rc; - struct lstcon_ndlink *ndl; - - rc = lstcon_group_find(name, grp); - if (rc) { - CDEBUG(D_NET, "can't find group %s\n", name); - return rc; - } - - list_for_each_entry(ndl, &(*grp)->grp_ndl_list, ndl_link) { - if (ndl->ndl_node->nd_state == LST_NODE_ACTIVE) - return 0; - } - - CDEBUG(D_NET, "Group %s has no ACTIVE nodes\n", name); - - return -EINVAL; -} - -int -lstcon_test_add(char *batch_name, int type, int loop, - int concur, int dist, int span, - char *src_name, char *dst_name, - void *param, int paramlen, int *retp, - struct list_head __user *result_up) -{ - struct lstcon_test *test = NULL; - int rc; - struct lstcon_group *src_grp = NULL; - struct lstcon_group *dst_grp = NULL; - struct lstcon_batch *batch = NULL; - - /* - * verify that a batch of the given name exists, and the groups - * that will be part of the batch exist and have at least one - * active node - */ - rc = lstcon_verify_batch(batch_name, &batch); - if (rc) - goto out; - - rc = lstcon_verify_group(src_name, &src_grp); - if (rc) - goto out; - - rc = lstcon_verify_group(dst_name, &dst_grp); - if (rc) - goto out; - - if (dst_grp->grp_userland) - *retp = 1; - - test = kzalloc(offsetof(struct lstcon_test, tes_param[paramlen]), - GFP_KERNEL); - if (!test) { - CERROR("Can't allocate test descriptor\n"); - rc = -ENOMEM; - - goto out; - } - - test->tes_hdr.tsb_id = batch->bat_hdr.tsb_id; - test->tes_batch = batch; - test->tes_type = type; - test->tes_oneside = 0; /* TODO */ - test->tes_loop = loop; - test->tes_concur = concur; - test->tes_stop_onerr = 1; /* TODO */ - test->tes_span = span; - test->tes_dist = dist; - test->tes_cliidx = 0; /* just used for creating RPC */ - test->tes_src_grp = src_grp; - test->tes_dst_grp = dst_grp; - INIT_LIST_HEAD(&test->tes_trans_list); - - if (param) { - test->tes_paramlen = paramlen; - memcpy(&test->tes_param[0], param, paramlen); - } - - rc = lstcon_test_nodes_add(test, result_up); - - if (rc) - goto out; - - if (lstcon_trans_stat()->trs_rpc_errno || - lstcon_trans_stat()->trs_fwk_errno) - CDEBUG(D_NET, "Failed to add test %d to batch %s\n", type, - batch_name); - - /* add to test list anyway, so user can check what's going on */ - list_add_tail(&test->tes_link, &batch->bat_test_list); - - batch->bat_ntest++; - test->tes_hdr.tsb_index = batch->bat_ntest; - - /* hold groups so nobody can change them */ - return rc; -out: - kfree(test); - - if (dst_grp) - lstcon_group_decref(dst_grp); - - if (src_grp) - lstcon_group_decref(src_grp); - - return rc; -} - -static int -lstcon_test_find(struct lstcon_batch *batch, int idx, - struct lstcon_test **testpp) -{ - struct lstcon_test *test; - - list_for_each_entry(test, &batch->bat_test_list, tes_link) { - if (idx == test->tes_hdr.tsb_index) { - *testpp = test; - return 0; - } - } - - return -ENOENT; -} - -static int -lstcon_tsbrpc_readent(int transop, struct srpc_msg *msg, - struct lstcon_rpc_ent __user *ent_up) -{ - struct srpc_batch_reply *rep = &msg->msg_body.bat_reply; - - LASSERT(transop == LST_TRANS_TSBCLIQRY || - transop == LST_TRANS_TSBSRVQRY); - - /* positive errno, framework error code */ - if (copy_to_user(&ent_up->rpe_priv[0], &rep->bar_active, - sizeof(rep->bar_active))) - return -EFAULT; - - return 0; -} - -int -lstcon_test_batch_query(char *name, int testidx, int client, - int timeout, struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - struct list_head *translist; - struct list_head *ndlist; - struct lstcon_tsb_hdr *hdr; - struct lstcon_batch *batch; - struct lstcon_test *test = NULL; - int transop; - int rc; - - rc = lstcon_batch_find(name, &batch); - if (rc) { - CDEBUG(D_NET, "Can't find batch: %s\n", name); - return rc; - } - - if (!testidx) { - translist = &batch->bat_trans_list; - ndlist = &batch->bat_cli_list; - hdr = &batch->bat_hdr; - } else { - /* query specified test only */ - rc = lstcon_test_find(batch, testidx, &test); - if (rc) { - CDEBUG(D_NET, "Can't find test: %d\n", testidx); - return rc; - } - - translist = &test->tes_trans_list; - ndlist = &test->tes_src_grp->grp_ndl_list; - hdr = &test->tes_hdr; - } - - transop = client ? LST_TRANS_TSBCLIQRY : LST_TRANS_TSBSRVQRY; - - rc = lstcon_rpc_trans_ndlist(ndlist, translist, transop, hdr, - lstcon_batrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - lstcon_rpc_trans_postwait(trans, timeout); - - /* query a batch, not a test */ - if (!testidx && - !lstcon_rpc_stat_failure(lstcon_trans_stat(), 0) && - !lstcon_tsbqry_stat_run(lstcon_trans_stat(), 0)) { - /* all RPCs finished, and no active test */ - batch->bat_state = LST_BATCH_IDLE; - } - - rc = lstcon_rpc_trans_interpreter(trans, result_up, - lstcon_tsbrpc_readent); - lstcon_rpc_trans_destroy(trans); - - return rc; -} - -static int -lstcon_statrpc_readent(int transop, struct srpc_msg *msg, - struct lstcon_rpc_ent __user *ent_up) -{ - struct srpc_stat_reply *rep = &msg->msg_body.stat_reply; - struct sfw_counters __user *sfwk_stat; - struct srpc_counters __user *srpc_stat; - struct lnet_counters __user *lnet_stat; - - if (rep->str_status) - return 0; - - sfwk_stat = (struct sfw_counters __user *)&ent_up->rpe_payload[0]; - srpc_stat = (struct srpc_counters __user *)(sfwk_stat + 1); - lnet_stat = (struct lnet_counters __user *)(srpc_stat + 1); - - if (copy_to_user(sfwk_stat, &rep->str_fw, sizeof(*sfwk_stat)) || - copy_to_user(srpc_stat, &rep->str_rpc, sizeof(*srpc_stat)) || - copy_to_user(lnet_stat, &rep->str_lnet, sizeof(*lnet_stat))) - return -EFAULT; - - return 0; -} - -static int -lstcon_ndlist_stat(struct list_head *ndlist, - int timeout, struct list_head __user *result_up) -{ - struct list_head head; - struct lstcon_rpc_trans *trans; - int rc; - - INIT_LIST_HEAD(&head); - - rc = lstcon_rpc_trans_ndlist(ndlist, &head, - LST_TRANS_STATQRY, NULL, NULL, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout)); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, - lstcon_statrpc_readent); - lstcon_rpc_trans_destroy(trans); - - return rc; -} - -int -lstcon_group_stat(char *grp_name, int timeout, - struct list_head __user *result_up) -{ - struct lstcon_group *grp; - int rc; - - rc = lstcon_group_find(grp_name, &grp); - if (rc) { - CDEBUG(D_NET, "Can't find group %s\n", grp_name); - return rc; - } - - rc = lstcon_ndlist_stat(&grp->grp_ndl_list, timeout, result_up); - - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_nodes_stat(int count, struct lnet_process_id __user *ids_up, - int timeout, struct list_head __user *result_up) -{ - struct lstcon_ndlink *ndl; - struct lstcon_group *tmp; - struct lnet_process_id id; - int i; - int rc; - - rc = lstcon_group_alloc(NULL, &tmp); - if (rc) { - CERROR("Out of memory\n"); - return -ENOMEM; - } - - for (i = 0 ; i < count; i++) { - if (copy_from_user(&id, &ids_up[i], sizeof(id))) { - rc = -EFAULT; - break; - } - - /* add to tmp group */ - rc = lstcon_group_ndlink_find(tmp, id, &ndl, 2); - if (rc) { - CDEBUG((rc == -ENOMEM) ? D_ERROR : D_NET, - "Failed to find or create %s: %d\n", - libcfs_id2str(id), rc); - break; - } - } - - if (rc) { - lstcon_group_decref(tmp); - return rc; - } - - rc = lstcon_ndlist_stat(&tmp->grp_ndl_list, timeout, result_up); - - lstcon_group_decref(tmp); - - return rc; -} - -static int -lstcon_debug_ndlist(struct list_head *ndlist, - struct list_head *translist, - int timeout, struct list_head __user *result_up) -{ - struct lstcon_rpc_trans *trans; - int rc; - - rc = lstcon_rpc_trans_ndlist(ndlist, translist, LST_TRANS_SESQRY, - NULL, lstcon_sesrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - lstcon_rpc_trans_postwait(trans, LST_VALIDATE_TIMEOUT(timeout)); - - rc = lstcon_rpc_trans_interpreter(trans, result_up, - lstcon_sesrpc_readent); - lstcon_rpc_trans_destroy(trans); - - return rc; -} - -int -lstcon_session_debug(int timeout, struct list_head __user *result_up) -{ - return lstcon_debug_ndlist(&console_session.ses_ndl_list, - NULL, timeout, result_up); -} - -int -lstcon_batch_debug(int timeout, char *name, - int client, struct list_head __user *result_up) -{ - struct lstcon_batch *bat; - int rc; - - rc = lstcon_batch_find(name, &bat); - if (rc) - return -ENOENT; - - rc = lstcon_debug_ndlist(client ? &bat->bat_cli_list : - &bat->bat_srv_list, - NULL, timeout, result_up); - - return rc; -} - -int -lstcon_group_debug(int timeout, char *name, - struct list_head __user *result_up) -{ - struct lstcon_group *grp; - int rc; - - rc = lstcon_group_find(name, &grp); - if (rc) - return -ENOENT; - - rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL, - timeout, result_up); - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_nodes_debug(int timeout, int count, - struct lnet_process_id __user *ids_up, - struct list_head __user *result_up) -{ - struct lnet_process_id id; - struct lstcon_ndlink *ndl; - struct lstcon_group *grp; - int i; - int rc; - - rc = lstcon_group_alloc(NULL, &grp); - if (rc) { - CDEBUG(D_NET, "Out of memory\n"); - return rc; - } - - for (i = 0; i < count; i++) { - if (copy_from_user(&id, &ids_up[i], sizeof(id))) { - rc = -EFAULT; - break; - } - - /* node is added to tmp group */ - rc = lstcon_group_ndlink_find(grp, id, &ndl, 1); - if (rc) { - CERROR("Can't create node link\n"); - break; - } - } - - if (rc) { - lstcon_group_decref(grp); - return rc; - } - - rc = lstcon_debug_ndlist(&grp->grp_ndl_list, NULL, - timeout, result_up); - - lstcon_group_decref(grp); - - return rc; -} - -int -lstcon_session_match(struct lst_sid sid) -{ - return (console_session.ses_id.ses_nid == sid.ses_nid && - console_session.ses_id.ses_stamp == sid.ses_stamp) ? 1 : 0; -} - -static void -lstcon_new_session_id(struct lst_sid *sid) -{ - struct lnet_process_id id; - - LASSERT(console_session.ses_state == LST_SESSION_NONE); - - LNetGetId(1, &id); - sid->ses_nid = id.nid; - sid->ses_stamp = cfs_time_current(); -} - -int -lstcon_session_new(char *name, int key, unsigned int feats, - int timeout, int force, struct lst_sid __user *sid_up) -{ - int rc = 0; - int i; - - if (console_session.ses_state != LST_SESSION_NONE) { - /* session exists */ - if (!force) { - CNETERR("Session %s already exists\n", - console_session.ses_name); - return -EEXIST; - } - - rc = lstcon_session_end(); - - /* lstcon_session_end() only return local error */ - if (rc) - return rc; - } - - if (feats & ~LST_FEATS_MASK) { - CNETERR("Unknown session features %x\n", - (feats & ~LST_FEATS_MASK)); - return -EINVAL; - } - - for (i = 0; i < LST_GLOBAL_HASHSIZE; i++) - LASSERT(list_empty(&console_session.ses_ndl_hash[i])); - - lstcon_new_session_id(&console_session.ses_id); - - console_session.ses_key = key; - console_session.ses_state = LST_SESSION_ACTIVE; - console_session.ses_force = !!force; - console_session.ses_features = feats; - console_session.ses_feats_updated = 0; - console_session.ses_timeout = (timeout <= 0) ? - LST_CONSOLE_TIMEOUT : timeout; - - if (strlen(name) > sizeof(console_session.ses_name) - 1) - return -E2BIG; - strlcpy(console_session.ses_name, name, - sizeof(console_session.ses_name)); - - rc = lstcon_batch_add(LST_DEFAULT_BATCH); - if (rc) - return rc; - - rc = lstcon_rpc_pinger_start(); - if (rc) { - struct lstcon_batch *bat = NULL; - - lstcon_batch_find(LST_DEFAULT_BATCH, &bat); - lstcon_batch_destroy(bat); - - return rc; - } - - if (!copy_to_user(sid_up, &console_session.ses_id, - sizeof(struct lst_sid))) - return rc; - - lstcon_session_end(); - - return -EFAULT; -} - -int -lstcon_session_info(struct lst_sid __user *sid_up, int __user *key_up, - unsigned __user *featp, - struct lstcon_ndlist_ent __user *ndinfo_up, - char __user *name_up, int len) -{ - struct lstcon_ndlist_ent *entp; - struct lstcon_ndlink *ndl; - int rc = 0; - - if (console_session.ses_state != LST_SESSION_ACTIVE) - return -ESRCH; - - entp = kzalloc(sizeof(*entp), GFP_NOFS); - if (!entp) - return -ENOMEM; - - list_for_each_entry(ndl, &console_session.ses_ndl_list, ndl_link) - LST_NODE_STATE_COUNTER(ndl->ndl_node, entp); - - if (copy_to_user(sid_up, &console_session.ses_id, - sizeof(*sid_up)) || - copy_to_user(key_up, &console_session.ses_key, - sizeof(*key_up)) || - copy_to_user(featp, &console_session.ses_features, - sizeof(*featp)) || - copy_to_user(ndinfo_up, entp, sizeof(*entp)) || - copy_to_user(name_up, console_session.ses_name, len)) - rc = -EFAULT; - - kfree(entp); - - return rc; -} - -int -lstcon_session_end(void) -{ - struct lstcon_rpc_trans *trans; - struct lstcon_group *grp; - struct lstcon_batch *bat; - int rc = 0; - - LASSERT(console_session.ses_state == LST_SESSION_ACTIVE); - - rc = lstcon_rpc_trans_ndlist(&console_session.ses_ndl_list, - NULL, LST_TRANS_SESEND, NULL, - lstcon_sesrpc_condition, &trans); - if (rc) { - CERROR("Can't create transaction: %d\n", rc); - return rc; - } - - console_session.ses_shutdown = 1; - - lstcon_rpc_pinger_stop(); - - lstcon_rpc_trans_postwait(trans, LST_TRANS_TIMEOUT); - - lstcon_rpc_trans_destroy(trans); - /* User can do nothing even rpc failed, so go on */ - - /* waiting for orphan rpcs to die */ - lstcon_rpc_cleanup_wait(); - - console_session.ses_id = LST_INVALID_SID; - console_session.ses_state = LST_SESSION_NONE; - console_session.ses_key = 0; - console_session.ses_force = 0; - console_session.ses_feats_updated = 0; - - /* destroy all batches */ - while (!list_empty(&console_session.ses_bat_list)) { - bat = list_entry(console_session.ses_bat_list.next, - struct lstcon_batch, bat_link); - - lstcon_batch_destroy(bat); - } - - /* destroy all groups */ - while (!list_empty(&console_session.ses_grp_list)) { - grp = list_entry(console_session.ses_grp_list.next, - struct lstcon_group, grp_link); - LASSERT(grp->grp_ref == 1); - - lstcon_group_decref(grp); - } - - /* all nodes should be released */ - LASSERT(list_empty(&console_session.ses_ndl_list)); - - console_session.ses_shutdown = 0; - console_session.ses_expired = 0; - - return rc; -} - -int -lstcon_session_feats_check(unsigned int feats) -{ - int rc = 0; - - if (feats & ~LST_FEATS_MASK) { - CERROR("Can't support these features: %x\n", - (feats & ~LST_FEATS_MASK)); - return -EPROTO; - } - - spin_lock(&console_session.ses_rpc_lock); - - if (!console_session.ses_feats_updated) { - console_session.ses_feats_updated = 1; - console_session.ses_features = feats; - } - - if (console_session.ses_features != feats) - rc = -EPROTO; - - spin_unlock(&console_session.ses_rpc_lock); - - if (rc) { - CERROR("remote features %x do not match with session features %x of console\n", - feats, console_session.ses_features); - } - - return rc; -} - -static int -lstcon_acceptor_handle(struct srpc_server_rpc *rpc) -{ - struct srpc_msg *rep = &rpc->srpc_replymsg; - struct srpc_msg *req = &rpc->srpc_reqstbuf->buf_msg; - struct srpc_join_reqst *jreq = &req->msg_body.join_reqst; - struct srpc_join_reply *jrep = &rep->msg_body.join_reply; - struct lstcon_group *grp = NULL; - struct lstcon_ndlink *ndl; - int rc = 0; - - sfw_unpack_message(req); - - mutex_lock(&console_session.ses_mutex); - - jrep->join_sid = console_session.ses_id; - - if (console_session.ses_id.ses_nid == LNET_NID_ANY) { - jrep->join_status = ESRCH; - goto out; - } - - if (lstcon_session_feats_check(req->msg_ses_feats)) { - jrep->join_status = EPROTO; - goto out; - } - - if (jreq->join_sid.ses_nid != LNET_NID_ANY && - !lstcon_session_match(jreq->join_sid)) { - jrep->join_status = EBUSY; - goto out; - } - - if (lstcon_group_find(jreq->join_group, &grp)) { - rc = lstcon_group_alloc(jreq->join_group, &grp); - if (rc) { - CERROR("Out of memory\n"); - goto out; - } - - list_add_tail(&grp->grp_link, - &console_session.ses_grp_list); - lstcon_group_addref(grp); - } - - if (grp->grp_ref > 2) { - /* Group in using */ - jrep->join_status = EBUSY; - goto out; - } - - rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 0); - if (!rc) { - jrep->join_status = EEXIST; - goto out; - } - - rc = lstcon_group_ndlink_find(grp, rpc->srpc_peer, &ndl, 1); - if (rc) { - CERROR("Out of memory\n"); - goto out; - } - - ndl->ndl_node->nd_state = LST_NODE_ACTIVE; - ndl->ndl_node->nd_timeout = console_session.ses_timeout; - - if (!grp->grp_userland) - grp->grp_userland = 1; - - strlcpy(jrep->join_session, console_session.ses_name, - sizeof(jrep->join_session)); - jrep->join_timeout = console_session.ses_timeout; - jrep->join_status = 0; - -out: - rep->msg_ses_feats = console_session.ses_features; - if (grp) - lstcon_group_decref(grp); - - mutex_unlock(&console_session.ses_mutex); - - return rc; -} - -static struct srpc_service lstcon_acceptor_service; - -static void lstcon_init_acceptor_service(void) -{ - /* initialize selftest console acceptor service table */ - lstcon_acceptor_service.sv_name = "join session"; - lstcon_acceptor_service.sv_handler = lstcon_acceptor_handle; - lstcon_acceptor_service.sv_id = SRPC_SERVICE_JOIN; - lstcon_acceptor_service.sv_wi_total = SFW_FRWK_WI_MAX; -} - -static DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry); - -/* initialize console */ -int -lstcon_console_init(void) -{ - int i; - int rc; - - memset(&console_session, 0, sizeof(struct lstcon_session)); - - console_session.ses_id = LST_INVALID_SID; - console_session.ses_state = LST_SESSION_NONE; - console_session.ses_timeout = 0; - console_session.ses_force = 0; - console_session.ses_expired = 0; - console_session.ses_feats_updated = 0; - console_session.ses_features = LST_FEATS_MASK; - console_session.ses_laststamp = ktime_get_real_seconds(); - - mutex_init(&console_session.ses_mutex); - - INIT_LIST_HEAD(&console_session.ses_ndl_list); - INIT_LIST_HEAD(&console_session.ses_grp_list); - INIT_LIST_HEAD(&console_session.ses_bat_list); - INIT_LIST_HEAD(&console_session.ses_trans_list); - - console_session.ses_ndl_hash = - kmalloc(sizeof(struct list_head) * LST_GLOBAL_HASHSIZE, GFP_KERNEL); - if (!console_session.ses_ndl_hash) - return -ENOMEM; - - for (i = 0; i < LST_GLOBAL_HASHSIZE; i++) - INIT_LIST_HEAD(&console_session.ses_ndl_hash[i]); - - /* initialize acceptor service table */ - lstcon_init_acceptor_service(); - - rc = srpc_add_service(&lstcon_acceptor_service); - LASSERT(rc != -EBUSY); - if (rc) { - kfree(console_session.ses_ndl_hash); - return rc; - } - - rc = srpc_service_add_buffers(&lstcon_acceptor_service, - lstcon_acceptor_service.sv_wi_total); - if (rc) { - rc = -ENOMEM; - goto out; - } - - rc = libcfs_register_ioctl(&lstcon_ioctl_handler); - - if (!rc) { - lstcon_rpc_module_init(); - return 0; - } - -out: - srpc_shutdown_service(&lstcon_acceptor_service); - srpc_remove_service(&lstcon_acceptor_service); - - kfree(console_session.ses_ndl_hash); - - srpc_wait_service_shutdown(&lstcon_acceptor_service); - - return rc; -} - -int -lstcon_console_fini(void) -{ - int i; - - libcfs_deregister_ioctl(&lstcon_ioctl_handler); - - mutex_lock(&console_session.ses_mutex); - - srpc_shutdown_service(&lstcon_acceptor_service); - srpc_remove_service(&lstcon_acceptor_service); - - if (console_session.ses_state != LST_SESSION_NONE) - lstcon_session_end(); - - lstcon_rpc_module_fini(); - - mutex_unlock(&console_session.ses_mutex); - - LASSERT(list_empty(&console_session.ses_ndl_list)); - LASSERT(list_empty(&console_session.ses_grp_list)); - LASSERT(list_empty(&console_session.ses_bat_list)); - LASSERT(list_empty(&console_session.ses_trans_list)); - - for (i = 0; i < LST_NODE_HASHSIZE; i++) - LASSERT(list_empty(&console_session.ses_ndl_hash[i])); - - kfree(console_session.ses_ndl_hash); - - srpc_wait_service_shutdown(&lstcon_acceptor_service); - - return 0; -} diff --git a/drivers/staging/lustre/lnet/selftest/console.h b/drivers/staging/lustre/lnet/selftest/console.h deleted file mode 100644 index 3933ed4cca93..000000000000 --- a/drivers/staging/lustre/lnet/selftest/console.h +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/console.h - * - * kernel structure for LST console - * - * Author: Liang Zhen <liangzhen@clusterfs.com> - */ - -#ifndef __LST_CONSOLE_H__ -#define __LST_CONSOLE_H__ - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-types.h> -#include <uapi/linux/lnet/lnetst.h> -#include "selftest.h" -#include "conrpc.h" - -/* node descriptor */ -struct lstcon_node { - struct lnet_process_id nd_id; /* id of the node */ - int nd_ref; /* reference count */ - int nd_state; /* state of the node */ - int nd_timeout; /* session timeout */ - unsigned long nd_stamp; /* timestamp of last replied RPC */ - struct lstcon_rpc nd_ping; /* ping rpc */ -}; - -/* node link descriptor */ -struct lstcon_ndlink { - struct list_head ndl_link; /* chain on list */ - struct list_head ndl_hlink; /* chain on hash */ - struct lstcon_node *ndl_node; /* pointer to node */ -}; - -/* (alias of nodes) group descriptor */ -struct lstcon_group { - struct list_head grp_link; /* chain on global group list - */ - int grp_ref; /* reference count */ - int grp_userland; /* has userland nodes */ - int grp_nnode; /* # of nodes */ - char grp_name[LST_NAME_SIZE]; /* group name */ - - struct list_head grp_trans_list; /* transaction list */ - struct list_head grp_ndl_list; /* nodes list */ - struct list_head grp_ndl_hash[0]; /* hash table for nodes */ -}; - -#define LST_BATCH_IDLE 0xB0 /* idle batch */ -#define LST_BATCH_RUNNING 0xB1 /* running batch */ - -struct lstcon_tsb_hdr { - struct lst_bid tsb_id; /* batch ID */ - int tsb_index; /* test index */ -}; - -/* (tests ) batch descriptor */ -struct lstcon_batch { - struct lstcon_tsb_hdr bat_hdr; /* test_batch header */ - struct list_head bat_link; /* chain on session's batches list */ - int bat_ntest; /* # of test */ - int bat_state; /* state of the batch */ - int bat_arg; /* parameter for run|stop, timeout - * for run, force for stop - */ - char bat_name[LST_NAME_SIZE];/* name of batch */ - - struct list_head bat_test_list; /* list head of tests (struct lstcon_test) - */ - struct list_head bat_trans_list; /* list head of transaction */ - struct list_head bat_cli_list; /* list head of client nodes - * (struct lstcon_node) - */ - struct list_head *bat_cli_hash; /* hash table of client nodes */ - struct list_head bat_srv_list; /* list head of server nodes */ - struct list_head *bat_srv_hash; /* hash table of server nodes */ -}; - -/* a single test descriptor */ -struct lstcon_test { - struct lstcon_tsb_hdr tes_hdr; /* test batch header */ - struct list_head tes_link; /* chain on batch's tests list */ - struct lstcon_batch *tes_batch; /* pointer to batch */ - - int tes_type; /* type of the test, i.e: bulk, ping */ - int tes_stop_onerr; /* stop on error */ - int tes_oneside; /* one-sided test */ - int tes_concur; /* concurrency */ - int tes_loop; /* loop count */ - int tes_dist; /* nodes distribution of target group */ - int tes_span; /* nodes span of target group */ - int tes_cliidx; /* client index, used for RPC creating */ - - struct list_head tes_trans_list; /* transaction list */ - struct lstcon_group *tes_src_grp; /* group run the test */ - struct lstcon_group *tes_dst_grp; /* target group */ - - int tes_paramlen; /* test parameter length */ - char tes_param[0]; /* test parameter */ -}; - -#define LST_GLOBAL_HASHSIZE 503 /* global nodes hash table size */ -#define LST_NODE_HASHSIZE 239 /* node hash table (for batch or group) */ - -#define LST_SESSION_NONE 0x0 /* no session */ -#define LST_SESSION_ACTIVE 0x1 /* working session */ - -#define LST_CONSOLE_TIMEOUT 300 /* default console timeout */ - -struct lstcon_session { - struct mutex ses_mutex; /* only 1 thread in session */ - struct lst_sid ses_id; /* global session id */ - int ses_key; /* local session key */ - int ses_state; /* state of session */ - int ses_timeout; /* timeout in seconds */ - time64_t ses_laststamp; /* last operation stamp (seconds) - */ - unsigned int ses_features; /* tests features of the session - */ - unsigned int ses_feats_updated:1; /* features are synced with - * remote test nodes - */ - unsigned int ses_force:1; /* force creating */ - unsigned int ses_shutdown:1; /* session is shutting down */ - unsigned int ses_expired:1; /* console is timedout */ - __u64 ses_id_cookie; /* batch id cookie */ - char ses_name[LST_NAME_SIZE];/* session name */ - struct lstcon_rpc_trans *ses_ping; /* session pinger */ - struct stt_timer ses_ping_timer; /* timer for pinger */ - struct lstcon_trans_stat ses_trans_stat; /* transaction stats */ - - struct list_head ses_trans_list; /* global list of transaction */ - struct list_head ses_grp_list; /* global list of groups */ - struct list_head ses_bat_list; /* global list of batches */ - struct list_head ses_ndl_list; /* global list of nodes */ - struct list_head *ses_ndl_hash; /* hash table of nodes */ - - spinlock_t ses_rpc_lock; /* serialize */ - atomic_t ses_rpc_counter; /* # of initialized RPCs */ - struct list_head ses_rpc_freelist; /* idle console rpc */ -}; /* session descriptor */ - -extern struct lstcon_session console_session; - -static inline struct lstcon_trans_stat * -lstcon_trans_stat(void) -{ - return &console_session.ses_trans_stat; -} - -static inline struct list_head * -lstcon_id2hash(struct lnet_process_id id, struct list_head *hash) -{ - unsigned int idx = LNET_NIDADDR(id.nid) % LST_NODE_HASHSIZE; - - return &hash[idx]; -} - -int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr); -int lstcon_console_init(void); -int lstcon_console_fini(void); -int lstcon_session_match(struct lst_sid sid); -int lstcon_session_new(char *name, int key, unsigned int version, - int timeout, int flags, struct lst_sid __user *sid_up); -int lstcon_session_info(struct lst_sid __user *sid_up, int __user *key, - unsigned __user *verp, struct lstcon_ndlist_ent __user *entp, - char __user *name_up, int len); -int lstcon_session_end(void); -int lstcon_session_debug(int timeout, struct list_head __user *result_up); -int lstcon_session_feats_check(unsigned int feats); -int lstcon_batch_debug(int timeout, char *name, - int client, struct list_head __user *result_up); -int lstcon_group_debug(int timeout, char *name, - struct list_head __user *result_up); -int lstcon_nodes_debug(int timeout, int nnd, - struct lnet_process_id __user *nds_up, - struct list_head __user *result_up); -int lstcon_group_add(char *name); -int lstcon_group_del(char *name); -int lstcon_group_clean(char *name, int args); -int lstcon_group_refresh(char *name, struct list_head __user *result_up); -int lstcon_nodes_add(char *name, int nnd, struct lnet_process_id __user *nds_up, - unsigned int *featp, struct list_head __user *result_up); -int lstcon_nodes_remove(char *name, int nnd, - struct lnet_process_id __user *nds_up, - struct list_head __user *result_up); -int lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gent_up, - int *index_p, int *ndent_p, - struct lstcon_node_ent __user *ndents_up); -int lstcon_group_list(int idx, int len, char __user *name_up); -int lstcon_batch_add(char *name); -int lstcon_batch_run(char *name, int timeout, - struct list_head __user *result_up); -int lstcon_batch_stop(char *name, int force, - struct list_head __user *result_up); -int lstcon_test_batch_query(char *name, int testidx, - int client, int timeout, - struct list_head __user *result_up); -int lstcon_batch_del(char *name); -int lstcon_batch_list(int idx, int namelen, char __user *name_up); -int lstcon_batch_info(char *name, struct lstcon_test_batch_ent __user *ent_up, - int server, int testidx, int *index_p, - int *ndent_p, struct lstcon_node_ent __user *dents_up); -int lstcon_group_stat(char *grp_name, int timeout, - struct list_head __user *result_up); -int lstcon_nodes_stat(int count, struct lnet_process_id __user *ids_up, - int timeout, struct list_head __user *result_up); -int lstcon_test_add(char *batch_name, int type, int loop, - int concur, int dist, int span, - char *src_name, char *dst_name, - void *param, int paramlen, int *retp, - struct list_head __user *result_up); -#endif diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c deleted file mode 100644 index 0ca1e3a780ca..000000000000 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ /dev/null @@ -1,1786 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/framework.c - * - * Author: Isaac Huang <isaac@clusterfs.com> - * Author: Liang Zhen <liangzhen@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_LNET - -#include "selftest.h" - -struct lst_sid LST_INVALID_SID = {LNET_NID_ANY, -1}; - -static int session_timeout = 100; -module_param(session_timeout, int, 0444); -MODULE_PARM_DESC(session_timeout, "test session timeout in seconds (100 by default, 0 == never)"); - -static int rpc_timeout = 64; -module_param(rpc_timeout, int, 0644); -MODULE_PARM_DESC(rpc_timeout, "rpc timeout in seconds (64 by default, 0 == never)"); - -#define sfw_unpack_id(id) \ -do { \ - __swab64s(&(id).nid); \ - __swab32s(&(id).pid); \ -} while (0) - -#define sfw_unpack_sid(sid) \ -do { \ - __swab64s(&(sid).ses_nid); \ - __swab64s(&(sid).ses_stamp); \ -} while (0) - -#define sfw_unpack_fw_counters(fc) \ -do { \ - __swab32s(&(fc).running_ms); \ - __swab32s(&(fc).active_batches); \ - __swab32s(&(fc).zombie_sessions); \ - __swab32s(&(fc).brw_errors); \ - __swab32s(&(fc).ping_errors); \ -} while (0) - -#define sfw_unpack_rpc_counters(rc) \ -do { \ - __swab32s(&(rc).errors); \ - __swab32s(&(rc).rpcs_sent); \ - __swab32s(&(rc).rpcs_rcvd); \ - __swab32s(&(rc).rpcs_dropped); \ - __swab32s(&(rc).rpcs_expired); \ - __swab64s(&(rc).bulk_get); \ - __swab64s(&(rc).bulk_put); \ -} while (0) - -#define sfw_unpack_lnet_counters(lc) \ -do { \ - __swab32s(&(lc).errors); \ - __swab32s(&(lc).msgs_max); \ - __swab32s(&(lc).msgs_alloc); \ - __swab32s(&(lc).send_count); \ - __swab32s(&(lc).recv_count); \ - __swab32s(&(lc).drop_count); \ - __swab32s(&(lc).route_count); \ - __swab64s(&(lc).send_length); \ - __swab64s(&(lc).recv_length); \ - __swab64s(&(lc).drop_length); \ - __swab64s(&(lc).route_length); \ -} while (0) - -#define sfw_test_active(t) (atomic_read(&(t)->tsi_nactive)) -#define sfw_batch_active(b) (atomic_read(&(b)->bat_nactive)) - -static struct smoketest_framework { - struct list_head fw_zombie_rpcs; /* RPCs to be recycled */ - struct list_head fw_zombie_sessions; /* stopping sessions */ - struct list_head fw_tests; /* registered test cases */ - atomic_t fw_nzombies; /* # zombie sessions */ - spinlock_t fw_lock; /* serialise */ - struct sfw_session *fw_session; /* _the_ session */ - int fw_shuttingdown; /* shutdown in progress */ - struct srpc_server_rpc *fw_active_srpc;/* running RPC */ -} sfw_data; - -/* forward ref's */ -int sfw_stop_batch(struct sfw_batch *tsb, int force); -void sfw_destroy_session(struct sfw_session *sn); - -static inline struct sfw_test_case * -sfw_find_test_case(int id) -{ - struct sfw_test_case *tsc; - - LASSERT(id <= SRPC_SERVICE_MAX_ID); - LASSERT(id > SRPC_FRAMEWORK_SERVICE_MAX_ID); - - list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { - if (tsc->tsc_srv_service->sv_id == id) - return tsc; - } - - return NULL; -} - -static int -sfw_register_test(struct srpc_service *service, - struct sfw_test_client_ops *cliops) -{ - struct sfw_test_case *tsc; - - if (sfw_find_test_case(service->sv_id)) { - CERROR("Failed to register test %s (%d)\n", - service->sv_name, service->sv_id); - return -EEXIST; - } - - tsc = kzalloc(sizeof(struct sfw_test_case), GFP_NOFS); - if (!tsc) - return -ENOMEM; - - tsc->tsc_cli_ops = cliops; - tsc->tsc_srv_service = service; - - list_add_tail(&tsc->tsc_list, &sfw_data.fw_tests); - return 0; -} - -static void -sfw_add_session_timer(void) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct stt_timer *timer = &sn->sn_timer; - - LASSERT(!sfw_data.fw_shuttingdown); - - if (!sn || !sn->sn_timeout) - return; - - LASSERT(!sn->sn_timer_active); - - sn->sn_timer_active = 1; - timer->stt_expires = ktime_get_real_seconds() + sn->sn_timeout; - stt_add_timer(timer); -} - -static int -sfw_del_session_timer(void) -{ - struct sfw_session *sn = sfw_data.fw_session; - - if (!sn || !sn->sn_timer_active) - return 0; - - LASSERT(sn->sn_timeout); - - if (stt_del_timer(&sn->sn_timer)) { /* timer defused */ - sn->sn_timer_active = 0; - return 0; - } - - return -EBUSY; /* racing with sfw_session_expired() */ -} - -static void -sfw_deactivate_session(void) -__must_hold(&sfw_data.fw_lock) -{ - struct sfw_session *sn = sfw_data.fw_session; - int nactive = 0; - struct sfw_batch *tsb; - struct sfw_test_case *tsc; - - if (!sn) - return; - - LASSERT(!sn->sn_timer_active); - - sfw_data.fw_session = NULL; - atomic_inc(&sfw_data.fw_nzombies); - list_add(&sn->sn_list, &sfw_data.fw_zombie_sessions); - - spin_unlock(&sfw_data.fw_lock); - - list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { - srpc_abort_service(tsc->tsc_srv_service); - } - - spin_lock(&sfw_data.fw_lock); - - list_for_each_entry(tsb, &sn->sn_batches, bat_list) { - if (sfw_batch_active(tsb)) { - nactive++; - sfw_stop_batch(tsb, 1); - } - } - - if (nactive) - return; /* wait for active batches to stop */ - - list_del_init(&sn->sn_list); - spin_unlock(&sfw_data.fw_lock); - - sfw_destroy_session(sn); - - spin_lock(&sfw_data.fw_lock); -} - -static void -sfw_session_expired(void *data) -{ - struct sfw_session *sn = data; - - spin_lock(&sfw_data.fw_lock); - - LASSERT(sn->sn_timer_active); - LASSERT(sn == sfw_data.fw_session); - - CWARN("Session expired! sid: %s-%llu, name: %s\n", - libcfs_nid2str(sn->sn_id.ses_nid), - sn->sn_id.ses_stamp, &sn->sn_name[0]); - - sn->sn_timer_active = 0; - sfw_deactivate_session(); - - spin_unlock(&sfw_data.fw_lock); -} - -static inline void -sfw_init_session(struct sfw_session *sn, struct lst_sid sid, - unsigned int features, const char *name) -{ - struct stt_timer *timer = &sn->sn_timer; - - memset(sn, 0, sizeof(struct sfw_session)); - INIT_LIST_HEAD(&sn->sn_list); - INIT_LIST_HEAD(&sn->sn_batches); - atomic_set(&sn->sn_refcount, 1); /* +1 for caller */ - atomic_set(&sn->sn_brw_errors, 0); - atomic_set(&sn->sn_ping_errors, 0); - strlcpy(&sn->sn_name[0], name, sizeof(sn->sn_name)); - - sn->sn_timer_active = 0; - sn->sn_id = sid; - sn->sn_features = features; - sn->sn_timeout = session_timeout; - sn->sn_started = cfs_time_current(); - - timer->stt_data = sn; - timer->stt_func = sfw_session_expired; - INIT_LIST_HEAD(&timer->stt_list); -} - -/* completion handler for incoming framework RPCs */ -static void -sfw_server_rpc_done(struct srpc_server_rpc *rpc) -{ - struct srpc_service *sv = rpc->srpc_scd->scd_svc; - int status = rpc->srpc_status; - - CDEBUG(D_NET, "Incoming framework RPC done: service %s, peer %s, status %s:%d\n", - sv->sv_name, libcfs_id2str(rpc->srpc_peer), - swi_state2str(rpc->srpc_wi.swi_state), - status); - - if (rpc->srpc_bulk) - sfw_free_pages(rpc); -} - -static void -sfw_client_rpc_fini(struct srpc_client_rpc *rpc) -{ - LASSERT(!rpc->crpc_bulk.bk_niov); - LASSERT(list_empty(&rpc->crpc_list)); - LASSERT(!atomic_read(&rpc->crpc_refcount)); - - CDEBUG(D_NET, "Outgoing framework RPC done: service %d, peer %s, status %s:%d:%d\n", - rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), - swi_state2str(rpc->crpc_wi.swi_state), - rpc->crpc_aborted, rpc->crpc_status); - - spin_lock(&sfw_data.fw_lock); - - /* my callers must finish all RPCs before shutting me down */ - LASSERT(!sfw_data.fw_shuttingdown); - list_add(&rpc->crpc_list, &sfw_data.fw_zombie_rpcs); - - spin_unlock(&sfw_data.fw_lock); -} - -static struct sfw_batch * -sfw_find_batch(struct lst_bid bid) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct sfw_batch *bat; - - LASSERT(sn); - - list_for_each_entry(bat, &sn->sn_batches, bat_list) { - if (bat->bat_id.bat_id == bid.bat_id) - return bat; - } - - return NULL; -} - -static struct sfw_batch * -sfw_bid2batch(struct lst_bid bid) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct sfw_batch *bat; - - LASSERT(sn); - - bat = sfw_find_batch(bid); - if (bat) - return bat; - - bat = kzalloc(sizeof(struct sfw_batch), GFP_NOFS); - if (!bat) - return NULL; - - bat->bat_error = 0; - bat->bat_session = sn; - bat->bat_id = bid; - atomic_set(&bat->bat_nactive, 0); - INIT_LIST_HEAD(&bat->bat_tests); - - list_add_tail(&bat->bat_list, &sn->sn_batches); - return bat; -} - -static int -sfw_get_stats(struct srpc_stat_reqst *request, struct srpc_stat_reply *reply) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct sfw_counters *cnt = &reply->str_fw; - struct sfw_batch *bat; - - reply->str_sid = !sn ? LST_INVALID_SID : sn->sn_id; - - if (request->str_sid.ses_nid == LNET_NID_ANY) { - reply->str_status = EINVAL; - return 0; - } - - if (!sn || !sfw_sid_equal(request->str_sid, sn->sn_id)) { - reply->str_status = ESRCH; - return 0; - } - - lnet_counters_get(&reply->str_lnet); - srpc_get_counters(&reply->str_rpc); - - /* - * send over the msecs since the session was started - * with 32 bits to send, this is ~49 days - */ - cnt->running_ms = jiffies_to_msecs(jiffies - sn->sn_started); - cnt->brw_errors = atomic_read(&sn->sn_brw_errors); - cnt->ping_errors = atomic_read(&sn->sn_ping_errors); - cnt->zombie_sessions = atomic_read(&sfw_data.fw_nzombies); - - cnt->active_batches = 0; - list_for_each_entry(bat, &sn->sn_batches, bat_list) { - if (atomic_read(&bat->bat_nactive) > 0) - cnt->active_batches++; - } - - reply->str_status = 0; - return 0; -} - -int -sfw_make_session(struct srpc_mksn_reqst *request, struct srpc_mksn_reply *reply) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct srpc_msg *msg = container_of(request, struct srpc_msg, - msg_body.mksn_reqst); - int cplen = 0; - - if (request->mksn_sid.ses_nid == LNET_NID_ANY) { - reply->mksn_sid = !sn ? LST_INVALID_SID : sn->sn_id; - reply->mksn_status = EINVAL; - return 0; - } - - if (sn) { - reply->mksn_status = 0; - reply->mksn_sid = sn->sn_id; - reply->mksn_timeout = sn->sn_timeout; - - if (sfw_sid_equal(request->mksn_sid, sn->sn_id)) { - atomic_inc(&sn->sn_refcount); - return 0; - } - - if (!request->mksn_force) { - reply->mksn_status = EBUSY; - cplen = strlcpy(&reply->mksn_name[0], &sn->sn_name[0], - sizeof(reply->mksn_name)); - if (cplen >= sizeof(reply->mksn_name)) - return -E2BIG; - return 0; - } - } - - /* - * reject the request if it requires unknown features - * NB: old version will always accept all features because it's not - * aware of srpc_msg::msg_ses_feats, it's a defect but it's also - * harmless because it will return zero feature to console, and it's - * console's responsibility to make sure all nodes in a session have - * same feature mask. - */ - if (msg->msg_ses_feats & ~LST_FEATS_MASK) { - reply->mksn_status = EPROTO; - return 0; - } - - /* brand new or create by force */ - sn = kzalloc(sizeof(struct sfw_session), GFP_NOFS); - if (!sn) { - CERROR("dropping RPC mksn under memory pressure\n"); - return -ENOMEM; - } - - sfw_init_session(sn, request->mksn_sid, - msg->msg_ses_feats, &request->mksn_name[0]); - - spin_lock(&sfw_data.fw_lock); - - sfw_deactivate_session(); - LASSERT(!sfw_data.fw_session); - sfw_data.fw_session = sn; - - spin_unlock(&sfw_data.fw_lock); - - reply->mksn_status = 0; - reply->mksn_sid = sn->sn_id; - reply->mksn_timeout = sn->sn_timeout; - return 0; -} - -static int -sfw_remove_session(struct srpc_rmsn_reqst *request, - struct srpc_rmsn_reply *reply) -{ - struct sfw_session *sn = sfw_data.fw_session; - - reply->rmsn_sid = !sn ? LST_INVALID_SID : sn->sn_id; - - if (request->rmsn_sid.ses_nid == LNET_NID_ANY) { - reply->rmsn_status = EINVAL; - return 0; - } - - if (!sn || !sfw_sid_equal(request->rmsn_sid, sn->sn_id)) { - reply->rmsn_status = !sn ? ESRCH : EBUSY; - return 0; - } - - if (!atomic_dec_and_test(&sn->sn_refcount)) { - reply->rmsn_status = 0; - return 0; - } - - spin_lock(&sfw_data.fw_lock); - sfw_deactivate_session(); - spin_unlock(&sfw_data.fw_lock); - - reply->rmsn_status = 0; - reply->rmsn_sid = LST_INVALID_SID; - LASSERT(!sfw_data.fw_session); - return 0; -} - -static int -sfw_debug_session(struct srpc_debug_reqst *request, - struct srpc_debug_reply *reply) -{ - struct sfw_session *sn = sfw_data.fw_session; - - if (!sn) { - reply->dbg_status = ESRCH; - reply->dbg_sid = LST_INVALID_SID; - return 0; - } - - reply->dbg_status = 0; - reply->dbg_sid = sn->sn_id; - reply->dbg_timeout = sn->sn_timeout; - if (strlcpy(reply->dbg_name, &sn->sn_name[0], sizeof(reply->dbg_name)) - >= sizeof(reply->dbg_name)) - return -E2BIG; - - return 0; -} - -static void -sfw_test_rpc_fini(struct srpc_client_rpc *rpc) -{ - struct sfw_test_unit *tsu = rpc->crpc_priv; - struct sfw_test_instance *tsi = tsu->tsu_instance; - - /* Called with hold of tsi->tsi_lock */ - LASSERT(list_empty(&rpc->crpc_list)); - list_add(&rpc->crpc_list, &tsi->tsi_free_rpcs); -} - -static inline int -sfw_test_buffers(struct sfw_test_instance *tsi) -{ - struct sfw_test_case *tsc; - struct srpc_service *svc; - int nbuf; - - LASSERT(tsi); - tsc = sfw_find_test_case(tsi->tsi_service); - LASSERT(tsc); - svc = tsc->tsc_srv_service; - LASSERT(svc); - - nbuf = min(svc->sv_wi_total, tsi->tsi_loop) / svc->sv_ncpts; - return max(SFW_TEST_WI_MIN, nbuf + SFW_TEST_WI_EXTRA); -} - -static int -sfw_load_test(struct sfw_test_instance *tsi) -{ - struct sfw_test_case *tsc; - struct srpc_service *svc; - int nbuf; - int rc; - - LASSERT(tsi); - tsc = sfw_find_test_case(tsi->tsi_service); - nbuf = sfw_test_buffers(tsi); - LASSERT(tsc); - svc = tsc->tsc_srv_service; - - if (tsi->tsi_is_client) { - tsi->tsi_ops = tsc->tsc_cli_ops; - return 0; - } - - rc = srpc_service_add_buffers(svc, nbuf); - if (rc) { - CWARN("Failed to reserve enough buffers: service %s, %d needed: %d\n", - svc->sv_name, nbuf, rc); - /* - * NB: this error handler is not strictly correct, because - * it may release more buffers than already allocated, - * but it doesn't matter because request portal should - * be lazy portal and will grow buffers if necessary. - */ - srpc_service_remove_buffers(svc, nbuf); - return -ENOMEM; - } - - CDEBUG(D_NET, "Reserved %d buffers for test %s\n", - nbuf * (srpc_serv_is_framework(svc) ? - 2 : cfs_cpt_number(cfs_cpt_table)), svc->sv_name); - return 0; -} - -static void -sfw_unload_test(struct sfw_test_instance *tsi) -{ - struct sfw_test_case *tsc; - - LASSERT(tsi); - tsc = sfw_find_test_case(tsi->tsi_service); - LASSERT(tsc); - - if (tsi->tsi_is_client) - return; - - /* - * shrink buffers, because request portal is lazy portal - * which can grow buffers at runtime so we may leave - * some buffers behind, but never mind... - */ - srpc_service_remove_buffers(tsc->tsc_srv_service, - sfw_test_buffers(tsi)); -} - -static void -sfw_destroy_test_instance(struct sfw_test_instance *tsi) -{ - struct srpc_client_rpc *rpc; - struct sfw_test_unit *tsu; - - if (!tsi->tsi_is_client) - goto clean; - - tsi->tsi_ops->tso_fini(tsi); - - LASSERT(!tsi->tsi_stopping); - LASSERT(list_empty(&tsi->tsi_active_rpcs)); - LASSERT(!sfw_test_active(tsi)); - - while (!list_empty(&tsi->tsi_units)) { - tsu = list_entry(tsi->tsi_units.next, - struct sfw_test_unit, tsu_list); - list_del(&tsu->tsu_list); - kfree(tsu); - } - - while (!list_empty(&tsi->tsi_free_rpcs)) { - rpc = list_entry(tsi->tsi_free_rpcs.next, - struct srpc_client_rpc, crpc_list); - list_del(&rpc->crpc_list); - kfree(rpc); - } - -clean: - sfw_unload_test(tsi); - kfree(tsi); -} - -static void -sfw_destroy_batch(struct sfw_batch *tsb) -{ - struct sfw_test_instance *tsi; - - LASSERT(!sfw_batch_active(tsb)); - LASSERT(list_empty(&tsb->bat_list)); - - while (!list_empty(&tsb->bat_tests)) { - tsi = list_entry(tsb->bat_tests.next, - struct sfw_test_instance, tsi_list); - list_del_init(&tsi->tsi_list); - sfw_destroy_test_instance(tsi); - } - - kfree(tsb); -} - -void -sfw_destroy_session(struct sfw_session *sn) -{ - struct sfw_batch *batch; - - LASSERT(list_empty(&sn->sn_list)); - LASSERT(sn != sfw_data.fw_session); - - while (!list_empty(&sn->sn_batches)) { - batch = list_entry(sn->sn_batches.next, - struct sfw_batch, bat_list); - list_del_init(&batch->bat_list); - sfw_destroy_batch(batch); - } - - kfree(sn); - atomic_dec(&sfw_data.fw_nzombies); -} - -static void -sfw_unpack_addtest_req(struct srpc_msg *msg) -{ - struct srpc_test_reqst *req = &msg->msg_body.tes_reqst; - - LASSERT(msg->msg_type == SRPC_MSG_TEST_REQST); - LASSERT(req->tsr_is_client); - - if (msg->msg_magic == SRPC_MSG_MAGIC) - return; /* no flipping needed */ - - LASSERT(msg->msg_magic == __swab32(SRPC_MSG_MAGIC)); - - if (req->tsr_service == SRPC_SERVICE_BRW) { - if (!(msg->msg_ses_feats & LST_FEAT_BULK_LEN)) { - struct test_bulk_req *bulk = &req->tsr_u.bulk_v0; - - __swab32s(&bulk->blk_opc); - __swab32s(&bulk->blk_npg); - __swab32s(&bulk->blk_flags); - - } else { - struct test_bulk_req_v1 *bulk = &req->tsr_u.bulk_v1; - - __swab16s(&bulk->blk_opc); - __swab16s(&bulk->blk_flags); - __swab32s(&bulk->blk_offset); - __swab32s(&bulk->blk_len); - } - - return; - } - - if (req->tsr_service == SRPC_SERVICE_PING) { - struct test_ping_req *ping = &req->tsr_u.ping; - - __swab32s(&ping->png_size); - __swab32s(&ping->png_flags); - return; - } - - LBUG(); -} - -static int -sfw_add_test_instance(struct sfw_batch *tsb, struct srpc_server_rpc *rpc) -{ - struct srpc_msg *msg = &rpc->srpc_reqstbuf->buf_msg; - struct srpc_test_reqst *req = &msg->msg_body.tes_reqst; - struct srpc_bulk *bk = rpc->srpc_bulk; - int ndest = req->tsr_ndest; - struct sfw_test_unit *tsu; - struct sfw_test_instance *tsi; - int i; - int rc; - - tsi = kzalloc(sizeof(*tsi), GFP_NOFS); - if (!tsi) { - CERROR("Can't allocate test instance for batch: %llu\n", - tsb->bat_id.bat_id); - return -ENOMEM; - } - - spin_lock_init(&tsi->tsi_lock); - atomic_set(&tsi->tsi_nactive, 0); - INIT_LIST_HEAD(&tsi->tsi_units); - INIT_LIST_HEAD(&tsi->tsi_free_rpcs); - INIT_LIST_HEAD(&tsi->tsi_active_rpcs); - - tsi->tsi_stopping = 0; - tsi->tsi_batch = tsb; - tsi->tsi_loop = req->tsr_loop; - tsi->tsi_concur = req->tsr_concur; - tsi->tsi_service = req->tsr_service; - tsi->tsi_is_client = !!(req->tsr_is_client); - tsi->tsi_stoptsu_onerr = !!(req->tsr_stop_onerr); - - rc = sfw_load_test(tsi); - if (rc) { - kfree(tsi); - return rc; - } - - LASSERT(!sfw_batch_active(tsb)); - - if (!tsi->tsi_is_client) { - /* it's test server, just add it to tsb */ - list_add_tail(&tsi->tsi_list, &tsb->bat_tests); - return 0; - } - - LASSERT(bk); - LASSERT(bk->bk_niov * SFW_ID_PER_PAGE >= (unsigned int)ndest); - LASSERT((unsigned int)bk->bk_len >= - sizeof(struct lnet_process_id_packed) * ndest); - - sfw_unpack_addtest_req(msg); - memcpy(&tsi->tsi_u, &req->tsr_u, sizeof(tsi->tsi_u)); - - for (i = 0; i < ndest; i++) { - struct lnet_process_id_packed *dests; - struct lnet_process_id_packed id; - int j; - - dests = page_address(bk->bk_iovs[i / SFW_ID_PER_PAGE].bv_page); - LASSERT(dests); /* my pages are within KVM always */ - id = dests[i % SFW_ID_PER_PAGE]; - if (msg->msg_magic != SRPC_MSG_MAGIC) - sfw_unpack_id(id); - - for (j = 0; j < tsi->tsi_concur; j++) { - tsu = kzalloc(sizeof(struct sfw_test_unit), GFP_NOFS); - if (!tsu) { - rc = -ENOMEM; - CERROR("Can't allocate tsu for %d\n", - tsi->tsi_service); - goto error; - } - - tsu->tsu_dest.nid = id.nid; - tsu->tsu_dest.pid = id.pid; - tsu->tsu_instance = tsi; - tsu->tsu_private = NULL; - list_add_tail(&tsu->tsu_list, &tsi->tsi_units); - } - } - - rc = tsi->tsi_ops->tso_init(tsi); - if (!rc) { - list_add_tail(&tsi->tsi_list, &tsb->bat_tests); - return 0; - } - -error: - LASSERT(rc); - sfw_destroy_test_instance(tsi); - return rc; -} - -static void -sfw_test_unit_done(struct sfw_test_unit *tsu) -{ - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct sfw_batch *tsb = tsi->tsi_batch; - struct sfw_session *sn = tsb->bat_session; - - LASSERT(sfw_test_active(tsi)); - - if (!atomic_dec_and_test(&tsi->tsi_nactive)) - return; - - /* the test instance is done */ - spin_lock(&tsi->tsi_lock); - - tsi->tsi_stopping = 0; - - spin_unlock(&tsi->tsi_lock); - - spin_lock(&sfw_data.fw_lock); - - if (!atomic_dec_and_test(&tsb->bat_nactive) || /* tsb still active */ - sn == sfw_data.fw_session) { /* sn also active */ - spin_unlock(&sfw_data.fw_lock); - return; - } - - LASSERT(!list_empty(&sn->sn_list)); /* I'm a zombie! */ - - list_for_each_entry(tsb, &sn->sn_batches, bat_list) { - if (sfw_batch_active(tsb)) { - spin_unlock(&sfw_data.fw_lock); - return; - } - } - - list_del_init(&sn->sn_list); - spin_unlock(&sfw_data.fw_lock); - - sfw_destroy_session(sn); -} - -static void -sfw_test_rpc_done(struct srpc_client_rpc *rpc) -{ - struct sfw_test_unit *tsu = rpc->crpc_priv; - struct sfw_test_instance *tsi = tsu->tsu_instance; - int done = 0; - - tsi->tsi_ops->tso_done_rpc(tsu, rpc); - - spin_lock(&tsi->tsi_lock); - - LASSERT(sfw_test_active(tsi)); - LASSERT(!list_empty(&rpc->crpc_list)); - - list_del_init(&rpc->crpc_list); - - /* batch is stopping or loop is done or get error */ - if (tsi->tsi_stopping || !tsu->tsu_loop || - (rpc->crpc_status && tsi->tsi_stoptsu_onerr)) - done = 1; - - /* dec ref for poster */ - srpc_client_rpc_decref(rpc); - - spin_unlock(&tsi->tsi_lock); - - if (!done) { - swi_schedule_workitem(&tsu->tsu_worker); - return; - } - - sfw_test_unit_done(tsu); -} - -int -sfw_create_test_rpc(struct sfw_test_unit *tsu, struct lnet_process_id peer, - unsigned int features, int nblk, int blklen, - struct srpc_client_rpc **rpcpp) -{ - struct srpc_client_rpc *rpc = NULL; - struct sfw_test_instance *tsi = tsu->tsu_instance; - - spin_lock(&tsi->tsi_lock); - - LASSERT(sfw_test_active(tsi)); - /* pick request from buffer */ - rpc = list_first_entry_or_null(&tsi->tsi_free_rpcs, - struct srpc_client_rpc, crpc_list); - if (rpc) { - LASSERT(nblk == rpc->crpc_bulk.bk_niov); - list_del_init(&rpc->crpc_list); - } - - spin_unlock(&tsi->tsi_lock); - - if (!rpc) { - rpc = srpc_create_client_rpc(peer, tsi->tsi_service, nblk, - blklen, sfw_test_rpc_done, - sfw_test_rpc_fini, tsu); - } else { - srpc_init_client_rpc(rpc, peer, tsi->tsi_service, nblk, - blklen, sfw_test_rpc_done, - sfw_test_rpc_fini, tsu); - } - - if (!rpc) { - CERROR("Can't create rpc for test %d\n", tsi->tsi_service); - return -ENOMEM; - } - - rpc->crpc_reqstmsg.msg_ses_feats = features; - *rpcpp = rpc; - - return 0; -} - -static void -sfw_run_test(struct swi_workitem *wi) -{ - struct sfw_test_unit *tsu = container_of(wi, struct sfw_test_unit, tsu_worker); - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct srpc_client_rpc *rpc = NULL; - - if (tsi->tsi_ops->tso_prep_rpc(tsu, tsu->tsu_dest, &rpc)) { - LASSERT(!rpc); - goto test_done; - } - - LASSERT(rpc); - - spin_lock(&tsi->tsi_lock); - - if (tsi->tsi_stopping) { - list_add(&rpc->crpc_list, &tsi->tsi_free_rpcs); - spin_unlock(&tsi->tsi_lock); - goto test_done; - } - - if (tsu->tsu_loop > 0) - tsu->tsu_loop--; - - list_add_tail(&rpc->crpc_list, &tsi->tsi_active_rpcs); - spin_unlock(&tsi->tsi_lock); - - spin_lock(&rpc->crpc_lock); - rpc->crpc_timeout = rpc_timeout; - srpc_post_rpc(rpc); - spin_unlock(&rpc->crpc_lock); - return; - -test_done: - /* - * No one can schedule me now since: - * - previous RPC, if any, has done and - * - no new RPC is initiated. - * - my batch is still active; no one can run it again now. - * Cancel pending schedules and prevent future schedule attempts: - */ - sfw_test_unit_done(tsu); -} - -static int -sfw_run_batch(struct sfw_batch *tsb) -{ - struct swi_workitem *wi; - struct sfw_test_unit *tsu; - struct sfw_test_instance *tsi; - - if (sfw_batch_active(tsb)) { - CDEBUG(D_NET, "Batch already active: %llu (%d)\n", - tsb->bat_id.bat_id, atomic_read(&tsb->bat_nactive)); - return 0; - } - - list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { - if (!tsi->tsi_is_client) /* skip server instances */ - continue; - - LASSERT(!tsi->tsi_stopping); - LASSERT(!sfw_test_active(tsi)); - - atomic_inc(&tsb->bat_nactive); - - list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) { - atomic_inc(&tsi->tsi_nactive); - tsu->tsu_loop = tsi->tsi_loop; - wi = &tsu->tsu_worker; - swi_init_workitem(wi, sfw_run_test, - lst_test_wq[lnet_cpt_of_nid(tsu->tsu_dest.nid)]); - swi_schedule_workitem(wi); - } - } - - return 0; -} - -int -sfw_stop_batch(struct sfw_batch *tsb, int force) -{ - struct sfw_test_instance *tsi; - struct srpc_client_rpc *rpc; - - if (!sfw_batch_active(tsb)) { - CDEBUG(D_NET, "Batch %llu inactive\n", tsb->bat_id.bat_id); - return 0; - } - - list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { - spin_lock(&tsi->tsi_lock); - - if (!tsi->tsi_is_client || - !sfw_test_active(tsi) || tsi->tsi_stopping) { - spin_unlock(&tsi->tsi_lock); - continue; - } - - tsi->tsi_stopping = 1; - - if (!force) { - spin_unlock(&tsi->tsi_lock); - continue; - } - - /* abort launched rpcs in the test */ - list_for_each_entry(rpc, &tsi->tsi_active_rpcs, crpc_list) { - spin_lock(&rpc->crpc_lock); - - srpc_abort_rpc(rpc, -EINTR); - - spin_unlock(&rpc->crpc_lock); - } - - spin_unlock(&tsi->tsi_lock); - } - - return 0; -} - -static int -sfw_query_batch(struct sfw_batch *tsb, int testidx, - struct srpc_batch_reply *reply) -{ - struct sfw_test_instance *tsi; - - if (testidx < 0) - return -EINVAL; - - if (!testidx) { - reply->bar_active = atomic_read(&tsb->bat_nactive); - return 0; - } - - list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { - if (testidx-- > 1) - continue; - - reply->bar_active = atomic_read(&tsi->tsi_nactive); - return 0; - } - - return -ENOENT; -} - -void -sfw_free_pages(struct srpc_server_rpc *rpc) -{ - srpc_free_bulk(rpc->srpc_bulk); - rpc->srpc_bulk = NULL; -} - -int -sfw_alloc_pages(struct srpc_server_rpc *rpc, int cpt, int npages, int len, - int sink) -{ - LASSERT(!rpc->srpc_bulk); - LASSERT(npages > 0 && npages <= LNET_MAX_IOV); - - rpc->srpc_bulk = srpc_alloc_bulk(cpt, 0, npages, len, sink); - if (!rpc->srpc_bulk) - return -ENOMEM; - - return 0; -} - -static int -sfw_add_test(struct srpc_server_rpc *rpc) -{ - struct sfw_session *sn = sfw_data.fw_session; - struct srpc_test_reply *reply = &rpc->srpc_replymsg.msg_body.tes_reply; - struct srpc_test_reqst *request; - int rc; - struct sfw_batch *bat; - - request = &rpc->srpc_reqstbuf->buf_msg.msg_body.tes_reqst; - reply->tsr_sid = !sn ? LST_INVALID_SID : sn->sn_id; - - if (!request->tsr_loop || - !request->tsr_concur || - request->tsr_sid.ses_nid == LNET_NID_ANY || - request->tsr_ndest > SFW_MAX_NDESTS || - (request->tsr_is_client && !request->tsr_ndest) || - request->tsr_concur > SFW_MAX_CONCUR || - request->tsr_service > SRPC_SERVICE_MAX_ID || - request->tsr_service <= SRPC_FRAMEWORK_SERVICE_MAX_ID) { - reply->tsr_status = EINVAL; - return 0; - } - - if (!sn || !sfw_sid_equal(request->tsr_sid, sn->sn_id) || - !sfw_find_test_case(request->tsr_service)) { - reply->tsr_status = ENOENT; - return 0; - } - - bat = sfw_bid2batch(request->tsr_bid); - if (!bat) { - CERROR("dropping RPC %s from %s under memory pressure\n", - rpc->srpc_scd->scd_svc->sv_name, - libcfs_id2str(rpc->srpc_peer)); - return -ENOMEM; - } - - if (sfw_batch_active(bat)) { - reply->tsr_status = EBUSY; - return 0; - } - - if (request->tsr_is_client && !rpc->srpc_bulk) { - /* rpc will be resumed later in sfw_bulk_ready */ - int npg = sfw_id_pages(request->tsr_ndest); - int len; - - if (!(sn->sn_features & LST_FEAT_BULK_LEN)) { - len = npg * PAGE_SIZE; - - } else { - len = sizeof(struct lnet_process_id_packed) * - request->tsr_ndest; - } - - return sfw_alloc_pages(rpc, CFS_CPT_ANY, npg, len, 1); - } - - rc = sfw_add_test_instance(bat, rpc); - CDEBUG(!rc ? D_NET : D_WARNING, - "%s test: sv %d %s, loop %d, concur %d, ndest %d\n", - !rc ? "Added" : "Failed to add", request->tsr_service, - request->tsr_is_client ? "client" : "server", - request->tsr_loop, request->tsr_concur, request->tsr_ndest); - - reply->tsr_status = (rc < 0) ? -rc : rc; - return 0; -} - -static int -sfw_control_batch(struct srpc_batch_reqst *request, - struct srpc_batch_reply *reply) -{ - struct sfw_session *sn = sfw_data.fw_session; - int rc = 0; - struct sfw_batch *bat; - - reply->bar_sid = !sn ? LST_INVALID_SID : sn->sn_id; - - if (!sn || !sfw_sid_equal(request->bar_sid, sn->sn_id)) { - reply->bar_status = ESRCH; - return 0; - } - - bat = sfw_find_batch(request->bar_bid); - if (!bat) { - reply->bar_status = ENOENT; - return 0; - } - - switch (request->bar_opc) { - case SRPC_BATCH_OPC_RUN: - rc = sfw_run_batch(bat); - break; - - case SRPC_BATCH_OPC_STOP: - rc = sfw_stop_batch(bat, request->bar_arg); - break; - - case SRPC_BATCH_OPC_QUERY: - rc = sfw_query_batch(bat, request->bar_testidx, reply); - break; - - default: - return -EINVAL; /* drop it */ - } - - reply->bar_status = (rc < 0) ? -rc : rc; - return 0; -} - -static int -sfw_handle_server_rpc(struct srpc_server_rpc *rpc) -{ - struct srpc_service *sv = rpc->srpc_scd->scd_svc; - struct srpc_msg *reply = &rpc->srpc_replymsg; - struct srpc_msg *request = &rpc->srpc_reqstbuf->buf_msg; - unsigned int features = LST_FEATS_MASK; - int rc = 0; - - LASSERT(!sfw_data.fw_active_srpc); - LASSERT(sv->sv_id <= SRPC_FRAMEWORK_SERVICE_MAX_ID); - - spin_lock(&sfw_data.fw_lock); - - if (sfw_data.fw_shuttingdown) { - spin_unlock(&sfw_data.fw_lock); - return -ESHUTDOWN; - } - - /* Remove timer to avoid racing with it or expiring active session */ - if (sfw_del_session_timer()) { - CERROR("dropping RPC %s from %s: racing with expiry timer\n", - sv->sv_name, libcfs_id2str(rpc->srpc_peer)); - spin_unlock(&sfw_data.fw_lock); - return -EAGAIN; - } - - sfw_data.fw_active_srpc = rpc; - spin_unlock(&sfw_data.fw_lock); - - sfw_unpack_message(request); - LASSERT(request->msg_type == srpc_service2request(sv->sv_id)); - - /* rpc module should have checked this */ - LASSERT(request->msg_version == SRPC_MSG_VERSION); - - if (sv->sv_id != SRPC_SERVICE_MAKE_SESSION && - sv->sv_id != SRPC_SERVICE_DEBUG) { - struct sfw_session *sn = sfw_data.fw_session; - - if (sn && - sn->sn_features != request->msg_ses_feats) { - CNETERR("Features of framework RPC don't match features of current session: %x/%x\n", - request->msg_ses_feats, sn->sn_features); - reply->msg_body.reply.status = EPROTO; - reply->msg_body.reply.sid = sn->sn_id; - goto out; - } - - } else if (request->msg_ses_feats & ~LST_FEATS_MASK) { - /* - * NB: at this point, old version will ignore features and - * create new session anyway, so console should be able - * to handle this - */ - reply->msg_body.reply.status = EPROTO; - goto out; - } - - switch (sv->sv_id) { - default: - LBUG(); - case SRPC_SERVICE_TEST: - rc = sfw_add_test(rpc); - break; - - case SRPC_SERVICE_BATCH: - rc = sfw_control_batch(&request->msg_body.bat_reqst, - &reply->msg_body.bat_reply); - break; - - case SRPC_SERVICE_QUERY_STAT: - rc = sfw_get_stats(&request->msg_body.stat_reqst, - &reply->msg_body.stat_reply); - break; - - case SRPC_SERVICE_DEBUG: - rc = sfw_debug_session(&request->msg_body.dbg_reqst, - &reply->msg_body.dbg_reply); - break; - - case SRPC_SERVICE_MAKE_SESSION: - rc = sfw_make_session(&request->msg_body.mksn_reqst, - &reply->msg_body.mksn_reply); - break; - - case SRPC_SERVICE_REMOVE_SESSION: - rc = sfw_remove_session(&request->msg_body.rmsn_reqst, - &reply->msg_body.rmsn_reply); - break; - } - - if (sfw_data.fw_session) - features = sfw_data.fw_session->sn_features; - out: - reply->msg_ses_feats = features; - rpc->srpc_done = sfw_server_rpc_done; - spin_lock(&sfw_data.fw_lock); - - if (!sfw_data.fw_shuttingdown) - sfw_add_session_timer(); - - sfw_data.fw_active_srpc = NULL; - spin_unlock(&sfw_data.fw_lock); - return rc; -} - -static int -sfw_bulk_ready(struct srpc_server_rpc *rpc, int status) -{ - struct srpc_service *sv = rpc->srpc_scd->scd_svc; - int rc; - - LASSERT(rpc->srpc_bulk); - LASSERT(sv->sv_id == SRPC_SERVICE_TEST); - LASSERT(!sfw_data.fw_active_srpc); - LASSERT(rpc->srpc_reqstbuf->buf_msg.msg_body.tes_reqst.tsr_is_client); - - spin_lock(&sfw_data.fw_lock); - - if (status) { - CERROR("Bulk transfer failed for RPC: service %s, peer %s, status %d\n", - sv->sv_name, libcfs_id2str(rpc->srpc_peer), status); - spin_unlock(&sfw_data.fw_lock); - return -EIO; - } - - if (sfw_data.fw_shuttingdown) { - spin_unlock(&sfw_data.fw_lock); - return -ESHUTDOWN; - } - - if (sfw_del_session_timer()) { - CERROR("dropping RPC %s from %s: racing with expiry timer\n", - sv->sv_name, libcfs_id2str(rpc->srpc_peer)); - spin_unlock(&sfw_data.fw_lock); - return -EAGAIN; - } - - sfw_data.fw_active_srpc = rpc; - spin_unlock(&sfw_data.fw_lock); - - rc = sfw_add_test(rpc); - - spin_lock(&sfw_data.fw_lock); - - if (!sfw_data.fw_shuttingdown) - sfw_add_session_timer(); - - sfw_data.fw_active_srpc = NULL; - spin_unlock(&sfw_data.fw_lock); - return rc; -} - -struct srpc_client_rpc * -sfw_create_rpc(struct lnet_process_id peer, int service, - unsigned int features, int nbulkiov, int bulklen, - void (*done)(struct srpc_client_rpc *), void *priv) -{ - struct srpc_client_rpc *rpc = NULL; - - spin_lock(&sfw_data.fw_lock); - - LASSERT(!sfw_data.fw_shuttingdown); - LASSERT(service <= SRPC_FRAMEWORK_SERVICE_MAX_ID); - - if (!nbulkiov && !list_empty(&sfw_data.fw_zombie_rpcs)) { - rpc = list_entry(sfw_data.fw_zombie_rpcs.next, - struct srpc_client_rpc, crpc_list); - list_del(&rpc->crpc_list); - - srpc_init_client_rpc(rpc, peer, service, 0, 0, - done, sfw_client_rpc_fini, priv); - } - - spin_unlock(&sfw_data.fw_lock); - - if (!rpc) { - rpc = srpc_create_client_rpc(peer, service, - nbulkiov, bulklen, done, - nbulkiov ? NULL : - sfw_client_rpc_fini, - priv); - } - - if (rpc) /* "session" is concept in framework */ - rpc->crpc_reqstmsg.msg_ses_feats = features; - - return rpc; -} - -void -sfw_unpack_message(struct srpc_msg *msg) -{ - if (msg->msg_magic == SRPC_MSG_MAGIC) - return; /* no flipping needed */ - - /* srpc module should guarantee I wouldn't get crap */ - LASSERT(msg->msg_magic == __swab32(SRPC_MSG_MAGIC)); - - if (msg->msg_type == SRPC_MSG_STAT_REQST) { - struct srpc_stat_reqst *req = &msg->msg_body.stat_reqst; - - __swab32s(&req->str_type); - __swab64s(&req->str_rpyid); - sfw_unpack_sid(req->str_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_STAT_REPLY) { - struct srpc_stat_reply *rep = &msg->msg_body.stat_reply; - - __swab32s(&rep->str_status); - sfw_unpack_sid(rep->str_sid); - sfw_unpack_fw_counters(rep->str_fw); - sfw_unpack_rpc_counters(rep->str_rpc); - sfw_unpack_lnet_counters(rep->str_lnet); - return; - } - - if (msg->msg_type == SRPC_MSG_MKSN_REQST) { - struct srpc_mksn_reqst *req = &msg->msg_body.mksn_reqst; - - __swab64s(&req->mksn_rpyid); - __swab32s(&req->mksn_force); - sfw_unpack_sid(req->mksn_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_MKSN_REPLY) { - struct srpc_mksn_reply *rep = &msg->msg_body.mksn_reply; - - __swab32s(&rep->mksn_status); - __swab32s(&rep->mksn_timeout); - sfw_unpack_sid(rep->mksn_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_RMSN_REQST) { - struct srpc_rmsn_reqst *req = &msg->msg_body.rmsn_reqst; - - __swab64s(&req->rmsn_rpyid); - sfw_unpack_sid(req->rmsn_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_RMSN_REPLY) { - struct srpc_rmsn_reply *rep = &msg->msg_body.rmsn_reply; - - __swab32s(&rep->rmsn_status); - sfw_unpack_sid(rep->rmsn_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_DEBUG_REQST) { - struct srpc_debug_reqst *req = &msg->msg_body.dbg_reqst; - - __swab64s(&req->dbg_rpyid); - __swab32s(&req->dbg_flags); - sfw_unpack_sid(req->dbg_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_DEBUG_REPLY) { - struct srpc_debug_reply *rep = &msg->msg_body.dbg_reply; - - __swab32s(&rep->dbg_nbatch); - __swab32s(&rep->dbg_timeout); - sfw_unpack_sid(rep->dbg_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_BATCH_REQST) { - struct srpc_batch_reqst *req = &msg->msg_body.bat_reqst; - - __swab32s(&req->bar_opc); - __swab64s(&req->bar_rpyid); - __swab32s(&req->bar_testidx); - __swab32s(&req->bar_arg); - sfw_unpack_sid(req->bar_sid); - __swab64s(&req->bar_bid.bat_id); - return; - } - - if (msg->msg_type == SRPC_MSG_BATCH_REPLY) { - struct srpc_batch_reply *rep = &msg->msg_body.bat_reply; - - __swab32s(&rep->bar_status); - sfw_unpack_sid(rep->bar_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_TEST_REQST) { - struct srpc_test_reqst *req = &msg->msg_body.tes_reqst; - - __swab64s(&req->tsr_rpyid); - __swab64s(&req->tsr_bulkid); - __swab32s(&req->tsr_loop); - __swab32s(&req->tsr_ndest); - __swab32s(&req->tsr_concur); - __swab32s(&req->tsr_service); - sfw_unpack_sid(req->tsr_sid); - __swab64s(&req->tsr_bid.bat_id); - return; - } - - if (msg->msg_type == SRPC_MSG_TEST_REPLY) { - struct srpc_test_reply *rep = &msg->msg_body.tes_reply; - - __swab32s(&rep->tsr_status); - sfw_unpack_sid(rep->tsr_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_JOIN_REQST) { - struct srpc_join_reqst *req = &msg->msg_body.join_reqst; - - __swab64s(&req->join_rpyid); - sfw_unpack_sid(req->join_sid); - return; - } - - if (msg->msg_type == SRPC_MSG_JOIN_REPLY) { - struct srpc_join_reply *rep = &msg->msg_body.join_reply; - - __swab32s(&rep->join_status); - __swab32s(&rep->join_timeout); - sfw_unpack_sid(rep->join_sid); - return; - } - - LBUG(); -} - -void -sfw_abort_rpc(struct srpc_client_rpc *rpc) -{ - LASSERT(atomic_read(&rpc->crpc_refcount) > 0); - LASSERT(rpc->crpc_service <= SRPC_FRAMEWORK_SERVICE_MAX_ID); - - spin_lock(&rpc->crpc_lock); - srpc_abort_rpc(rpc, -EINTR); - spin_unlock(&rpc->crpc_lock); -} - -void -sfw_post_rpc(struct srpc_client_rpc *rpc) -{ - spin_lock(&rpc->crpc_lock); - - LASSERT(!rpc->crpc_closed); - LASSERT(!rpc->crpc_aborted); - LASSERT(list_empty(&rpc->crpc_list)); - LASSERT(!sfw_data.fw_shuttingdown); - - rpc->crpc_timeout = rpc_timeout; - srpc_post_rpc(rpc); - - spin_unlock(&rpc->crpc_lock); -} - -static struct srpc_service sfw_services[] = { - { - /* sv_id */ SRPC_SERVICE_DEBUG, - /* sv_name */ "debug", - 0 - }, - { - /* sv_id */ SRPC_SERVICE_QUERY_STAT, - /* sv_name */ "query stats", - 0 - }, - { - /* sv_id */ SRPC_SERVICE_MAKE_SESSION, - /* sv_name */ "make session", - 0 - }, - { - /* sv_id */ SRPC_SERVICE_REMOVE_SESSION, - /* sv_name */ "remove session", - 0 - }, - { - /* sv_id */ SRPC_SERVICE_BATCH, - /* sv_name */ "batch service", - 0 - }, - { - /* sv_id */ SRPC_SERVICE_TEST, - /* sv_name */ "test service", - 0 - }, - { - /* sv_id */ 0, - /* sv_name */ NULL, - 0 - } -}; - -int -sfw_startup(void) -{ - int i; - int rc; - int error; - struct srpc_service *sv; - struct sfw_test_case *tsc; - - if (session_timeout < 0) { - CERROR("Session timeout must be non-negative: %d\n", - session_timeout); - return -EINVAL; - } - - if (rpc_timeout < 0) { - CERROR("RPC timeout must be non-negative: %d\n", - rpc_timeout); - return -EINVAL; - } - - if (!session_timeout) - CWARN("Zero session_timeout specified - test sessions never expire.\n"); - - if (!rpc_timeout) - CWARN("Zero rpc_timeout specified - test RPC never expire.\n"); - - memset(&sfw_data, 0, sizeof(struct smoketest_framework)); - - sfw_data.fw_session = NULL; - sfw_data.fw_active_srpc = NULL; - spin_lock_init(&sfw_data.fw_lock); - atomic_set(&sfw_data.fw_nzombies, 0); - INIT_LIST_HEAD(&sfw_data.fw_tests); - INIT_LIST_HEAD(&sfw_data.fw_zombie_rpcs); - INIT_LIST_HEAD(&sfw_data.fw_zombie_sessions); - - brw_init_test_client(); - brw_init_test_service(); - rc = sfw_register_test(&brw_test_service, &brw_test_client); - LASSERT(!rc); - - ping_init_test_client(); - ping_init_test_service(); - rc = sfw_register_test(&ping_test_service, &ping_test_client); - LASSERT(!rc); - - error = 0; - list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { - sv = tsc->tsc_srv_service; - - rc = srpc_add_service(sv); - LASSERT(rc != -EBUSY); - if (rc) { - CWARN("Failed to add %s service: %d\n", - sv->sv_name, rc); - error = rc; - } - } - - for (i = 0; ; i++) { - sv = &sfw_services[i]; - if (!sv->sv_name) - break; - - sv->sv_bulk_ready = NULL; - sv->sv_handler = sfw_handle_server_rpc; - sv->sv_wi_total = SFW_FRWK_WI_MAX; - if (sv->sv_id == SRPC_SERVICE_TEST) - sv->sv_bulk_ready = sfw_bulk_ready; - - rc = srpc_add_service(sv); - LASSERT(rc != -EBUSY); - if (rc) { - CWARN("Failed to add %s service: %d\n", - sv->sv_name, rc); - error = rc; - } - - /* about to sfw_shutdown, no need to add buffer */ - if (error) - continue; - - rc = srpc_service_add_buffers(sv, sv->sv_wi_total); - if (rc) { - CWARN("Failed to reserve enough buffers: service %s, %d needed: %d\n", - sv->sv_name, sv->sv_wi_total, rc); - error = -ENOMEM; - } - } - - if (error) - sfw_shutdown(); - return error; -} - -void -sfw_shutdown(void) -{ - struct srpc_service *sv; - struct sfw_test_case *tsc; - int i; - - spin_lock(&sfw_data.fw_lock); - - sfw_data.fw_shuttingdown = 1; - lst_wait_until(!sfw_data.fw_active_srpc, sfw_data.fw_lock, - "waiting for active RPC to finish.\n"); - - if (sfw_del_session_timer()) - lst_wait_until(!sfw_data.fw_session, sfw_data.fw_lock, - "waiting for session timer to explode.\n"); - - sfw_deactivate_session(); - lst_wait_until(!atomic_read(&sfw_data.fw_nzombies), - sfw_data.fw_lock, - "waiting for %d zombie sessions to die.\n", - atomic_read(&sfw_data.fw_nzombies)); - - spin_unlock(&sfw_data.fw_lock); - - for (i = 0; ; i++) { - sv = &sfw_services[i]; - if (!sv->sv_name) - break; - - srpc_shutdown_service(sv); - srpc_remove_service(sv); - } - - list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { - sv = tsc->tsc_srv_service; - srpc_shutdown_service(sv); - srpc_remove_service(sv); - } - - while (!list_empty(&sfw_data.fw_zombie_rpcs)) { - struct srpc_client_rpc *rpc; - - rpc = list_entry(sfw_data.fw_zombie_rpcs.next, - struct srpc_client_rpc, crpc_list); - list_del(&rpc->crpc_list); - - kfree(rpc); - } - - for (i = 0; ; i++) { - sv = &sfw_services[i]; - if (!sv->sv_name) - break; - - srpc_wait_service_shutdown(sv); - } - - while (!list_empty(&sfw_data.fw_tests)) { - tsc = list_entry(sfw_data.fw_tests.next, - struct sfw_test_case, tsc_list); - - srpc_wait_service_shutdown(tsc->tsc_srv_service); - - list_del(&tsc->tsc_list); - kfree(tsc); - } -} diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c deleted file mode 100644 index 7359aa56d9b3..000000000000 --- a/drivers/staging/lustre/lnet/selftest/module.c +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#define DEBUG_SUBSYSTEM S_LNET - -#include "selftest.h" -#include "console.h" - -enum { - LST_INIT_NONE = 0, - LST_INIT_WI_SERIAL, - LST_INIT_WI_TEST, - LST_INIT_RPC, - LST_INIT_FW, - LST_INIT_CONSOLE -}; - -static int lst_init_step = LST_INIT_NONE; - -struct workqueue_struct *lst_serial_wq; -struct workqueue_struct **lst_test_wq; - -static void -lnet_selftest_exit(void) -{ - int i; - - switch (lst_init_step) { - case LST_INIT_CONSOLE: - lstcon_console_fini(); - /* fall through */ - case LST_INIT_FW: - sfw_shutdown(); - /* fall through */ - case LST_INIT_RPC: - srpc_shutdown(); - /* fall through */ - case LST_INIT_WI_TEST: - for (i = 0; - i < cfs_cpt_number(lnet_cpt_table()); i++) { - if (!lst_test_wq[i]) - continue; - destroy_workqueue(lst_test_wq[i]); - } - kvfree(lst_test_wq); - lst_test_wq = NULL; - /* fall through */ - case LST_INIT_WI_SERIAL: - destroy_workqueue(lst_serial_wq); - lst_serial_wq = NULL; - case LST_INIT_NONE: - break; - default: - LBUG(); - } -} - -static int -lnet_selftest_init(void) -{ - int nscheds; - int rc = -ENOMEM; - int i; - - lst_serial_wq = alloc_ordered_workqueue("lst_s", 0); - if (!lst_serial_wq) { - CERROR("Failed to create serial WI scheduler for LST\n"); - return -ENOMEM; - } - lst_init_step = LST_INIT_WI_SERIAL; - - nscheds = cfs_cpt_number(lnet_cpt_table()); - lst_test_wq = kvmalloc_array(nscheds, sizeof(lst_test_wq[0]), - GFP_KERNEL | __GFP_ZERO); - if (!lst_test_wq) { - rc = -ENOMEM; - goto error; - } - - lst_init_step = LST_INIT_WI_TEST; - for (i = 0; i < nscheds; i++) { - int nthrs = cfs_cpt_weight(lnet_cpt_table(), i); - struct workqueue_attrs attrs = {0}; - cpumask_var_t *mask = cfs_cpt_cpumask(lnet_cpt_table(), i); - - /* reserve at least one CPU for LND */ - nthrs = max(nthrs - 1, 1); - lst_test_wq[i] = alloc_workqueue("lst_t", WQ_UNBOUND, nthrs); - if (!lst_test_wq[i]) { - CWARN("Failed to create CPU partition affinity WI scheduler %d for LST\n", - i); - rc = -ENOMEM; - goto error; - } - - if (mask && alloc_cpumask_var(&attrs.cpumask, GFP_KERNEL)) { - cpumask_copy(attrs.cpumask, *mask); - apply_workqueue_attrs(lst_test_wq[i], &attrs); - free_cpumask_var(attrs.cpumask); - } - } - - rc = srpc_startup(); - if (rc) { - CERROR("LST can't startup rpc\n"); - goto error; - } - lst_init_step = LST_INIT_RPC; - - rc = sfw_startup(); - if (rc) { - CERROR("LST can't startup framework\n"); - goto error; - } - lst_init_step = LST_INIT_FW; - - rc = lstcon_console_init(); - if (rc) { - CERROR("LST can't startup console\n"); - goto error; - } - lst_init_step = LST_INIT_CONSOLE; - return 0; -error: - lnet_selftest_exit(); - return rc; -} - -MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>"); -MODULE_DESCRIPTION("LNet Selftest"); -MODULE_VERSION("2.7.0"); -MODULE_LICENSE("GPL"); - -module_init(lnet_selftest_init); -module_exit(lnet_selftest_exit); diff --git a/drivers/staging/lustre/lnet/selftest/ping_test.c b/drivers/staging/lustre/lnet/selftest/ping_test.c deleted file mode 100644 index f54bd630dbf8..000000000000 --- a/drivers/staging/lustre/lnet/selftest/ping_test.c +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/conctl.c - * - * Test client & Server - * - * Author: Liang Zhen <liangzhen@clusterfs.com> - */ - -#include "selftest.h" - -#define LST_PING_TEST_MAGIC 0xbabeface - -static int ping_srv_workitems = SFW_TEST_WI_MAX; -module_param(ping_srv_workitems, int, 0644); -MODULE_PARM_DESC(ping_srv_workitems, "# PING server workitems"); - -struct lst_ping_data { - spinlock_t pnd_lock; /* serialize */ - int pnd_counter; /* sequence counter */ -}; - -static struct lst_ping_data lst_ping_data; - -static int -ping_client_init(struct sfw_test_instance *tsi) -{ - struct sfw_session *sn = tsi->tsi_batch->bat_session; - - LASSERT(tsi->tsi_is_client); - LASSERT(sn && !(sn->sn_features & ~LST_FEATS_MASK)); - - spin_lock_init(&lst_ping_data.pnd_lock); - lst_ping_data.pnd_counter = 0; - - return 0; -} - -static void -ping_client_fini(struct sfw_test_instance *tsi) -{ - struct sfw_session *sn = tsi->tsi_batch->bat_session; - int errors; - - LASSERT(sn); - LASSERT(tsi->tsi_is_client); - - errors = atomic_read(&sn->sn_ping_errors); - if (errors) - CWARN("%d pings have failed.\n", errors); - else - CDEBUG(D_NET, "Ping test finished OK.\n"); -} - -static int -ping_client_prep_rpc(struct sfw_test_unit *tsu, struct lnet_process_id dest, - struct srpc_client_rpc **rpc) -{ - struct srpc_ping_reqst *req; - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct sfw_session *sn = tsi->tsi_batch->bat_session; - struct timespec64 ts; - int rc; - - LASSERT(sn); - LASSERT(!(sn->sn_features & ~LST_FEATS_MASK)); - - rc = sfw_create_test_rpc(tsu, dest, sn->sn_features, 0, 0, rpc); - if (rc) - return rc; - - req = &(*rpc)->crpc_reqstmsg.msg_body.ping_reqst; - - req->pnr_magic = LST_PING_TEST_MAGIC; - - spin_lock(&lst_ping_data.pnd_lock); - req->pnr_seq = lst_ping_data.pnd_counter++; - spin_unlock(&lst_ping_data.pnd_lock); - - ktime_get_real_ts64(&ts); - req->pnr_time_sec = ts.tv_sec; - req->pnr_time_usec = ts.tv_nsec / NSEC_PER_USEC; - - return rc; -} - -static void -ping_client_done_rpc(struct sfw_test_unit *tsu, struct srpc_client_rpc *rpc) -{ - struct sfw_test_instance *tsi = tsu->tsu_instance; - struct sfw_session *sn = tsi->tsi_batch->bat_session; - struct srpc_ping_reqst *reqst = &rpc->crpc_reqstmsg.msg_body.ping_reqst; - struct srpc_ping_reply *reply = &rpc->crpc_replymsg.msg_body.ping_reply; - struct timespec64 ts; - - LASSERT(sn); - - if (rpc->crpc_status) { - if (!tsi->tsi_stopping) /* rpc could have been aborted */ - atomic_inc(&sn->sn_ping_errors); - CERROR("Unable to ping %s (%d): %d\n", - libcfs_id2str(rpc->crpc_dest), - reqst->pnr_seq, rpc->crpc_status); - return; - } - - if (rpc->crpc_replymsg.msg_magic != SRPC_MSG_MAGIC) { - __swab32s(&reply->pnr_seq); - __swab32s(&reply->pnr_magic); - __swab32s(&reply->pnr_status); - } - - if (reply->pnr_magic != LST_PING_TEST_MAGIC) { - rpc->crpc_status = -EBADMSG; - atomic_inc(&sn->sn_ping_errors); - CERROR("Bad magic %u from %s, %u expected.\n", - reply->pnr_magic, libcfs_id2str(rpc->crpc_dest), - LST_PING_TEST_MAGIC); - return; - } - - if (reply->pnr_seq != reqst->pnr_seq) { - rpc->crpc_status = -EBADMSG; - atomic_inc(&sn->sn_ping_errors); - CERROR("Bad seq %u from %s, %u expected.\n", - reply->pnr_seq, libcfs_id2str(rpc->crpc_dest), - reqst->pnr_seq); - return; - } - - ktime_get_real_ts64(&ts); - CDEBUG(D_NET, "%d reply in %u usec\n", reply->pnr_seq, - (unsigned int)((ts.tv_sec - reqst->pnr_time_sec) * 1000000 + - (ts.tv_nsec / NSEC_PER_USEC - reqst->pnr_time_usec))); -} - -static int -ping_server_handle(struct srpc_server_rpc *rpc) -{ - struct srpc_service *sv = rpc->srpc_scd->scd_svc; - struct srpc_msg *reqstmsg = &rpc->srpc_reqstbuf->buf_msg; - struct srpc_msg *replymsg = &rpc->srpc_replymsg; - struct srpc_ping_reqst *req = &reqstmsg->msg_body.ping_reqst; - struct srpc_ping_reply *rep = &rpc->srpc_replymsg.msg_body.ping_reply; - - LASSERT(sv->sv_id == SRPC_SERVICE_PING); - - if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) { - LASSERT(reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC)); - - __swab32s(&req->pnr_seq); - __swab32s(&req->pnr_magic); - __swab64s(&req->pnr_time_sec); - __swab64s(&req->pnr_time_usec); - } - LASSERT(reqstmsg->msg_type == srpc_service2request(sv->sv_id)); - - if (req->pnr_magic != LST_PING_TEST_MAGIC) { - CERROR("Unexpected magic %08x from %s\n", - req->pnr_magic, libcfs_id2str(rpc->srpc_peer)); - return -EINVAL; - } - - rep->pnr_seq = req->pnr_seq; - rep->pnr_magic = LST_PING_TEST_MAGIC; - - if (reqstmsg->msg_ses_feats & ~LST_FEATS_MASK) { - replymsg->msg_ses_feats = LST_FEATS_MASK; - rep->pnr_status = EPROTO; - return 0; - } - - replymsg->msg_ses_feats = reqstmsg->msg_ses_feats; - - CDEBUG(D_NET, "Get ping %d from %s\n", - req->pnr_seq, libcfs_id2str(rpc->srpc_peer)); - return 0; -} - -struct sfw_test_client_ops ping_test_client; - -void ping_init_test_client(void) -{ - ping_test_client.tso_init = ping_client_init; - ping_test_client.tso_fini = ping_client_fini; - ping_test_client.tso_prep_rpc = ping_client_prep_rpc; - ping_test_client.tso_done_rpc = ping_client_done_rpc; -} - -struct srpc_service ping_test_service; - -void ping_init_test_service(void) -{ - ping_test_service.sv_id = SRPC_SERVICE_PING; - ping_test_service.sv_name = "ping_test"; - ping_test_service.sv_handler = ping_server_handle; - ping_test_service.sv_wi_total = ping_srv_workitems; -} diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c deleted file mode 100644 index 9613b0a77007..000000000000 --- a/drivers/staging/lustre/lnet/selftest/rpc.c +++ /dev/null @@ -1,1682 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2015, Intel Corporation. - */ -/* - * 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> - * - * 2012-05-13: Liang Zhen <liang@whamcloud.com> - * - percpt data for service to improve smp performance - * - code cleanup - */ - -#define DEBUG_SUBSYSTEM S_LNET - -#include "selftest.h" - -enum srpc_state { - SRPC_STATE_NONE, - SRPC_STATE_NI_INIT, - SRPC_STATE_EQ_INIT, - SRPC_STATE_RUNNING, - SRPC_STATE_STOPPING, -}; - -static struct smoketest_rpc { - spinlock_t rpc_glock; /* global lock */ - struct srpc_service *rpc_services[SRPC_SERVICE_MAX_ID + 1]; - struct lnet_handle_eq rpc_lnet_eq; /* _the_ LNet event queue */ - enum srpc_state rpc_state; - struct srpc_counters rpc_counters; - __u64 rpc_matchbits; /* matchbits counter */ -} srpc_data; - -static inline int -srpc_serv_portal(int svc_id) -{ - return svc_id < SRPC_FRAMEWORK_SERVICE_MAX_ID ? - SRPC_FRAMEWORK_REQUEST_PORTAL : SRPC_REQUEST_PORTAL; -} - -/* forward ref's */ -void srpc_handle_rpc(struct swi_workitem *wi); - -void srpc_get_counters(struct srpc_counters *cnt) -{ - spin_lock(&srpc_data.rpc_glock); - *cnt = srpc_data.rpc_counters; - spin_unlock(&srpc_data.rpc_glock); -} - -void srpc_set_counters(const struct srpc_counters *cnt) -{ - spin_lock(&srpc_data.rpc_glock); - srpc_data.rpc_counters = *cnt; - spin_unlock(&srpc_data.rpc_glock); -} - -static int -srpc_add_bulk_page(struct srpc_bulk *bk, struct page *pg, int i, int off, - int nob) -{ - LASSERT(off < PAGE_SIZE); - LASSERT(nob > 0 && nob <= PAGE_SIZE); - - bk->bk_iovs[i].bv_offset = off; - bk->bk_iovs[i].bv_page = pg; - bk->bk_iovs[i].bv_len = nob; - return nob; -} - -void -srpc_free_bulk(struct srpc_bulk *bk) -{ - int i; - struct page *pg; - - LASSERT(bk); - - for (i = 0; i < bk->bk_niov; i++) { - pg = bk->bk_iovs[i].bv_page; - if (!pg) - break; - - __free_page(pg); - } - - kfree(bk); -} - -struct srpc_bulk * -srpc_alloc_bulk(int cpt, unsigned int bulk_off, unsigned int bulk_npg, - unsigned int bulk_len, int sink) -{ - struct srpc_bulk *bk; - int i; - - LASSERT(bulk_npg > 0 && bulk_npg <= LNET_MAX_IOV); - - bk = kzalloc_cpt(offsetof(struct srpc_bulk, bk_iovs[bulk_npg]), - GFP_KERNEL, cpt); - if (!bk) { - CERROR("Can't allocate descriptor for %d pages\n", bulk_npg); - return NULL; - } - - memset(bk, 0, offsetof(struct srpc_bulk, bk_iovs[bulk_npg])); - bk->bk_sink = sink; - bk->bk_len = bulk_len; - bk->bk_niov = bulk_npg; - - for (i = 0; i < bulk_npg; i++) { - struct page *pg; - int nob; - - pg = alloc_pages_node(cfs_cpt_spread_node(lnet_cpt_table(), cpt), - GFP_KERNEL, 0); - if (!pg) { - CERROR("Can't allocate page %d of %d\n", i, bulk_npg); - srpc_free_bulk(bk); - return NULL; - } - - nob = min_t(unsigned int, bulk_off + bulk_len, PAGE_SIZE) - - bulk_off; - srpc_add_bulk_page(bk, pg, i, bulk_off, nob); - bulk_len -= nob; - bulk_off = 0; - } - - return bk; -} - -static inline __u64 -srpc_next_id(void) -{ - __u64 id; - - spin_lock(&srpc_data.rpc_glock); - id = srpc_data.rpc_matchbits++; - spin_unlock(&srpc_data.rpc_glock); - return id; -} - -static void -srpc_init_server_rpc(struct srpc_server_rpc *rpc, - struct srpc_service_cd *scd, - struct srpc_buffer *buffer) -{ - memset(rpc, 0, sizeof(*rpc)); - swi_init_workitem(&rpc->srpc_wi, srpc_handle_rpc, - srpc_serv_is_framework(scd->scd_svc) ? - lst_serial_wq : lst_test_wq[scd->scd_cpt]); - - rpc->srpc_ev.ev_fired = 1; /* no event expected now */ - - rpc->srpc_scd = scd; - rpc->srpc_reqstbuf = buffer; - rpc->srpc_peer = buffer->buf_peer; - rpc->srpc_self = buffer->buf_self; - LNetInvalidateMDHandle(&rpc->srpc_replymdh); -} - -static void -srpc_service_fini(struct srpc_service *svc) -{ - struct srpc_service_cd *scd; - struct srpc_server_rpc *rpc; - struct srpc_buffer *buf; - struct list_head *q; - int i; - - if (!svc->sv_cpt_data) - return; - - cfs_percpt_for_each(scd, i, svc->sv_cpt_data) { - while (1) { - if (!list_empty(&scd->scd_buf_posted)) - q = &scd->scd_buf_posted; - else if (!list_empty(&scd->scd_buf_blocked)) - q = &scd->scd_buf_blocked; - else - break; - - while (!list_empty(q)) { - buf = list_entry(q->next, struct srpc_buffer, - buf_list); - list_del(&buf->buf_list); - kfree(buf); - } - } - - LASSERT(list_empty(&scd->scd_rpc_active)); - - while (!list_empty(&scd->scd_rpc_free)) { - rpc = list_entry(scd->scd_rpc_free.next, - struct srpc_server_rpc, - srpc_list); - list_del(&rpc->srpc_list); - kfree(rpc); - } - } - - cfs_percpt_free(svc->sv_cpt_data); - svc->sv_cpt_data = NULL; -} - -static int -srpc_service_nrpcs(struct srpc_service *svc) -{ - int nrpcs = svc->sv_wi_total / svc->sv_ncpts; - - return srpc_serv_is_framework(svc) ? - max(nrpcs, SFW_FRWK_WI_MIN) : max(nrpcs, SFW_TEST_WI_MIN); -} - -void srpc_add_buffer(struct swi_workitem *wi); - -static int -srpc_service_init(struct srpc_service *svc) -{ - struct srpc_service_cd *scd; - struct srpc_server_rpc *rpc; - int nrpcs; - int i; - int j; - - svc->sv_shuttingdown = 0; - - svc->sv_cpt_data = cfs_percpt_alloc(lnet_cpt_table(), - sizeof(**svc->sv_cpt_data)); - if (!svc->sv_cpt_data) - return -ENOMEM; - - svc->sv_ncpts = srpc_serv_is_framework(svc) ? - 1 : cfs_cpt_number(lnet_cpt_table()); - nrpcs = srpc_service_nrpcs(svc); - - cfs_percpt_for_each(scd, i, svc->sv_cpt_data) { - scd->scd_cpt = i; - scd->scd_svc = svc; - spin_lock_init(&scd->scd_lock); - INIT_LIST_HEAD(&scd->scd_rpc_free); - INIT_LIST_HEAD(&scd->scd_rpc_active); - INIT_LIST_HEAD(&scd->scd_buf_posted); - INIT_LIST_HEAD(&scd->scd_buf_blocked); - - scd->scd_ev.ev_data = scd; - scd->scd_ev.ev_type = SRPC_REQUEST_RCVD; - - /* - * NB: don't use lst_serial_wq for adding buffer, - * see details in srpc_service_add_buffers() - */ - swi_init_workitem(&scd->scd_buf_wi, - srpc_add_buffer, lst_test_wq[i]); - - if (i && srpc_serv_is_framework(svc)) { - /* - * NB: framework service only needs srpc_service_cd for - * one partition, but we allocate for all to make - * it easier to implement, it will waste a little - * memory but nobody should care about this - */ - continue; - } - - for (j = 0; j < nrpcs; j++) { - rpc = kzalloc_cpt(sizeof(*rpc), GFP_NOFS, i); - if (!rpc) { - srpc_service_fini(svc); - return -ENOMEM; - } - list_add(&rpc->srpc_list, &scd->scd_rpc_free); - } - } - - return 0; -} - -int -srpc_add_service(struct srpc_service *sv) -{ - int id = sv->sv_id; - - LASSERT(0 <= id && id <= SRPC_SERVICE_MAX_ID); - - if (srpc_service_init(sv)) - return -ENOMEM; - - spin_lock(&srpc_data.rpc_glock); - - LASSERT(srpc_data.rpc_state == SRPC_STATE_RUNNING); - - if (srpc_data.rpc_services[id]) { - spin_unlock(&srpc_data.rpc_glock); - goto failed; - } - - srpc_data.rpc_services[id] = sv; - spin_unlock(&srpc_data.rpc_glock); - - CDEBUG(D_NET, "Adding service: id %d, name %s\n", id, sv->sv_name); - return 0; - - failed: - srpc_service_fini(sv); - return -EBUSY; -} - -int -srpc_remove_service(struct srpc_service *sv) -{ - int id = sv->sv_id; - - spin_lock(&srpc_data.rpc_glock); - - if (srpc_data.rpc_services[id] != sv) { - spin_unlock(&srpc_data.rpc_glock); - return -ENOENT; - } - - srpc_data.rpc_services[id] = NULL; - spin_unlock(&srpc_data.rpc_glock); - return 0; -} - -static int -srpc_post_passive_rdma(int portal, int local, __u64 matchbits, void *buf, - int len, int options, struct lnet_process_id peer, - struct lnet_handle_md *mdh, struct srpc_event *ev) -{ - int rc; - struct lnet_md md; - struct lnet_handle_me meh; - - rc = LNetMEAttach(portal, peer, matchbits, 0, LNET_UNLINK, - local ? LNET_INS_LOCAL : LNET_INS_AFTER, &meh); - if (rc) { - CERROR("LNetMEAttach failed: %d\n", rc); - LASSERT(rc == -ENOMEM); - return -ENOMEM; - } - - md.threshold = 1; - md.user_ptr = ev; - md.start = buf; - md.length = len; - md.options = options; - md.eq_handle = srpc_data.rpc_lnet_eq; - - rc = LNetMDAttach(meh, md, LNET_UNLINK, mdh); - if (rc) { - CERROR("LNetMDAttach failed: %d\n", rc); - LASSERT(rc == -ENOMEM); - - rc = LNetMEUnlink(meh); - LASSERT(!rc); - return -ENOMEM; - } - - CDEBUG(D_NET, "Posted passive RDMA: peer %s, portal %d, matchbits %#llx\n", - libcfs_id2str(peer), portal, matchbits); - return 0; -} - -static int -srpc_post_active_rdma(int portal, __u64 matchbits, void *buf, int len, - int options, struct lnet_process_id peer, - lnet_nid_t self, struct lnet_handle_md *mdh, - struct srpc_event *ev) -{ - int rc; - struct lnet_md md; - - md.user_ptr = ev; - md.start = buf; - md.length = len; - md.eq_handle = srpc_data.rpc_lnet_eq; - md.threshold = options & LNET_MD_OP_GET ? 2 : 1; - md.options = options & ~(LNET_MD_OP_PUT | LNET_MD_OP_GET); - - rc = LNetMDBind(md, LNET_UNLINK, mdh); - if (rc) { - CERROR("LNetMDBind failed: %d\n", rc); - LASSERT(rc == -ENOMEM); - return -ENOMEM; - } - - /* - * 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) { - rc = LNetPut(self, *mdh, LNET_NOACK_REQ, peer, - portal, matchbits, 0, 0); - } else { - LASSERT(options & LNET_MD_OP_GET); - - rc = LNetGet(self, *mdh, peer, portal, matchbits, 0); - } - - if (rc) { - CERROR("LNet%s(%s, %d, %lld) failed: %d\n", - options & LNET_MD_OP_PUT ? "Put" : "Get", - libcfs_id2str(peer), portal, matchbits, rc); - - /* - * The forthcoming unlink event will complete this operation - * with failure, so fall through and return success here. - */ - rc = LNetMDUnlink(*mdh); - LASSERT(!rc); - } else { - CDEBUG(D_NET, "Posted active RDMA: peer %s, portal %u, matchbits %#llx\n", - libcfs_id2str(peer), portal, matchbits); - } - return 0; -} - -static int -srpc_post_passive_rqtbuf(int service, int local, void *buf, int len, - struct lnet_handle_md *mdh, struct srpc_event *ev) -{ - struct lnet_process_id any = { 0 }; - - any.nid = LNET_NID_ANY; - any.pid = LNET_PID_ANY; - - return srpc_post_passive_rdma(srpc_serv_portal(service), - local, service, buf, len, - LNET_MD_OP_PUT, any, mdh, ev); -} - -static int -srpc_service_post_buffer(struct srpc_service_cd *scd, struct srpc_buffer *buf) -__must_hold(&scd->scd_lock) -{ - struct srpc_service *sv = scd->scd_svc; - struct srpc_msg *msg = &buf->buf_msg; - int rc; - - LNetInvalidateMDHandle(&buf->buf_mdh); - list_add(&buf->buf_list, &scd->scd_buf_posted); - scd->scd_buf_nposted++; - spin_unlock(&scd->scd_lock); - - rc = srpc_post_passive_rqtbuf(sv->sv_id, - !srpc_serv_is_framework(sv), - msg, sizeof(*msg), &buf->buf_mdh, - &scd->scd_ev); - - /* - * At this point, a RPC (new or delayed) may have arrived in - * msg and its event handler has been called. So we must add - * buf to scd_buf_posted _before_ dropping scd_lock - */ - spin_lock(&scd->scd_lock); - - if (!rc) { - if (!sv->sv_shuttingdown) - return 0; - - spin_unlock(&scd->scd_lock); - /* - * srpc_shutdown_service might have tried to unlink me - * when my buf_mdh was still invalid - */ - LNetMDUnlink(buf->buf_mdh); - spin_lock(&scd->scd_lock); - return 0; - } - - scd->scd_buf_nposted--; - if (sv->sv_shuttingdown) - return rc; /* don't allow to change scd_buf_posted */ - - list_del(&buf->buf_list); - spin_unlock(&scd->scd_lock); - - kfree(buf); - - spin_lock(&scd->scd_lock); - return rc; -} - -void -srpc_add_buffer(struct swi_workitem *wi) -{ - struct srpc_service_cd *scd = container_of(wi, struct srpc_service_cd, scd_buf_wi); - struct srpc_buffer *buf; - int rc = 0; - - /* - * it's called by workitem scheduler threads, these threads - * should have been set CPT affinity, so buffers will be posted - * on CPT local list of Portal - */ - spin_lock(&scd->scd_lock); - - while (scd->scd_buf_adjust > 0 && - !scd->scd_svc->sv_shuttingdown) { - scd->scd_buf_adjust--; /* consume it */ - scd->scd_buf_posting++; - - spin_unlock(&scd->scd_lock); - - buf = kzalloc(sizeof(*buf), GFP_NOFS); - if (!buf) { - CERROR("Failed to add new buf to service: %s\n", - scd->scd_svc->sv_name); - spin_lock(&scd->scd_lock); - rc = -ENOMEM; - break; - } - - spin_lock(&scd->scd_lock); - if (scd->scd_svc->sv_shuttingdown) { - spin_unlock(&scd->scd_lock); - kfree(buf); - - spin_lock(&scd->scd_lock); - rc = -ESHUTDOWN; - break; - } - - rc = srpc_service_post_buffer(scd, buf); - if (rc) - break; /* buf has been freed inside */ - - LASSERT(scd->scd_buf_posting > 0); - scd->scd_buf_posting--; - scd->scd_buf_total++; - scd->scd_buf_low = max(2, scd->scd_buf_total / 4); - } - - if (rc) { - scd->scd_buf_err_stamp = ktime_get_real_seconds(); - scd->scd_buf_err = rc; - - LASSERT(scd->scd_buf_posting > 0); - scd->scd_buf_posting--; - } - - spin_unlock(&scd->scd_lock); -} - -int -srpc_service_add_buffers(struct srpc_service *sv, int nbuffer) -{ - struct srpc_service_cd *scd; - int rc = 0; - int i; - - LASSERTF(nbuffer > 0, "nbuffer must be positive: %d\n", nbuffer); - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - spin_lock(&scd->scd_lock); - - scd->scd_buf_err = 0; - scd->scd_buf_err_stamp = 0; - scd->scd_buf_posting = 0; - scd->scd_buf_adjust = nbuffer; - /* start to post buffers */ - swi_schedule_workitem(&scd->scd_buf_wi); - spin_unlock(&scd->scd_lock); - - /* framework service only post buffer for one partition */ - if (srpc_serv_is_framework(sv)) - break; - } - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - spin_lock(&scd->scd_lock); - /* - * NB: srpc_service_add_buffers() can be called inside - * thread context of lst_serial_wq, and we don't normally - * allow to sleep inside thread context of WI scheduler - * because it will block current scheduler thread from doing - * anything else, even worse, it could deadlock if it's - * waiting on result from another WI of the same scheduler. - * However, it's safe at here because scd_buf_wi is scheduled - * by thread in a different WI scheduler (lst_test_wq), - * so we don't have any risk of deadlock, though this could - * block all WIs pending on lst_serial_wq for a moment - * which is not good but not fatal. - */ - lst_wait_until(scd->scd_buf_err || - (!scd->scd_buf_adjust && - !scd->scd_buf_posting), - scd->scd_lock, "waiting for adding buffer\n"); - - if (scd->scd_buf_err && !rc) - rc = scd->scd_buf_err; - - spin_unlock(&scd->scd_lock); - } - - return rc; -} - -void -srpc_service_remove_buffers(struct srpc_service *sv, int nbuffer) -{ - struct srpc_service_cd *scd; - int num; - int i; - - LASSERT(!sv->sv_shuttingdown); - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - spin_lock(&scd->scd_lock); - - num = scd->scd_buf_total + scd->scd_buf_posting; - scd->scd_buf_adjust -= min(nbuffer, num); - - spin_unlock(&scd->scd_lock); - } -} - -/* returns 1 if sv has finished, otherwise 0 */ -int -srpc_finish_service(struct srpc_service *sv) -{ - struct srpc_service_cd *scd; - struct srpc_server_rpc *rpc; - int i; - - LASSERT(sv->sv_shuttingdown); /* srpc_shutdown_service called */ - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - swi_cancel_workitem(&scd->scd_buf_wi); - - spin_lock(&scd->scd_lock); - - if (scd->scd_buf_nposted > 0) { - CDEBUG(D_NET, "waiting for %d posted buffers to unlink\n", - scd->scd_buf_nposted); - spin_unlock(&scd->scd_lock); - return 0; - } - - if (list_empty(&scd->scd_rpc_active)) { - spin_unlock(&scd->scd_lock); - continue; - } - - rpc = list_entry(scd->scd_rpc_active.next, - struct srpc_server_rpc, srpc_list); - CNETERR("Active RPC %p on shutdown: sv %s, peer %s, wi %s, ev fired %d type %d status %d lnet %d\n", - rpc, sv->sv_name, libcfs_id2str(rpc->srpc_peer), - swi_state2str(rpc->srpc_wi.swi_state), - rpc->srpc_ev.ev_fired, rpc->srpc_ev.ev_type, - rpc->srpc_ev.ev_status, rpc->srpc_ev.ev_lnet); - spin_unlock(&scd->scd_lock); - return 0; - } - - /* no lock needed from now on */ - srpc_service_fini(sv); - return 1; -} - -/* called with sv->sv_lock held */ -static void -srpc_service_recycle_buffer(struct srpc_service_cd *scd, - struct srpc_buffer *buf) -__must_hold(&scd->scd_lock) -{ - if (!scd->scd_svc->sv_shuttingdown && scd->scd_buf_adjust >= 0) { - if (srpc_service_post_buffer(scd, buf)) { - CWARN("Failed to post %s buffer\n", - scd->scd_svc->sv_name); - } - return; - } - - /* service is shutting down, or we want to recycle some buffers */ - scd->scd_buf_total--; - - if (scd->scd_buf_adjust < 0) { - scd->scd_buf_adjust++; - if (scd->scd_buf_adjust < 0 && - !scd->scd_buf_total && !scd->scd_buf_posting) { - CDEBUG(D_INFO, - "Try to recycle %d buffers but nothing left\n", - scd->scd_buf_adjust); - scd->scd_buf_adjust = 0; - } - } - - spin_unlock(&scd->scd_lock); - kfree(buf); - spin_lock(&scd->scd_lock); -} - -void -srpc_abort_service(struct srpc_service *sv) -{ - struct srpc_service_cd *scd; - struct srpc_server_rpc *rpc; - int i; - - CDEBUG(D_NET, "Aborting service: id %d, name %s\n", - sv->sv_id, sv->sv_name); - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - spin_lock(&scd->scd_lock); - - /* - * schedule in-flight RPCs to notice the abort, NB: - * racing with incoming RPCs; complete fix should make test - * RPCs carry session ID in its headers - */ - list_for_each_entry(rpc, &scd->scd_rpc_active, srpc_list) { - rpc->srpc_aborted = 1; - swi_schedule_workitem(&rpc->srpc_wi); - } - - spin_unlock(&scd->scd_lock); - } -} - -void -srpc_shutdown_service(struct srpc_service *sv) -{ - struct srpc_service_cd *scd; - struct srpc_server_rpc *rpc; - struct srpc_buffer *buf; - int i; - - CDEBUG(D_NET, "Shutting down service: id %d, name %s\n", - sv->sv_id, sv->sv_name); - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) - spin_lock(&scd->scd_lock); - - sv->sv_shuttingdown = 1; /* i.e. no new active RPC */ - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) - spin_unlock(&scd->scd_lock); - - cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { - spin_lock(&scd->scd_lock); - - /* schedule in-flight RPCs to notice the shutdown */ - list_for_each_entry(rpc, &scd->scd_rpc_active, srpc_list) - swi_schedule_workitem(&rpc->srpc_wi); - - spin_unlock(&scd->scd_lock); - - /* - * OK to traverse scd_buf_posted without lock, since no one - * touches scd_buf_posted now - */ - list_for_each_entry(buf, &scd->scd_buf_posted, buf_list) - LNetMDUnlink(buf->buf_mdh); - } -} - -static int -srpc_send_request(struct srpc_client_rpc *rpc) -{ - struct srpc_event *ev = &rpc->crpc_reqstev; - int rc; - - ev->ev_fired = 0; - ev->ev_data = rpc; - ev->ev_type = SRPC_REQUEST_SENT; - - rc = srpc_post_active_rdma(srpc_serv_portal(rpc->crpc_service), - rpc->crpc_service, &rpc->crpc_reqstmsg, - sizeof(struct srpc_msg), LNET_MD_OP_PUT, - rpc->crpc_dest, LNET_NID_ANY, - &rpc->crpc_reqstmdh, ev); - if (rc) { - LASSERT(rc == -ENOMEM); - ev->ev_fired = 1; /* no more event expected */ - } - return rc; -} - -static int -srpc_prepare_reply(struct srpc_client_rpc *rpc) -{ - struct srpc_event *ev = &rpc->crpc_replyev; - __u64 *id = &rpc->crpc_reqstmsg.msg_body.reqst.rpyid; - int rc; - - ev->ev_fired = 0; - ev->ev_data = rpc; - ev->ev_type = SRPC_REPLY_RCVD; - - *id = srpc_next_id(); - - rc = srpc_post_passive_rdma(SRPC_RDMA_PORTAL, 0, *id, - &rpc->crpc_replymsg, - sizeof(struct srpc_msg), - LNET_MD_OP_PUT, rpc->crpc_dest, - &rpc->crpc_replymdh, ev); - if (rc) { - LASSERT(rc == -ENOMEM); - ev->ev_fired = 1; /* no more event expected */ - } - return rc; -} - -static int -srpc_prepare_bulk(struct srpc_client_rpc *rpc) -{ - struct srpc_bulk *bk = &rpc->crpc_bulk; - struct srpc_event *ev = &rpc->crpc_bulkev; - __u64 *id = &rpc->crpc_reqstmsg.msg_body.reqst.bulkid; - int rc; - int opt; - - LASSERT(bk->bk_niov <= LNET_MAX_IOV); - - if (!bk->bk_niov) - return 0; /* nothing to do */ - - opt = bk->bk_sink ? LNET_MD_OP_PUT : LNET_MD_OP_GET; - opt |= LNET_MD_KIOV; - - ev->ev_fired = 0; - ev->ev_data = rpc; - ev->ev_type = SRPC_BULK_REQ_RCVD; - - *id = srpc_next_id(); - - rc = srpc_post_passive_rdma(SRPC_RDMA_PORTAL, 0, *id, - &bk->bk_iovs[0], bk->bk_niov, opt, - rpc->crpc_dest, &bk->bk_mdh, ev); - if (rc) { - LASSERT(rc == -ENOMEM); - ev->ev_fired = 1; /* no more event expected */ - } - return rc; -} - -static int -srpc_do_bulk(struct srpc_server_rpc *rpc) -{ - struct srpc_event *ev = &rpc->srpc_ev; - struct srpc_bulk *bk = rpc->srpc_bulk; - __u64 id = rpc->srpc_reqstbuf->buf_msg.msg_body.reqst.bulkid; - int rc; - int opt; - - LASSERT(bk); - - opt = bk->bk_sink ? LNET_MD_OP_GET : LNET_MD_OP_PUT; - opt |= LNET_MD_KIOV; - - ev->ev_fired = 0; - ev->ev_data = rpc; - ev->ev_type = bk->bk_sink ? SRPC_BULK_GET_RPLD : SRPC_BULK_PUT_SENT; - - rc = srpc_post_active_rdma(SRPC_RDMA_PORTAL, id, - &bk->bk_iovs[0], bk->bk_niov, opt, - rpc->srpc_peer, rpc->srpc_self, - &bk->bk_mdh, ev); - if (rc) - ev->ev_fired = 1; /* no more event expected */ - return rc; -} - -/* only called from srpc_handle_rpc */ -static void -srpc_server_rpc_done(struct srpc_server_rpc *rpc, int status) -{ - struct srpc_service_cd *scd = rpc->srpc_scd; - struct srpc_service *sv = scd->scd_svc; - struct srpc_buffer *buffer; - - LASSERT(status || rpc->srpc_wi.swi_state == SWI_STATE_DONE); - - rpc->srpc_status = status; - - CDEBUG_LIMIT(!status ? D_NET : D_NETERROR, - "Server RPC %p done: service %s, peer %s, status %s:%d\n", - rpc, sv->sv_name, libcfs_id2str(rpc->srpc_peer), - swi_state2str(rpc->srpc_wi.swi_state), status); - - if (status) { - spin_lock(&srpc_data.rpc_glock); - srpc_data.rpc_counters.rpcs_dropped++; - spin_unlock(&srpc_data.rpc_glock); - } - - if (rpc->srpc_done) - (*rpc->srpc_done) (rpc); - LASSERT(!rpc->srpc_bulk); - - spin_lock(&scd->scd_lock); - - if (rpc->srpc_reqstbuf) { - /* - * NB might drop sv_lock in srpc_service_recycle_buffer, but - * sv won't go away for scd_rpc_active must not be empty - */ - srpc_service_recycle_buffer(scd, rpc->srpc_reqstbuf); - rpc->srpc_reqstbuf = NULL; - } - - list_del(&rpc->srpc_list); /* from scd->scd_rpc_active */ - - /* - * No one can schedule me now since: - * - I'm not on scd_rpc_active. - * - all LNet events have been fired. - * Cancel pending schedules and prevent future schedule attempts: - */ - LASSERT(rpc->srpc_ev.ev_fired); - - if (!sv->sv_shuttingdown && !list_empty(&scd->scd_buf_blocked)) { - buffer = list_entry(scd->scd_buf_blocked.next, - struct srpc_buffer, buf_list); - list_del(&buffer->buf_list); - - srpc_init_server_rpc(rpc, scd, buffer); - list_add_tail(&rpc->srpc_list, &scd->scd_rpc_active); - swi_schedule_workitem(&rpc->srpc_wi); - } else { - list_add(&rpc->srpc_list, &scd->scd_rpc_free); - } - - spin_unlock(&scd->scd_lock); -} - -/* handles an incoming RPC */ -void -srpc_handle_rpc(struct swi_workitem *wi) -{ - struct srpc_server_rpc *rpc = container_of(wi, struct srpc_server_rpc, srpc_wi); - struct srpc_service_cd *scd = rpc->srpc_scd; - struct srpc_service *sv = scd->scd_svc; - struct srpc_event *ev = &rpc->srpc_ev; - int rc = 0; - - LASSERT(wi == &rpc->srpc_wi); - - spin_lock(&scd->scd_lock); - - if (sv->sv_shuttingdown || rpc->srpc_aborted) { - spin_unlock(&scd->scd_lock); - - if (rpc->srpc_bulk) - LNetMDUnlink(rpc->srpc_bulk->bk_mdh); - LNetMDUnlink(rpc->srpc_replymdh); - - if (ev->ev_fired) { /* no more event, OK to finish */ - srpc_server_rpc_done(rpc, -ESHUTDOWN); - } - return; - } - - spin_unlock(&scd->scd_lock); - - switch (wi->swi_state) { - default: - LBUG(); - case SWI_STATE_NEWBORN: { - struct srpc_msg *msg; - struct srpc_generic_reply *reply; - - msg = &rpc->srpc_reqstbuf->buf_msg; - reply = &rpc->srpc_replymsg.msg_body.reply; - - if (!msg->msg_magic) { - /* moaned already in srpc_lnet_ev_handler */ - srpc_server_rpc_done(rpc, EBADMSG); - return; - } - - srpc_unpack_msg_hdr(msg); - if (msg->msg_version != SRPC_MSG_VERSION) { - CWARN("Version mismatch: %u, %u expected, from %s\n", - msg->msg_version, SRPC_MSG_VERSION, - libcfs_id2str(rpc->srpc_peer)); - reply->status = EPROTO; - /* drop through and send reply */ - } else { - reply->status = 0; - rc = (*sv->sv_handler)(rpc); - LASSERT(!reply->status || !rpc->srpc_bulk); - if (rc) { - srpc_server_rpc_done(rpc, rc); - return; - } - } - - wi->swi_state = SWI_STATE_BULK_STARTED; - - if (rpc->srpc_bulk) { - rc = srpc_do_bulk(rpc); - if (!rc) - return; /* wait for bulk */ - - LASSERT(ev->ev_fired); - ev->ev_status = rc; - } - } - /* fall through */ - case SWI_STATE_BULK_STARTED: - LASSERT(!rpc->srpc_bulk || ev->ev_fired); - - if (rpc->srpc_bulk) { - rc = ev->ev_status; - - if (sv->sv_bulk_ready) - rc = (*sv->sv_bulk_ready) (rpc, rc); - - if (rc) { - srpc_server_rpc_done(rpc, rc); - return; - } - } - - wi->swi_state = SWI_STATE_REPLY_SUBMITTED; - rc = srpc_send_reply(rpc); - if (!rc) - return; /* wait for reply */ - srpc_server_rpc_done(rpc, rc); - return; - - case SWI_STATE_REPLY_SUBMITTED: - if (!ev->ev_fired) { - CERROR("RPC %p: bulk %p, service %d\n", - rpc, rpc->srpc_bulk, sv->sv_id); - CERROR("Event: status %d, type %d, lnet %d\n", - ev->ev_status, ev->ev_type, ev->ev_lnet); - LASSERT(ev->ev_fired); - } - - wi->swi_state = SWI_STATE_DONE; - srpc_server_rpc_done(rpc, ev->ev_status); - return; - } -} - -static void -srpc_client_rpc_expired(void *data) -{ - struct srpc_client_rpc *rpc = data; - - CWARN("Client RPC expired: service %d, peer %s, timeout %d.\n", - rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), - rpc->crpc_timeout); - - spin_lock(&rpc->crpc_lock); - - rpc->crpc_timeout = 0; - srpc_abort_rpc(rpc, -ETIMEDOUT); - - spin_unlock(&rpc->crpc_lock); - - spin_lock(&srpc_data.rpc_glock); - srpc_data.rpc_counters.rpcs_expired++; - spin_unlock(&srpc_data.rpc_glock); -} - -static void -srpc_add_client_rpc_timer(struct srpc_client_rpc *rpc) -{ - struct stt_timer *timer = &rpc->crpc_timer; - - if (!rpc->crpc_timeout) - return; - - INIT_LIST_HEAD(&timer->stt_list); - timer->stt_data = rpc; - timer->stt_func = srpc_client_rpc_expired; - timer->stt_expires = ktime_get_real_seconds() + rpc->crpc_timeout; - stt_add_timer(timer); -} - -/* - * Called with rpc->crpc_lock held. - * - * Upon exit the RPC expiry timer is not queued and the handler is not - * running on any CPU. - */ -static void -srpc_del_client_rpc_timer(struct srpc_client_rpc *rpc) -{ - /* timer not planted or already exploded */ - if (!rpc->crpc_timeout) - return; - - /* timer successfully defused */ - if (stt_del_timer(&rpc->crpc_timer)) - return; - - /* timer detonated, wait for it to explode */ - while (rpc->crpc_timeout) { - spin_unlock(&rpc->crpc_lock); - - schedule(); - - spin_lock(&rpc->crpc_lock); - } -} - -static void -srpc_client_rpc_done(struct srpc_client_rpc *rpc, int status) -{ - struct swi_workitem *wi = &rpc->crpc_wi; - - LASSERT(status || wi->swi_state == SWI_STATE_DONE); - - spin_lock(&rpc->crpc_lock); - - rpc->crpc_closed = 1; - if (!rpc->crpc_status) - rpc->crpc_status = status; - - srpc_del_client_rpc_timer(rpc); - - CDEBUG_LIMIT(!status ? D_NET : D_NETERROR, - "Client RPC done: service %d, peer %s, status %s:%d:%d\n", - rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), - swi_state2str(wi->swi_state), rpc->crpc_aborted, status); - - /* - * 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 - * scheduling me. - * Cancel pending schedules and prevent future schedule attempts: - */ - LASSERT(!srpc_event_pending(rpc)); - - spin_unlock(&rpc->crpc_lock); - - (*rpc->crpc_done)(rpc); -} - -/* sends an outgoing RPC */ -void -srpc_send_rpc(struct swi_workitem *wi) -{ - int rc = 0; - struct srpc_client_rpc *rpc; - struct srpc_msg *reply; - int do_bulk; - - LASSERT(wi); - - rpc = container_of(wi, struct srpc_client_rpc, crpc_wi); - - LASSERT(rpc); - LASSERT(wi == &rpc->crpc_wi); - - reply = &rpc->crpc_replymsg; - do_bulk = rpc->crpc_bulk.bk_niov > 0; - - spin_lock(&rpc->crpc_lock); - - if (rpc->crpc_aborted) { - spin_unlock(&rpc->crpc_lock); - goto abort; - } - - spin_unlock(&rpc->crpc_lock); - - switch (wi->swi_state) { - default: - LBUG(); - case SWI_STATE_NEWBORN: - LASSERT(!srpc_event_pending(rpc)); - - rc = srpc_prepare_reply(rpc); - if (rc) { - srpc_client_rpc_done(rpc, rc); - return; - } - - rc = srpc_prepare_bulk(rpc); - if (rc) - break; - - wi->swi_state = SWI_STATE_REQUEST_SUBMITTED; - rc = srpc_send_request(rpc); - break; - - case SWI_STATE_REQUEST_SUBMITTED: - /* - * CAVEAT EMPTOR: rqtev, rpyev, and bulkev may come in any - * order; however, they're processed in a strict order: - * rqt, rpy, and bulk. - */ - if (!rpc->crpc_reqstev.ev_fired) - break; - - rc = rpc->crpc_reqstev.ev_status; - if (rc) - break; - - wi->swi_state = SWI_STATE_REQUEST_SENT; - /* perhaps more events */ - /* fall through */ - case SWI_STATE_REQUEST_SENT: { - enum srpc_msg_type type = srpc_service2reply(rpc->crpc_service); - - if (!rpc->crpc_replyev.ev_fired) - break; - - rc = rpc->crpc_replyev.ev_status; - if (rc) - break; - - srpc_unpack_msg_hdr(reply); - if (reply->msg_type != type || - (reply->msg_magic != SRPC_MSG_MAGIC && - reply->msg_magic != __swab32(SRPC_MSG_MAGIC))) { - CWARN("Bad message from %s: type %u (%d expected), magic %u (%d expected).\n", - libcfs_id2str(rpc->crpc_dest), - reply->msg_type, type, - reply->msg_magic, SRPC_MSG_MAGIC); - rc = -EBADMSG; - break; - } - - if (do_bulk && reply->msg_body.reply.status) { - CWARN("Remote error %d at %s, unlink bulk buffer in case peer didn't initiate bulk transfer\n", - reply->msg_body.reply.status, - libcfs_id2str(rpc->crpc_dest)); - LNetMDUnlink(rpc->crpc_bulk.bk_mdh); - } - - wi->swi_state = SWI_STATE_REPLY_RECEIVED; - } - /* fall through */ - case SWI_STATE_REPLY_RECEIVED: - if (do_bulk && !rpc->crpc_bulkev.ev_fired) - break; - - rc = do_bulk ? rpc->crpc_bulkev.ev_status : 0; - - /* - * Bulk buffer was unlinked due to remote error. Clear error - * since reply buffer still contains valid data. - * NB rpc->crpc_done shouldn't look into bulk data in case of - * remote error. - */ - if (do_bulk && rpc->crpc_bulkev.ev_lnet == LNET_EVENT_UNLINK && - !rpc->crpc_status && reply->msg_body.reply.status) - rc = 0; - - wi->swi_state = SWI_STATE_DONE; - srpc_client_rpc_done(rpc, rc); - return; - } - - if (rc) { - spin_lock(&rpc->crpc_lock); - srpc_abort_rpc(rpc, rc); - spin_unlock(&rpc->crpc_lock); - } - -abort: - if (rpc->crpc_aborted) { - LNetMDUnlink(rpc->crpc_reqstmdh); - LNetMDUnlink(rpc->crpc_replymdh); - LNetMDUnlink(rpc->crpc_bulk.bk_mdh); - - if (!srpc_event_pending(rpc)) { - srpc_client_rpc_done(rpc, -EINTR); - return; - } - } -} - -struct srpc_client_rpc * -srpc_create_client_rpc(struct lnet_process_id peer, int service, - int nbulkiov, int bulklen, - void (*rpc_done)(struct srpc_client_rpc *), - void (*rpc_fini)(struct srpc_client_rpc *), void *priv) -{ - struct srpc_client_rpc *rpc; - - rpc = kzalloc(offsetof(struct srpc_client_rpc, - crpc_bulk.bk_iovs[nbulkiov]), GFP_KERNEL); - if (!rpc) - return NULL; - - srpc_init_client_rpc(rpc, peer, service, nbulkiov, - bulklen, rpc_done, rpc_fini, priv); - return rpc; -} - -/* called with rpc->crpc_lock held */ -void -srpc_abort_rpc(struct srpc_client_rpc *rpc, int why) -{ - LASSERT(why); - - if (rpc->crpc_aborted || /* already aborted */ - rpc->crpc_closed) /* callback imminent */ - return; - - CDEBUG(D_NET, "Aborting RPC: service %d, peer %s, state %s, why %d\n", - rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), - swi_state2str(rpc->crpc_wi.swi_state), why); - - rpc->crpc_aborted = 1; - rpc->crpc_status = why; - swi_schedule_workitem(&rpc->crpc_wi); -} - -/* called with rpc->crpc_lock held */ -void -srpc_post_rpc(struct srpc_client_rpc *rpc) -{ - LASSERT(!rpc->crpc_aborted); - LASSERT(srpc_data.rpc_state == SRPC_STATE_RUNNING); - - CDEBUG(D_NET, "Posting RPC: peer %s, service %d, timeout %d\n", - libcfs_id2str(rpc->crpc_dest), rpc->crpc_service, - rpc->crpc_timeout); - - srpc_add_client_rpc_timer(rpc); - swi_schedule_workitem(&rpc->crpc_wi); -} - -int -srpc_send_reply(struct srpc_server_rpc *rpc) -{ - struct srpc_event *ev = &rpc->srpc_ev; - struct srpc_msg *msg = &rpc->srpc_replymsg; - struct srpc_buffer *buffer = rpc->srpc_reqstbuf; - struct srpc_service_cd *scd = rpc->srpc_scd; - struct srpc_service *sv = scd->scd_svc; - __u64 rpyid; - int rc; - - LASSERT(buffer); - rpyid = buffer->buf_msg.msg_body.reqst.rpyid; - - spin_lock(&scd->scd_lock); - - if (!sv->sv_shuttingdown && !srpc_serv_is_framework(sv)) { - /* - * Repost buffer before replying since test client - * might send me another RPC once it gets the reply - */ - if (srpc_service_post_buffer(scd, buffer)) - CWARN("Failed to repost %s buffer\n", sv->sv_name); - rpc->srpc_reqstbuf = NULL; - } - - spin_unlock(&scd->scd_lock); - - ev->ev_fired = 0; - ev->ev_data = rpc; - ev->ev_type = SRPC_REPLY_SENT; - - msg->msg_magic = SRPC_MSG_MAGIC; - msg->msg_version = SRPC_MSG_VERSION; - msg->msg_type = srpc_service2reply(sv->sv_id); - - rc = srpc_post_active_rdma(SRPC_RDMA_PORTAL, rpyid, msg, - sizeof(*msg), LNET_MD_OP_PUT, - rpc->srpc_peer, rpc->srpc_self, - &rpc->srpc_replymdh, ev); - if (rc) - ev->ev_fired = 1; /* no more event expected */ - return rc; -} - -/* when in kernel always called with LNET_LOCK() held, and in thread context */ -static void -srpc_lnet_ev_handler(struct lnet_event *ev) -{ - struct srpc_service_cd *scd; - struct srpc_event *rpcev = ev->md.user_ptr; - struct srpc_client_rpc *crpc; - struct srpc_server_rpc *srpc; - struct srpc_buffer *buffer; - struct srpc_service *sv; - struct srpc_msg *msg; - enum srpc_msg_type type; - - LASSERT(!in_interrupt()); - - if (ev->status) { - __u32 errors; - - spin_lock(&srpc_data.rpc_glock); - if (ev->status != -ECANCELED) /* cancellation is not error */ - srpc_data.rpc_counters.errors++; - errors = srpc_data.rpc_counters.errors; - spin_unlock(&srpc_data.rpc_glock); - - CNETERR("LNet event status %d type %d, RPC errors %u\n", - ev->status, ev->type, errors); - } - - rpcev->ev_lnet = ev->type; - - switch (rpcev->ev_type) { - default: - CERROR("Unknown event: status %d, type %d, lnet %d\n", - rpcev->ev_status, rpcev->ev_type, rpcev->ev_lnet); - LBUG(); - case SRPC_REQUEST_SENT: - if (!ev->status && ev->type != LNET_EVENT_UNLINK) { - spin_lock(&srpc_data.rpc_glock); - srpc_data.rpc_counters.rpcs_sent++; - spin_unlock(&srpc_data.rpc_glock); - } - /* fall through */ - case SRPC_REPLY_RCVD: - case SRPC_BULK_REQ_RCVD: - crpc = rpcev->ev_data; - - if (rpcev != &crpc->crpc_reqstev && - rpcev != &crpc->crpc_replyev && - rpcev != &crpc->crpc_bulkev) { - CERROR("rpcev %p, crpc %p, reqstev %p, replyev %p, bulkev %p\n", - rpcev, crpc, &crpc->crpc_reqstev, - &crpc->crpc_replyev, &crpc->crpc_bulkev); - CERROR("Bad event: status %d, type %d, lnet %d\n", - rpcev->ev_status, rpcev->ev_type, rpcev->ev_lnet); - LBUG(); - } - - spin_lock(&crpc->crpc_lock); - - LASSERT(!rpcev->ev_fired); - rpcev->ev_fired = 1; - rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ? - -EINTR : ev->status; - swi_schedule_workitem(&crpc->crpc_wi); - - spin_unlock(&crpc->crpc_lock); - break; - - case SRPC_REQUEST_RCVD: - scd = rpcev->ev_data; - sv = scd->scd_svc; - - LASSERT(rpcev == &scd->scd_ev); - - spin_lock(&scd->scd_lock); - - LASSERT(ev->unlinked); - LASSERT(ev->type == LNET_EVENT_PUT || - ev->type == LNET_EVENT_UNLINK); - LASSERT(ev->type != LNET_EVENT_UNLINK || - sv->sv_shuttingdown); - - buffer = container_of(ev->md.start, struct srpc_buffer, buf_msg); - buffer->buf_peer = ev->initiator; - buffer->buf_self = ev->target.nid; - - LASSERT(scd->scd_buf_nposted > 0); - scd->scd_buf_nposted--; - - if (sv->sv_shuttingdown) { - /* - * Leave buffer on scd->scd_buf_nposted since - * srpc_finish_service needs to traverse it. - */ - spin_unlock(&scd->scd_lock); - break; - } - - if (scd->scd_buf_err_stamp && - scd->scd_buf_err_stamp < ktime_get_real_seconds()) { - /* re-enable adding buffer */ - scd->scd_buf_err_stamp = 0; - scd->scd_buf_err = 0; - } - - if (!scd->scd_buf_err && /* adding buffer is enabled */ - !scd->scd_buf_adjust && - scd->scd_buf_nposted < scd->scd_buf_low) { - scd->scd_buf_adjust = max(scd->scd_buf_total / 2, - SFW_TEST_WI_MIN); - swi_schedule_workitem(&scd->scd_buf_wi); - } - - list_del(&buffer->buf_list); /* from scd->scd_buf_posted */ - msg = &buffer->buf_msg; - type = srpc_service2request(sv->sv_id); - - if (ev->status || ev->mlength != sizeof(*msg) || - (msg->msg_type != type && - msg->msg_type != __swab32(type)) || - (msg->msg_magic != SRPC_MSG_MAGIC && - msg->msg_magic != __swab32(SRPC_MSG_MAGIC))) { - CERROR("Dropping RPC (%s) from %s: status %d mlength %d type %u magic %u.\n", - sv->sv_name, libcfs_id2str(ev->initiator), - ev->status, ev->mlength, - msg->msg_type, msg->msg_magic); - - /* - * 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(&scd->scd_rpc_free)) { - srpc = list_entry(scd->scd_rpc_free.next, - struct srpc_server_rpc, - srpc_list); - list_del(&srpc->srpc_list); - - srpc_init_server_rpc(srpc, scd, buffer); - list_add_tail(&srpc->srpc_list, - &scd->scd_rpc_active); - swi_schedule_workitem(&srpc->srpc_wi); - } else { - list_add_tail(&buffer->buf_list, - &scd->scd_buf_blocked); - } - - spin_unlock(&scd->scd_lock); - - spin_lock(&srpc_data.rpc_glock); - srpc_data.rpc_counters.rpcs_rcvd++; - spin_unlock(&srpc_data.rpc_glock); - break; - - case SRPC_BULK_GET_RPLD: - LASSERT(ev->type == LNET_EVENT_SEND || - ev->type == LNET_EVENT_REPLY || - ev->type == LNET_EVENT_UNLINK); - - if (!ev->unlinked) - break; /* wait for final event */ - /* fall through */ - case SRPC_BULK_PUT_SENT: - if (!ev->status && ev->type != LNET_EVENT_UNLINK) { - spin_lock(&srpc_data.rpc_glock); - - if (rpcev->ev_type == SRPC_BULK_GET_RPLD) - srpc_data.rpc_counters.bulk_get += ev->mlength; - else - srpc_data.rpc_counters.bulk_put += ev->mlength; - - spin_unlock(&srpc_data.rpc_glock); - } - /* fall through */ - case SRPC_REPLY_SENT: - srpc = rpcev->ev_data; - scd = srpc->srpc_scd; - - LASSERT(rpcev == &srpc->srpc_ev); - - spin_lock(&scd->scd_lock); - - rpcev->ev_fired = 1; - rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ? - -EINTR : ev->status; - swi_schedule_workitem(&srpc->srpc_wi); - - spin_unlock(&scd->scd_lock); - break; - } -} - -int -srpc_startup(void) -{ - int rc; - - memset(&srpc_data, 0, sizeof(struct smoketest_rpc)); - spin_lock_init(&srpc_data.rpc_glock); - - /* 1 second pause to avoid timestamp reuse */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - srpc_data.rpc_matchbits = ((__u64)ktime_get_real_seconds()) << 48; - - srpc_data.rpc_state = SRPC_STATE_NONE; - - rc = LNetNIInit(LNET_PID_LUSTRE); - if (rc < 0) { - CERROR("LNetNIInit() has failed: %d\n", rc); - return rc; - } - - srpc_data.rpc_state = SRPC_STATE_NI_INIT; - - LNetInvalidateEQHandle(&srpc_data.rpc_lnet_eq); - rc = LNetEQAlloc(0, srpc_lnet_ev_handler, &srpc_data.rpc_lnet_eq); - if (rc) { - CERROR("LNetEQAlloc() has failed: %d\n", rc); - goto bail; - } - - rc = LNetSetLazyPortal(SRPC_FRAMEWORK_REQUEST_PORTAL); - LASSERT(!rc); - rc = LNetSetLazyPortal(SRPC_REQUEST_PORTAL); - LASSERT(!rc); - - srpc_data.rpc_state = SRPC_STATE_EQ_INIT; - - rc = stt_startup(); - -bail: - if (rc) - srpc_shutdown(); - else - srpc_data.rpc_state = SRPC_STATE_RUNNING; - - return rc; -} - -void -srpc_shutdown(void) -{ - int i; - int rc; - int state; - - state = srpc_data.rpc_state; - srpc_data.rpc_state = SRPC_STATE_STOPPING; - - switch (state) { - default: - LBUG(); - case SRPC_STATE_RUNNING: - spin_lock(&srpc_data.rpc_glock); - - for (i = 0; i <= SRPC_SERVICE_MAX_ID; i++) { - struct srpc_service *sv = srpc_data.rpc_services[i]; - - LASSERTF(!sv, "service not empty: id %d, name %s\n", - i, sv->sv_name); - } - - spin_unlock(&srpc_data.rpc_glock); - - stt_shutdown(); - /* fall through */ - case SRPC_STATE_EQ_INIT: - rc = LNetClearLazyPortal(SRPC_FRAMEWORK_REQUEST_PORTAL); - rc = LNetClearLazyPortal(SRPC_REQUEST_PORTAL); - LASSERT(!rc); - rc = LNetEQFree(srpc_data.rpc_lnet_eq); - LASSERT(!rc); /* the EQ should have no user by now */ - /* fall through */ - case SRPC_STATE_NI_INIT: - LNetNIFini(); - } -} diff --git a/drivers/staging/lustre/lnet/selftest/rpc.h b/drivers/staging/lustre/lnet/selftest/rpc.h deleted file mode 100644 index 465b5b534423..000000000000 --- a/drivers/staging/lustre/lnet/selftest/rpc.h +++ /dev/null @@ -1,295 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#ifndef __SELFTEST_RPC_H__ -#define __SELFTEST_RPC_H__ - -#include <uapi/linux/lnet/lnetst.h> - -/* - * LST wired structures - * - * XXX: *REPLY == *REQST + 1 - */ -enum srpc_msg_type { - SRPC_MSG_MKSN_REQST = 0, - SRPC_MSG_MKSN_REPLY = 1, - SRPC_MSG_RMSN_REQST = 2, - SRPC_MSG_RMSN_REPLY = 3, - SRPC_MSG_BATCH_REQST = 4, - SRPC_MSG_BATCH_REPLY = 5, - SRPC_MSG_STAT_REQST = 6, - SRPC_MSG_STAT_REPLY = 7, - SRPC_MSG_TEST_REQST = 8, - SRPC_MSG_TEST_REPLY = 9, - SRPC_MSG_DEBUG_REQST = 10, - SRPC_MSG_DEBUG_REPLY = 11, - SRPC_MSG_BRW_REQST = 12, - SRPC_MSG_BRW_REPLY = 13, - SRPC_MSG_PING_REQST = 14, - SRPC_MSG_PING_REPLY = 15, - SRPC_MSG_JOIN_REQST = 16, - SRPC_MSG_JOIN_REPLY = 17, -}; - -/* CAVEAT EMPTOR: - * All srpc_*_reqst_t's 1st field must be matchbits of reply buffer, - * and 2nd field matchbits of bulk buffer if any. - * - * All srpc_*_reply_t's 1st field must be a __u32 status, and 2nd field - * session id if needed. - */ -struct srpc_generic_reqst { - __u64 rpyid; /* reply buffer matchbits */ - __u64 bulkid; /* bulk buffer matchbits */ -} WIRE_ATTR; - -struct srpc_generic_reply { - __u32 status; - struct lst_sid sid; -} WIRE_ATTR; - -/* FRAMEWORK RPCs */ -struct srpc_mksn_reqst { - __u64 mksn_rpyid; /* reply buffer matchbits */ - struct lst_sid mksn_sid; /* session id */ - __u32 mksn_force; /* use brute force */ - char mksn_name[LST_NAME_SIZE]; -} WIRE_ATTR; /* make session request */ - -struct srpc_mksn_reply { - __u32 mksn_status; /* session status */ - struct lst_sid mksn_sid; /* session id */ - __u32 mksn_timeout; /* session timeout */ - char mksn_name[LST_NAME_SIZE]; -} WIRE_ATTR; /* make session reply */ - -struct srpc_rmsn_reqst { - __u64 rmsn_rpyid; /* reply buffer matchbits */ - struct lst_sid rmsn_sid; /* session id */ -} WIRE_ATTR; /* remove session request */ - -struct srpc_rmsn_reply { - __u32 rmsn_status; - struct lst_sid rmsn_sid; /* session id */ -} WIRE_ATTR; /* remove session reply */ - -struct srpc_join_reqst { - __u64 join_rpyid; /* reply buffer matchbits */ - struct lst_sid join_sid; /* session id to join */ - char join_group[LST_NAME_SIZE]; /* group name */ -} WIRE_ATTR; - -struct srpc_join_reply { - __u32 join_status; /* returned status */ - struct lst_sid join_sid; /* session id */ - __u32 join_timeout; /* # seconds' inactivity to - * expire - */ - char join_session[LST_NAME_SIZE]; /* session name */ -} WIRE_ATTR; - -struct srpc_debug_reqst { - __u64 dbg_rpyid; /* reply buffer matchbits */ - struct lst_sid dbg_sid; /* session id */ - __u32 dbg_flags; /* bitmap of debug */ -} WIRE_ATTR; - -struct srpc_debug_reply { - __u32 dbg_status; /* returned code */ - struct lst_sid dbg_sid; /* session id */ - __u32 dbg_timeout; /* session timeout */ - __u32 dbg_nbatch; /* # of batches in the node */ - char dbg_name[LST_NAME_SIZE]; /* session name */ -} WIRE_ATTR; - -#define SRPC_BATCH_OPC_RUN 1 -#define SRPC_BATCH_OPC_STOP 2 -#define SRPC_BATCH_OPC_QUERY 3 - -struct srpc_batch_reqst { - __u64 bar_rpyid; /* reply buffer matchbits */ - struct lst_sid bar_sid; /* session id */ - struct lst_bid bar_bid; /* batch id */ - __u32 bar_opc; /* create/start/stop batch */ - __u32 bar_testidx; /* index of test */ - __u32 bar_arg; /* parameters */ -} WIRE_ATTR; - -struct srpc_batch_reply { - __u32 bar_status; /* status of request */ - struct lst_sid bar_sid; /* session id */ - __u32 bar_active; /* # of active tests in batch/test */ - __u32 bar_time; /* remained time */ -} WIRE_ATTR; - -struct srpc_stat_reqst { - __u64 str_rpyid; /* reply buffer matchbits */ - struct lst_sid str_sid; /* session id */ - __u32 str_type; /* type of stat */ -} WIRE_ATTR; - -struct srpc_stat_reply { - __u32 str_status; - struct lst_sid str_sid; - struct sfw_counters str_fw; - struct srpc_counters str_rpc; - struct lnet_counters str_lnet; -} WIRE_ATTR; - -struct test_bulk_req { - __u32 blk_opc; /* bulk operation code */ - __u32 blk_npg; /* # of pages */ - __u32 blk_flags; /* reserved flags */ -} WIRE_ATTR; - -struct test_bulk_req_v1 { - __u16 blk_opc; /* bulk operation code */ - __u16 blk_flags; /* data check flags */ - __u32 blk_len; /* data length */ - __u32 blk_offset; /* offset */ -} WIRE_ATTR; - -struct test_ping_req { - __u32 png_size; /* size of ping message */ - __u32 png_flags; /* reserved flags */ -} WIRE_ATTR; - -struct srpc_test_reqst { - __u64 tsr_rpyid; /* reply buffer matchbits */ - __u64 tsr_bulkid; /* bulk buffer matchbits */ - struct lst_sid tsr_sid; /* session id */ - struct lst_bid tsr_bid; /* batch id */ - __u32 tsr_service; /* test type: bulk|ping|... */ - __u32 tsr_loop; /* test client loop count or - * # server buffers needed - */ - __u32 tsr_concur; /* concurrency of test */ - __u8 tsr_is_client; /* is test client or not */ - __u8 tsr_stop_onerr; /* stop on error */ - __u32 tsr_ndest; /* # of dest nodes */ - - union { - struct test_ping_req ping; - struct test_bulk_req bulk_v0; - struct test_bulk_req_v1 bulk_v1; - } tsr_u; -} WIRE_ATTR; - -struct srpc_test_reply { - __u32 tsr_status; /* returned code */ - struct lst_sid tsr_sid; -} WIRE_ATTR; - -/* TEST RPCs */ -struct srpc_ping_reqst { - __u64 pnr_rpyid; - __u32 pnr_magic; - __u32 pnr_seq; - __u64 pnr_time_sec; - __u64 pnr_time_usec; -} WIRE_ATTR; - -struct srpc_ping_reply { - __u32 pnr_status; - __u32 pnr_magic; - __u32 pnr_seq; -} WIRE_ATTR; - -struct srpc_brw_reqst { - __u64 brw_rpyid; /* reply buffer matchbits */ - __u64 brw_bulkid; /* bulk buffer matchbits */ - __u32 brw_rw; /* read or write */ - __u32 brw_len; /* bulk data len */ - __u32 brw_flags; /* bulk data patterns */ -} WIRE_ATTR; /* bulk r/w request */ - -struct srpc_brw_reply { - __u32 brw_status; -} WIRE_ATTR; /* bulk r/w reply */ - -#define SRPC_MSG_MAGIC 0xeeb0f00d -#define SRPC_MSG_VERSION 1 - -struct srpc_msg { - __u32 msg_magic; /* magic number */ - __u32 msg_version; /* message version number */ - __u32 msg_type; /* type of message body: srpc_msg_type */ - __u32 msg_reserved0; - __u32 msg_reserved1; - __u32 msg_ses_feats; /* test session features */ - union { - struct srpc_generic_reqst reqst; - struct srpc_generic_reply reply; - - struct srpc_mksn_reqst mksn_reqst; - struct srpc_mksn_reply mksn_reply; - struct srpc_rmsn_reqst rmsn_reqst; - struct srpc_rmsn_reply rmsn_reply; - struct srpc_debug_reqst dbg_reqst; - struct srpc_debug_reply dbg_reply; - struct srpc_batch_reqst bat_reqst; - struct srpc_batch_reply bat_reply; - struct srpc_stat_reqst stat_reqst; - struct srpc_stat_reply stat_reply; - struct srpc_test_reqst tes_reqst; - struct srpc_test_reply tes_reply; - struct srpc_join_reqst join_reqst; - struct srpc_join_reply join_reply; - - struct srpc_ping_reqst ping_reqst; - struct srpc_ping_reply ping_reply; - struct srpc_brw_reqst brw_reqst; - struct srpc_brw_reply brw_reply; - } msg_body; -} WIRE_ATTR; - -static inline void -srpc_unpack_msg_hdr(struct srpc_msg *msg) -{ - if (msg->msg_magic == SRPC_MSG_MAGIC) - return; /* no flipping needed */ - - /* - * We do not swap the magic number here as it is needed to - * determine whether the body needs to be swapped. - */ - /* __swab32s(&msg->msg_magic); */ - __swab32s(&msg->msg_type); - __swab32s(&msg->msg_version); - __swab32s(&msg->msg_ses_feats); - __swab32s(&msg->msg_reserved0); - __swab32s(&msg->msg_reserved1); -} - -#endif /* __SELFTEST_RPC_H__ */ diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h deleted file mode 100644 index 05466b85e1c0..000000000000 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ /dev/null @@ -1,623 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/selftest.h - * - * Author: Isaac Huang <isaac@clusterfs.com> - */ -#ifndef __SELFTEST_SELFTEST_H__ -#define __SELFTEST_SELFTEST_H__ - -#define LNET_ONLY - -#include <linux/libcfs/libcfs.h> -#include <linux/lnet/lib-lnet.h> -#include <linux/lnet/lib-types.h> -#include <uapi/linux/lnet/lnetst.h> - -#include "rpc.h" -#include "timer.h" - -#ifndef MADE_WITHOUT_COMPROMISE -#define MADE_WITHOUT_COMPROMISE -#endif - -#define SWI_STATE_NEWBORN 0 -#define SWI_STATE_REPLY_SUBMITTED 1 -#define SWI_STATE_REPLY_SENT 2 -#define SWI_STATE_REQUEST_SUBMITTED 3 -#define SWI_STATE_REQUEST_SENT 4 -#define SWI_STATE_REPLY_RECEIVED 5 -#define SWI_STATE_BULK_STARTED 6 -#define SWI_STATE_DONE 10 - -/* forward refs */ -struct srpc_service; -struct srpc_service_cd; -struct sfw_test_unit; -struct sfw_test_instance; - -/* services below SRPC_FRAMEWORK_SERVICE_MAX_ID are framework - * services, e.g. create/modify session. - */ -#define SRPC_SERVICE_DEBUG 0 -#define SRPC_SERVICE_MAKE_SESSION 1 -#define SRPC_SERVICE_REMOVE_SESSION 2 -#define SRPC_SERVICE_BATCH 3 -#define SRPC_SERVICE_TEST 4 -#define SRPC_SERVICE_QUERY_STAT 5 -#define SRPC_SERVICE_JOIN 6 -#define SRPC_FRAMEWORK_SERVICE_MAX_ID 10 -/* other services start from SRPC_FRAMEWORK_SERVICE_MAX_ID+1 */ -#define SRPC_SERVICE_BRW 11 -#define SRPC_SERVICE_PING 12 -#define SRPC_SERVICE_MAX_ID 12 - -#define SRPC_REQUEST_PORTAL 50 -/* a lazy portal for framework RPC requests */ -#define SRPC_FRAMEWORK_REQUEST_PORTAL 51 -/* all reply/bulk RDMAs go to this portal */ -#define SRPC_RDMA_PORTAL 52 - -static inline enum srpc_msg_type -srpc_service2request(int service) -{ - switch (service) { - default: - LBUG(); - case SRPC_SERVICE_DEBUG: - return SRPC_MSG_DEBUG_REQST; - - case SRPC_SERVICE_MAKE_SESSION: - return SRPC_MSG_MKSN_REQST; - - case SRPC_SERVICE_REMOVE_SESSION: - return SRPC_MSG_RMSN_REQST; - - case SRPC_SERVICE_BATCH: - return SRPC_MSG_BATCH_REQST; - - case SRPC_SERVICE_TEST: - return SRPC_MSG_TEST_REQST; - - case SRPC_SERVICE_QUERY_STAT: - return SRPC_MSG_STAT_REQST; - - case SRPC_SERVICE_BRW: - return SRPC_MSG_BRW_REQST; - - case SRPC_SERVICE_PING: - return SRPC_MSG_PING_REQST; - - case SRPC_SERVICE_JOIN: - return SRPC_MSG_JOIN_REQST; - } -} - -static inline enum srpc_msg_type -srpc_service2reply(int service) -{ - return srpc_service2request(service) + 1; -} - -enum srpc_event_type { - SRPC_BULK_REQ_RCVD = 1, /* passive bulk request(PUT sink/GET source) - * received - */ - SRPC_BULK_PUT_SENT = 2, /* active bulk PUT sent (source) */ - SRPC_BULK_GET_RPLD = 3, /* active bulk GET replied (sink) */ - SRPC_REPLY_RCVD = 4, /* incoming reply received */ - SRPC_REPLY_SENT = 5, /* outgoing reply sent */ - SRPC_REQUEST_RCVD = 6, /* incoming request received */ - SRPC_REQUEST_SENT = 7, /* outgoing request sent */ -}; - -/* RPC event */ -struct srpc_event { - enum srpc_event_type ev_type; /* what's up */ - enum lnet_event_kind ev_lnet; /* LNet event type */ - int ev_fired; /* LNet event fired? */ - int ev_status; /* LNet event status */ - void *ev_data; /* owning server/client RPC */ -}; - -/* bulk descriptor */ -struct srpc_bulk { - int bk_len; /* len of bulk data */ - struct lnet_handle_md bk_mdh; - int bk_sink; /* sink/source */ - int bk_niov; /* # iov in bk_iovs */ - struct bio_vec bk_iovs[0]; -}; - -/* message buffer descriptor */ -struct srpc_buffer { - struct list_head buf_list; /* chain on srpc_service::*_msgq */ - struct srpc_msg buf_msg; - struct lnet_handle_md buf_mdh; - lnet_nid_t buf_self; - struct lnet_process_id buf_peer; -}; - -struct swi_workitem; -typedef void (*swi_action_t) (struct swi_workitem *); - -struct swi_workitem { - struct workqueue_struct *swi_wq; - struct work_struct swi_work; - swi_action_t swi_action; - int swi_state; -}; - -/* server-side state of a RPC */ -struct srpc_server_rpc { - /* chain on srpc_service::*_rpcq */ - struct list_head srpc_list; - struct srpc_service_cd *srpc_scd; - struct swi_workitem srpc_wi; - struct srpc_event srpc_ev; /* bulk/reply event */ - lnet_nid_t srpc_self; - struct lnet_process_id srpc_peer; - struct srpc_msg srpc_replymsg; - struct lnet_handle_md srpc_replymdh; - struct srpc_buffer *srpc_reqstbuf; - struct srpc_bulk *srpc_bulk; - - unsigned int srpc_aborted; /* being given up */ - int srpc_status; - void (*srpc_done)(struct srpc_server_rpc *); -}; - -/* client-side state of a RPC */ -struct srpc_client_rpc { - struct list_head crpc_list; /* chain on user's lists */ - spinlock_t crpc_lock; /* serialize */ - int crpc_service; - atomic_t crpc_refcount; - int crpc_timeout; /* # seconds to wait for reply */ - struct stt_timer crpc_timer; - struct swi_workitem crpc_wi; - struct lnet_process_id crpc_dest; - - void (*crpc_done)(struct srpc_client_rpc *); - void (*crpc_fini)(struct srpc_client_rpc *); - int crpc_status; /* completion status */ - void *crpc_priv; /* caller data */ - - /* state flags */ - unsigned int crpc_aborted:1; /* being given up */ - unsigned int crpc_closed:1; /* completed */ - - /* RPC events */ - struct srpc_event crpc_bulkev; /* bulk event */ - struct srpc_event crpc_reqstev; /* request event */ - struct srpc_event crpc_replyev; /* reply event */ - - /* bulk, request(reqst), and reply exchanged on wire */ - struct srpc_msg crpc_reqstmsg; - struct srpc_msg crpc_replymsg; - struct lnet_handle_md crpc_reqstmdh; - struct lnet_handle_md crpc_replymdh; - struct srpc_bulk crpc_bulk; -}; - -#define srpc_client_rpc_size(rpc) \ -offsetof(struct srpc_client_rpc, crpc_bulk.bk_iovs[(rpc)->crpc_bulk.bk_niov]) - -#define srpc_client_rpc_addref(rpc) \ -do { \ - CDEBUG(D_NET, "RPC[%p] -> %s (%d)++\n", \ - (rpc), libcfs_id2str((rpc)->crpc_dest), \ - atomic_read(&(rpc)->crpc_refcount)); \ - LASSERT(atomic_read(&(rpc)->crpc_refcount) > 0); \ - atomic_inc(&(rpc)->crpc_refcount); \ -} while (0) - -#define srpc_client_rpc_decref(rpc) \ -do { \ - CDEBUG(D_NET, "RPC[%p] -> %s (%d)--\n", \ - (rpc), libcfs_id2str((rpc)->crpc_dest), \ - atomic_read(&(rpc)->crpc_refcount)); \ - LASSERT(atomic_read(&(rpc)->crpc_refcount) > 0); \ - if (atomic_dec_and_test(&(rpc)->crpc_refcount)) \ - srpc_destroy_client_rpc(rpc); \ -} while (0) - -#define srpc_event_pending(rpc) (!(rpc)->crpc_bulkev.ev_fired || \ - !(rpc)->crpc_reqstev.ev_fired || \ - !(rpc)->crpc_replyev.ev_fired) - -/* CPU partition data of srpc service */ -struct srpc_service_cd { - /** serialize */ - spinlock_t scd_lock; - /** backref to service */ - struct srpc_service *scd_svc; - /** event buffer */ - struct srpc_event scd_ev; - /** free RPC descriptors */ - struct list_head scd_rpc_free; - /** in-flight RPCs */ - struct list_head scd_rpc_active; - /** workitem for posting buffer */ - struct swi_workitem scd_buf_wi; - /** CPT id */ - int scd_cpt; - /** error code for scd_buf_wi */ - int scd_buf_err; - /** timestamp for scd_buf_err */ - time64_t scd_buf_err_stamp; - /** total # request buffers */ - int scd_buf_total; - /** # posted request buffers */ - int scd_buf_nposted; - /** in progress of buffer posting */ - int scd_buf_posting; - /** allocate more buffers if scd_buf_nposted < scd_buf_low */ - int scd_buf_low; - /** increase/decrease some buffers */ - int scd_buf_adjust; - /** posted message buffers */ - struct list_head scd_buf_posted; - /** blocked for RPC descriptor */ - struct list_head scd_buf_blocked; -}; - -/* number of server workitems (mini-thread) for testing service */ -#define SFW_TEST_WI_MIN 256 -#define SFW_TEST_WI_MAX 2048 -/* extra buffers for tolerating buggy peers, or unbalanced number - * of peers between partitions - */ -#define SFW_TEST_WI_EXTRA 64 - -/* number of server workitems (mini-thread) for framework service */ -#define SFW_FRWK_WI_MIN 16 -#define SFW_FRWK_WI_MAX 256 - -struct srpc_service { - int sv_id; /* service id */ - const char *sv_name; /* human readable name */ - int sv_wi_total; /* total server workitems */ - int sv_shuttingdown; - int sv_ncpts; - /* percpt data for srpc_service */ - struct srpc_service_cd **sv_cpt_data; - /* Service callbacks: - * - sv_handler: process incoming RPC request - * - sv_bulk_ready: notify bulk data - */ - int (*sv_handler)(struct srpc_server_rpc *); - int (*sv_bulk_ready)(struct srpc_server_rpc *, int); -}; - -struct sfw_session { - struct list_head sn_list; /* chain on fw_zombie_sessions */ - struct lst_sid sn_id; /* unique identifier */ - unsigned int sn_timeout; /* # seconds' inactivity to expire */ - int sn_timer_active; - unsigned int sn_features; - struct stt_timer sn_timer; - struct list_head sn_batches; /* list of batches */ - char sn_name[LST_NAME_SIZE]; - atomic_t sn_refcount; - atomic_t sn_brw_errors; - atomic_t sn_ping_errors; - unsigned long sn_started; -}; - -#define sfw_sid_equal(sid0, sid1) ((sid0).ses_nid == (sid1).ses_nid && \ - (sid0).ses_stamp == (sid1).ses_stamp) - -struct sfw_batch { - struct list_head bat_list; /* chain on sn_batches */ - struct lst_bid bat_id; /* batch id */ - int bat_error; /* error code of batch */ - struct sfw_session *bat_session; /* batch's session */ - atomic_t bat_nactive; /* # of active tests */ - struct list_head bat_tests; /* test instances */ -}; - -struct sfw_test_client_ops { - int (*tso_init)(struct sfw_test_instance *tsi); /* initialize test - * client - */ - void (*tso_fini)(struct sfw_test_instance *tsi); /* finalize test - * client - */ - int (*tso_prep_rpc)(struct sfw_test_unit *tsu, - struct lnet_process_id dest, - struct srpc_client_rpc **rpc); /* prep a tests rpc */ - void (*tso_done_rpc)(struct sfw_test_unit *tsu, - struct srpc_client_rpc *rpc); /* done a test rpc */ -}; - -struct sfw_test_instance { - struct list_head tsi_list; /* chain on batch */ - int tsi_service; /* test type */ - struct sfw_batch *tsi_batch; /* batch */ - struct sfw_test_client_ops *tsi_ops; /* test client operation - */ - - /* public parameter for all test units */ - unsigned int tsi_is_client:1; /* is test client */ - unsigned int tsi_stoptsu_onerr:1; /* stop tsu on error */ - int tsi_concur; /* concurrency */ - int tsi_loop; /* loop count */ - - /* status of test instance */ - spinlock_t tsi_lock; /* serialize */ - unsigned int tsi_stopping:1; /* test is stopping */ - atomic_t tsi_nactive; /* # of active test - * unit - */ - struct list_head tsi_units; /* test units */ - struct list_head tsi_free_rpcs; /* free rpcs */ - struct list_head tsi_active_rpcs; /* active rpcs */ - - union { - struct test_ping_req ping; /* ping parameter */ - struct test_bulk_req bulk_v0; /* bulk parameter */ - struct test_bulk_req_v1 bulk_v1; /* bulk v1 parameter */ - } tsi_u; -}; - -/* - * XXX: trailing (PAGE_SIZE % sizeof(struct lnet_process_id)) bytes at the end - * of pages are not used - */ -#define SFW_MAX_CONCUR LST_MAX_CONCUR -#define SFW_ID_PER_PAGE (PAGE_SIZE / sizeof(struct lnet_process_id_packed)) -#define SFW_MAX_NDESTS (LNET_MAX_IOV * SFW_ID_PER_PAGE) -#define sfw_id_pages(n) (((n) + SFW_ID_PER_PAGE - 1) / SFW_ID_PER_PAGE) - -struct sfw_test_unit { - struct list_head tsu_list; /* chain on lst_test_instance */ - struct lnet_process_id tsu_dest; /* id of dest node */ - int tsu_loop; /* loop count of the test */ - struct sfw_test_instance *tsu_instance; /* pointer to test instance */ - void *tsu_private; /* private data */ - struct swi_workitem tsu_worker; /* workitem of the test unit */ -}; - -struct sfw_test_case { - struct list_head tsc_list; /* chain on fw_tests */ - struct srpc_service *tsc_srv_service; /* test service */ - struct sfw_test_client_ops *tsc_cli_ops; /* ops of test client */ -}; - -struct srpc_client_rpc * -sfw_create_rpc(struct lnet_process_id peer, int service, - unsigned int features, int nbulkiov, int bulklen, - void (*done)(struct srpc_client_rpc *), void *priv); -int sfw_create_test_rpc(struct sfw_test_unit *tsu, - struct lnet_process_id peer, unsigned int features, - int nblk, int blklen, struct srpc_client_rpc **rpc); -void sfw_abort_rpc(struct srpc_client_rpc *rpc); -void sfw_post_rpc(struct srpc_client_rpc *rpc); -void sfw_client_rpc_done(struct srpc_client_rpc *rpc); -void sfw_unpack_message(struct srpc_msg *msg); -void sfw_free_pages(struct srpc_server_rpc *rpc); -void sfw_add_bulk_page(struct srpc_bulk *bk, struct page *pg, int i); -int sfw_alloc_pages(struct srpc_server_rpc *rpc, int cpt, int npages, int len, - int sink); -int sfw_make_session(struct srpc_mksn_reqst *request, - struct srpc_mksn_reply *reply); - -struct srpc_client_rpc * -srpc_create_client_rpc(struct lnet_process_id peer, int service, - int nbulkiov, int bulklen, - void (*rpc_done)(struct srpc_client_rpc *), - void (*rpc_fini)(struct srpc_client_rpc *), void *priv); -void srpc_post_rpc(struct srpc_client_rpc *rpc); -void srpc_abort_rpc(struct srpc_client_rpc *rpc, int why); -void srpc_free_bulk(struct srpc_bulk *bk); -struct srpc_bulk *srpc_alloc_bulk(int cpt, unsigned int off, - unsigned int bulk_npg, unsigned int bulk_len, - int sink); -void srpc_send_rpc(struct swi_workitem *wi); -int srpc_send_reply(struct srpc_server_rpc *rpc); -int srpc_add_service(struct srpc_service *sv); -int srpc_remove_service(struct srpc_service *sv); -void srpc_shutdown_service(struct srpc_service *sv); -void srpc_abort_service(struct srpc_service *sv); -int srpc_finish_service(struct srpc_service *sv); -int srpc_service_add_buffers(struct srpc_service *sv, int nbuffer); -void srpc_service_remove_buffers(struct srpc_service *sv, int nbuffer); -void srpc_get_counters(struct srpc_counters *cnt); -void srpc_set_counters(const struct srpc_counters *cnt); - -extern struct workqueue_struct *lst_serial_wq; -extern struct workqueue_struct **lst_test_wq; - -static inline int -srpc_serv_is_framework(struct srpc_service *svc) -{ - return svc->sv_id < SRPC_FRAMEWORK_SERVICE_MAX_ID; -} - -static void -swi_wi_action(struct work_struct *wi) -{ - struct swi_workitem *swi; - - swi = container_of(wi, struct swi_workitem, swi_work); - - swi->swi_action(swi); -} - -static inline void -swi_init_workitem(struct swi_workitem *swi, - swi_action_t action, struct workqueue_struct *wq) -{ - swi->swi_wq = wq; - swi->swi_action = action; - swi->swi_state = SWI_STATE_NEWBORN; - INIT_WORK(&swi->swi_work, swi_wi_action); -} - -static inline void -swi_schedule_workitem(struct swi_workitem *wi) -{ - queue_work(wi->swi_wq, &wi->swi_work); -} - -static inline int -swi_cancel_workitem(struct swi_workitem *swi) -{ - return cancel_work_sync(&swi->swi_work); -} - -int sfw_startup(void); -int srpc_startup(void); -void sfw_shutdown(void); -void srpc_shutdown(void); - -static inline void -srpc_destroy_client_rpc(struct srpc_client_rpc *rpc) -{ - LASSERT(rpc); - LASSERT(!srpc_event_pending(rpc)); - LASSERT(!atomic_read(&rpc->crpc_refcount)); - - if (!rpc->crpc_fini) - kfree(rpc); - else - (*rpc->crpc_fini)(rpc); -} - -static inline void -srpc_init_client_rpc(struct srpc_client_rpc *rpc, struct lnet_process_id peer, - int service, int nbulkiov, int bulklen, - void (*rpc_done)(struct srpc_client_rpc *), - void (*rpc_fini)(struct srpc_client_rpc *), void *priv) -{ - LASSERT(nbulkiov <= LNET_MAX_IOV); - - memset(rpc, 0, offsetof(struct srpc_client_rpc, - crpc_bulk.bk_iovs[nbulkiov])); - - INIT_LIST_HEAD(&rpc->crpc_list); - swi_init_workitem(&rpc->crpc_wi, srpc_send_rpc, - lst_test_wq[lnet_cpt_of_nid(peer.nid)]); - spin_lock_init(&rpc->crpc_lock); - atomic_set(&rpc->crpc_refcount, 1); /* 1 ref for caller */ - - rpc->crpc_dest = peer; - rpc->crpc_priv = priv; - rpc->crpc_service = service; - rpc->crpc_bulk.bk_len = bulklen; - rpc->crpc_bulk.bk_niov = nbulkiov; - rpc->crpc_done = rpc_done; - rpc->crpc_fini = rpc_fini; - LNetInvalidateMDHandle(&rpc->crpc_reqstmdh); - LNetInvalidateMDHandle(&rpc->crpc_replymdh); - LNetInvalidateMDHandle(&rpc->crpc_bulk.bk_mdh); - - /* no event is expected at this point */ - rpc->crpc_bulkev.ev_fired = 1; - rpc->crpc_reqstev.ev_fired = 1; - rpc->crpc_replyev.ev_fired = 1; - - rpc->crpc_reqstmsg.msg_magic = SRPC_MSG_MAGIC; - rpc->crpc_reqstmsg.msg_version = SRPC_MSG_VERSION; - rpc->crpc_reqstmsg.msg_type = srpc_service2request(service); -} - -static inline const char * -swi_state2str(int state) -{ -#define STATE2STR(x) case x: return #x - switch (state) { - default: - LBUG(); - STATE2STR(SWI_STATE_NEWBORN); - STATE2STR(SWI_STATE_REPLY_SUBMITTED); - STATE2STR(SWI_STATE_REPLY_SENT); - STATE2STR(SWI_STATE_REQUEST_SUBMITTED); - STATE2STR(SWI_STATE_REQUEST_SENT); - STATE2STR(SWI_STATE_REPLY_RECEIVED); - STATE2STR(SWI_STATE_BULK_STARTED); - STATE2STR(SWI_STATE_DONE); - } -#undef STATE2STR -} - -#define selftest_wait_events() \ - do { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - schedule_timeout(HZ / 10); \ - } while (0) - -#define lst_wait_until(cond, lock, fmt, ...) \ -do { \ - int __I = 2; \ - while (!(cond)) { \ - CDEBUG(is_power_of_2(++__I) ? D_WARNING : D_NET, \ - fmt, ## __VA_ARGS__); \ - spin_unlock(&(lock)); \ - \ - selftest_wait_events(); \ - \ - spin_lock(&(lock)); \ - } \ -} while (0) - -static inline void -srpc_wait_service_shutdown(struct srpc_service *sv) -{ - int i = 2; - - LASSERT(sv->sv_shuttingdown); - - while (!srpc_finish_service(sv)) { - i++; - CDEBUG(((i & -i) == i) ? D_WARNING : D_NET, - "Waiting for %s service to shutdown...\n", - sv->sv_name); - selftest_wait_events(); - } -} - -extern struct sfw_test_client_ops brw_test_client; -void brw_init_test_client(void); - -extern struct srpc_service brw_test_service; -void brw_init_test_service(void); - -extern struct sfw_test_client_ops ping_test_client; -void ping_init_test_client(void); - -extern struct srpc_service ping_test_service; -void ping_init_test_service(void); - -#endif /* __SELFTEST_SELFTEST_H__ */ diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c deleted file mode 100644 index 1b2c5fc81358..000000000000 --- a/drivers/staging/lustre/lnet/selftest/timer.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lnet/selftest/timer.c - * - * Author: Isaac Huang <isaac@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_LNET - -#include "selftest.h" - -/* - * Timers are implemented as a sorted queue of expiry times. The queue - * is slotted, with each slot holding timers which expire in a - * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are - * sorted by increasing expiry time. The number of slots is 2**7 (128), - * to cover a time period of 1024 seconds into the future before wrapping. - */ -#define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */ -#define STTIMER_SLOTTIME BIT(STTIMER_MINPOLL) -#define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1)) -#define STTIMER_NSLOTS BIT(7) -#define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \ - (STTIMER_NSLOTS - 1))]) - -static struct st_timer_data { - spinlock_t stt_lock; - unsigned long stt_prev_slot; /* start time of the slot processed - * previously - */ - struct list_head stt_hash[STTIMER_NSLOTS]; - int stt_shuttingdown; - wait_queue_head_t stt_waitq; - int stt_nthreads; -} stt_data; - -void -stt_add_timer(struct stt_timer *timer) -{ - struct list_head *pos; - - spin_lock(&stt_data.stt_lock); - - LASSERT(stt_data.stt_nthreads > 0); - LASSERT(!stt_data.stt_shuttingdown); - LASSERT(timer->stt_func); - LASSERT(list_empty(&timer->stt_list)); - LASSERT(timer->stt_expires > ktime_get_real_seconds()); - - /* a simple insertion sort */ - list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) { - struct stt_timer *old = list_entry(pos, struct stt_timer, - stt_list); - - if (timer->stt_expires >= old->stt_expires) - break; - } - list_add(&timer->stt_list, pos); - - spin_unlock(&stt_data.stt_lock); -} - -/* - * The function returns whether it has deactivated a pending timer or not. - * (ie. del_timer() of an inactive timer returns 0, del_timer() of an - * active timer returns 1.) - * - * CAVEAT EMPTOR: - * When 0 is returned, it is possible that timer->stt_func _is_ running on - * another CPU. - */ -int -stt_del_timer(struct stt_timer *timer) -{ - int ret = 0; - - spin_lock(&stt_data.stt_lock); - - LASSERT(stt_data.stt_nthreads > 0); - LASSERT(!stt_data.stt_shuttingdown); - - if (!list_empty(&timer->stt_list)) { - ret = 1; - list_del_init(&timer->stt_list); - } - - spin_unlock(&stt_data.stt_lock); - return ret; -} - -/* called with stt_data.stt_lock held */ -static int -stt_expire_list(struct list_head *slot, time64_t now) -{ - int expired = 0; - struct stt_timer *timer; - - while (!list_empty(slot)) { - timer = list_entry(slot->next, struct stt_timer, stt_list); - - if (timer->stt_expires > now) - break; - - list_del_init(&timer->stt_list); - spin_unlock(&stt_data.stt_lock); - - expired++; - (*timer->stt_func) (timer->stt_data); - - spin_lock(&stt_data.stt_lock); - } - - return expired; -} - -static int -stt_check_timers(unsigned long *last) -{ - int expired = 0; - time64_t now; - unsigned long this_slot; - - now = ktime_get_real_seconds(); - this_slot = now & STTIMER_SLOTTIMEMASK; - - spin_lock(&stt_data.stt_lock); - - while (cfs_time_aftereq(this_slot, *last)) { - expired += stt_expire_list(STTIMER_SLOT(this_slot), now); - this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME); - } - - *last = now & STTIMER_SLOTTIMEMASK; - spin_unlock(&stt_data.stt_lock); - return expired; -} - -static int -stt_timer_main(void *arg) -{ - int rc = 0; - - while (!stt_data.stt_shuttingdown) { - stt_check_timers(&stt_data.stt_prev_slot); - - rc = wait_event_timeout(stt_data.stt_waitq, - stt_data.stt_shuttingdown, - STTIMER_SLOTTIME * HZ); - } - - spin_lock(&stt_data.stt_lock); - stt_data.stt_nthreads--; - spin_unlock(&stt_data.stt_lock); - return rc; -} - -static int -stt_start_timer_thread(void) -{ - struct task_struct *task; - - LASSERT(!stt_data.stt_shuttingdown); - - task = kthread_run(stt_timer_main, NULL, "st_timer"); - if (IS_ERR(task)) - return PTR_ERR(task); - - spin_lock(&stt_data.stt_lock); - stt_data.stt_nthreads++; - spin_unlock(&stt_data.stt_lock); - return 0; -} - -int -stt_startup(void) -{ - int rc = 0; - int i; - - stt_data.stt_shuttingdown = 0; - stt_data.stt_prev_slot = ktime_get_real_seconds() & STTIMER_SLOTTIMEMASK; - - spin_lock_init(&stt_data.stt_lock); - for (i = 0; i < STTIMER_NSLOTS; i++) - INIT_LIST_HEAD(&stt_data.stt_hash[i]); - - stt_data.stt_nthreads = 0; - init_waitqueue_head(&stt_data.stt_waitq); - rc = stt_start_timer_thread(); - if (rc) - CERROR("Can't spawn timer thread: %d\n", rc); - - return rc; -} - -void -stt_shutdown(void) -{ - int i; - - spin_lock(&stt_data.stt_lock); - - for (i = 0; i < STTIMER_NSLOTS; i++) - LASSERT(list_empty(&stt_data.stt_hash[i])); - - stt_data.stt_shuttingdown = 1; - - wake_up(&stt_data.stt_waitq); - lst_wait_until(!stt_data.stt_nthreads, stt_data.stt_lock, - "waiting for %d threads to terminate\n", - stt_data.stt_nthreads); - - spin_unlock(&stt_data.stt_lock); -} diff --git a/drivers/staging/lustre/lnet/selftest/timer.h b/drivers/staging/lustre/lnet/selftest/timer.h deleted file mode 100644 index 7f0ef9bd0cda..000000000000 --- a/drivers/staging/lustre/lnet/selftest/timer.h +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 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) 2007, 2010, Oracle and/or its affiliates. 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/timer.h - * - * Author: Isaac Huang <isaac@clusterfs.com> - */ -#ifndef __SELFTEST_TIMER_H__ -#define __SELFTEST_TIMER_H__ - -struct stt_timer { - struct list_head stt_list; - time64_t stt_expires; - void (*stt_func)(void *); - void *stt_data; -}; - -void stt_add_timer(struct stt_timer *timer); -int stt_del_timer(struct stt_timer *timer); -int stt_startup(void); -void stt_shutdown(void); - -#endif /* __SELFTEST_TIMER_H__ */ |