1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/conf.h" 8 #include "spdk/event.h" 9 #include "spdk/vhost.h" 10 #include "spdk/json.h" 11 #include "spdk/jsonrpc.h" 12 #include "spdk/rpc.h" 13 #include "spdk/env.h" 14 #include "spdk/scheduler.h" 15 16 #include "spdk_internal/event.h" 17 18 struct rpc_reactor_set_interrupt_mode { 19 int32_t lcore; 20 bool disable_interrupt; 21 int rc; 22 struct spdk_thread *rpc_thread; 23 struct spdk_jsonrpc_request *request; 24 }; 25 26 static const struct spdk_json_object_decoder rpc_reactor_set_interrupt_mode_decoders[] = { 27 {"lcore", offsetof(struct rpc_reactor_set_interrupt_mode, lcore), spdk_json_decode_int32}, 28 {"disable_interrupt", offsetof(struct rpc_reactor_set_interrupt_mode, disable_interrupt), spdk_json_decode_bool}, 29 }; 30 31 static void 32 rpc_reactor_set_interrupt_mode_cb(void *cb_arg) 33 { 34 struct rpc_reactor_set_interrupt_mode *req = cb_arg; 35 36 SPDK_NOTICELOG("complete reactor switch\n"); 37 38 spdk_jsonrpc_send_bool_response(req->request, true); 39 free(req); 40 } 41 42 static void 43 set_interrupt_mode_cb(void *arg1, void *arg2) 44 { 45 struct rpc_reactor_set_interrupt_mode *req = arg1; 46 47 spdk_thread_send_msg(req->rpc_thread, rpc_reactor_set_interrupt_mode_cb, req); 48 } 49 50 static void 51 set_interrupt_mode(void *arg1, void *arg2) 52 { 53 struct rpc_reactor_set_interrupt_mode *req = arg1; 54 int rc; 55 56 rc = spdk_reactor_set_interrupt_mode(req->lcore, !req->disable_interrupt, 57 set_interrupt_mode_cb, req); 58 if (rc) { 59 req->rc = rc; 60 set_interrupt_mode_cb(req, NULL); 61 } 62 } 63 64 static void 65 rpc_reactor_set_interrupt_mode(struct spdk_jsonrpc_request *request, 66 const struct spdk_json_val *params) 67 { 68 struct rpc_reactor_set_interrupt_mode *req; 69 70 req = calloc(1, sizeof(*req)); 71 if (req == NULL) { 72 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 73 "Out of memory"); 74 return; 75 } 76 77 req->request = request; 78 req->rpc_thread = spdk_get_thread(); 79 80 if (spdk_json_decode_object(params, rpc_reactor_set_interrupt_mode_decoders, 81 SPDK_COUNTOF(rpc_reactor_set_interrupt_mode_decoders), 82 req)) { 83 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 84 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 85 "spdk_json_decode_object failed"); 86 free(req); 87 return; 88 } 89 90 if (!spdk_interrupt_mode_is_enabled()) { 91 SPDK_ERRLOG("Interrupt mode is not set when staring the application\n"); 92 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 93 "spdk_json_decode_object failed"); 94 free(req); 95 return; 96 } 97 98 99 SPDK_NOTICELOG("RPC Start to %s interrupt mode on reactor %d.\n", 100 req->disable_interrupt ? "disable" : "enable", req->lcore); 101 if (req->lcore >= (int64_t)spdk_env_get_first_core() && 102 req->lcore <= (int64_t)spdk_env_get_last_core()) { 103 struct spdk_event *e; 104 105 e = spdk_event_allocate(spdk_scheduler_get_scheduling_lcore(), 106 set_interrupt_mode, req, NULL); 107 spdk_event_call(e); 108 } else { 109 free(req); 110 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 111 "Invalid parameters"); 112 } 113 } 114 /* private */ SPDK_RPC_REGISTER("reactor_set_interrupt_mode", rpc_reactor_set_interrupt_mode, 115 SPDK_RPC_RUNTIME) 116 117 static void 118 interrupt_tgt_usage(void) 119 { 120 printf(" -E Set interrupt mode\n"); 121 printf(" -S <path> directory where to create vhost sockets (default: pwd)\n"); 122 } 123 124 static int 125 interrupt_tgt_parse_arg(int ch, char *arg) 126 { 127 switch (ch) { 128 case 'S': 129 spdk_vhost_set_socket_path(arg); 130 break; 131 case 'E': 132 spdk_interrupt_mode_enable(); 133 break; 134 default: 135 return -EINVAL; 136 } 137 return 0; 138 } 139 140 static void 141 interrupt_tgt_started(void *arg1) 142 { 143 } 144 145 int 146 main(int argc, char *argv[]) 147 { 148 struct spdk_app_opts opts = {}; 149 int rc; 150 151 spdk_app_opts_init(&opts, sizeof(opts)); 152 opts.name = "interrupt_tgt"; 153 154 if ((rc = spdk_app_parse_args(argc, argv, &opts, "S:E", NULL, 155 interrupt_tgt_parse_arg, interrupt_tgt_usage)) != 156 SPDK_APP_PARSE_ARGS_SUCCESS) { 157 exit(rc); 158 } 159 160 /* Blocks until the application is exiting */ 161 rc = spdk_app_start(&opts, interrupt_tgt_started, NULL); 162 163 spdk_app_fini(); 164 165 return rc; 166 } 167