/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_prv_data) { struct xio_msg *rsp; struct thread_data *tdata = (struct thread_data *)cb_prv_data; /* process request */ process_request(tdata, req); /* alloc transaction */ rsp = msg_pool_get(tdata->pool); rsp->request = req; /* fill response */ msg_build_out_sgl(&msg_prms, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, req); /* better to do disconnect */ /*xio_disconnect(tdata->conn);*/ xio_assert(0); } tdata->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct xio_msg *rsp; /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_write(&msg_params, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_prv_data) { struct xio_msg *rsp; if (req->status) printf("**** request completed with error. [%s]\n", xio_strerror(req->status)); /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_set(rsp, 0, test_config.hdr_len, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_prv_data) { struct xio_msg *rsp; struct thread_data *tdata = cb_prv_data; /* alloc transaction */ rsp = msg_pool_get(tdata->pool); /* fill response */ rsp->request = req; rsp->more_in_batch = more_in_batch; rsp->in.header.iov_len = 0; rsp->out.header.iov_len = 0; vmsg_sglist_set_nents(&rsp->in, 0); if (tdata->user_param->verb == READ) vmsg_sglist_set_nents(&rsp->out, 0); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, req); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_user_context) { struct server_data *server_data = (struct server_data *)cb_user_context; int i = req->sn % QUEUE_DEPTH; /* process request */ process_request(server_data, req); /* attach request to response */ server_data->rsp[i].request = req; xio_send_response(&server_data->rsp[i]); server_data->nsent++; if (test_disconnect) { if (server_data->nsent == DISCONNECT_NR) { xio_disconnect(server_data->connection); return 0; } } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_prv_data) { struct xio_msg *rsp; /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; /* fill response */ msg_build_out_sgl(&msg_params, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, req); xio_assert(0); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_cmd_submit_comp(struct raio_io_cmd *iocmd) { struct raio_io_u *io_u = iocmd->user_context; struct raio_answer ans = { RAIO_CMD_IO_SUBMIT, 0, 0, 0 }; pack_u32((uint32_t *)&iocmd->res2, pack_u32((uint32_t *)&iocmd->res, pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, io_u->rsp->out.header.iov_base)))))); io_u->rsp->out.header.iov_len = sizeof(struct raio_answer) + 2*sizeof(uint32_t); if (iocmd->res != iocmd->bcount) { if (iocmd->res < iocmd->bcount) { io_u->rsp->out.data_iov[0].iov_len = iocmd->res; } else { io_u->rsp->out.data_iovlen = 0; io_u->rsp->out.data_iov[0].iov_len = iocmd->res; } } else { io_u->rsp->out.data_iov[0].iov_len = iocmd->bcount; } xio_send_response(io_u->rsp); return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct thread_data *tdata = cb_user_context; int i = req->sn % QUEUE_DEPTH; /* process request */ process_request(tdata, req); /* attach request to response */ tdata->rsp[i].request = req; xio_send_response(&tdata->rsp[i]); tdata->nsent++; #if TEST_DISCONNECT if (tdata->nsent == DISCONNECT_NR) { struct xio_connection *connection = xio_get_connection(session,tdata->ctx); xio_disconnect(connection); return 0; } #endif return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_user_context) { struct server_data *server_data = (struct server_data *)cb_user_context; struct xio_msg *rsp = ring_get_next_msg(server_data); /* process request */ process_request(server_data, req); /* attach request to response */ rsp->request = req; xio_send_response(rsp); server_data->nsent++; if (test_disconnect) { if (server_data->nsent == DISCONNECT_NR) { xio_disconnect(server_data->connection); return 0; } } return 0; }
/*---------------------------------------------------------------------------*/ static int raio_handle_close(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { struct raio_io_session_data *sd = prv_session_data; struct raio_io_portal_data *pd = prv_portal_data; int fd; int retval = 0; unpack_u32((uint32_t *)&fd, cmd_data); if (sizeof(fd) != cmd->data_len) { retval = -1; errno = EINVAL; printf("open request rejected\n"); goto reject; } if (!sd->is_null) retval = close(fd); reject: if (retval != 0) { struct raio_answer ans = { RAIO_CMD_CLOSE, 0, -1, errno }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); } else { struct raio_answer ans = { RAIO_CMD_CLOSE, 0, 0, 0 }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); } pd->close_rsp.out.header.iov_len = sizeof(struct raio_answer); pd->close_rsp.out.header.iov_base = pd->rsp_hdr; pd->close_rsp.out.data_iovlen = 0; pd->close_rsp.request = req; xio_send_response(&pd->close_rsp); return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct hw_thread_data *tdata = cb_user_context; int i = req->sn % QUEUE_DEPTH; /* process request */ process_request(tdata, req); /* attach request to response */ tdata->rsp[i].request = req; xio_send_response(&tdata->rsp[i]); return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_user_context) { struct server_data *server_data = cb_user_context; int i = req->sn % QUEUE_DEPTH; /* process request */ process_request(req); /* attach request to response */ server_data->rsp[i].request = req; xio_send_response(&server_data->rsp[i]); return 0; }
main_fn void xio_send_reply(struct client_info *ci) { struct request *req; struct xio_msg xrsp; req = list_first_entry(&ci->done_reqs, struct request, request_list); list_del(&req->request_list); memset(&xrsp, 0, sizeof(xrsp)); server_msg_vec_init(&xrsp); msg_prep_for_reply(&req->rp, req->data, &xrsp); xrsp.request = ci->xio_req; xio_send_response(&xrsp); xio_context_run_loop(xio_get_main_ctx(), XIO_INFINITE); req->data = NULL; /* the data is owned by xio */ free_request(req); }
/*---------------------------------------------------------------------------*/ int raio_reject_request(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { struct raio_io_portal_data *pd = prv_portal_data; struct raio_answer ans = { RAIO_CMD_UNKNOWN, 0, -1, errno }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); pd->rsp.out.header.iov_len = sizeof(struct raio_answer); pd->rsp.out.data_iovlen = 0; pd->rsp.request = req; xio_send_response(&pd->rsp); return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct xio_msg *rsp; struct test_params *test_params = cb_user_context; if (req->status) printf("**** request completed with error. [%s]\n", xio_strerror(req->status)); /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(test_params->pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_write(&test_params->msg_params, rsp, NULL, test_config.hdr_len, NULL, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(test_params->pool, req); } test_params->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int raio_handle_submit(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { struct raio_io_portal_data *pd = prv_portal_data; struct raio_io_session_data *sd = prv_session_data; struct raio_io_u *io_u; struct raio_iocb iocb; struct raio_answer ans; int retval; uint32_t is_last_in_batch; uint32_t msg_sz = SUBMIT_BLOCK_SIZE + sizeof(uint32_t); io_u = TAILQ_FIRST(&pd->io_u_free_list); if (!io_u) { printf("io_u_free_list empty\n"); errno = ENOSR; return -1; } TAILQ_REMOVE(&pd->io_u_free_list, io_u, io_u_list); msg_reset(io_u->rsp); pd->io_u_free_nr--; if (msg_sz != cmd->data_len) { retval = EINVAL; printf("io submit request rejected\n"); goto reject; } unpack_iocb(&iocb, unpack_u32(&is_last_in_batch, cmd_data)); io_u->iocmd.fd = iocb.raio_fildes; io_u->iocmd.op = iocb.raio_lio_opcode; io_u->iocmd.bcount = iocb.u.c.nbytes; io_u->iocmd.buf = io_u->rsp->out.data_iov[0].iov_base; io_u->iocmd.mr = io_u->rsp->out.data_iov[0].mr; io_u->iocmd.fsize = sd->fsize; io_u->iocmd.offset = iocb.u.c.offset; io_u->iocmd.is_last_in_batch = is_last_in_batch; io_u->iocmd.res = 0; io_u->iocmd.res2 = 0; io_u->iocmd.user_context = io_u; io_u->iocmd.comp_cb = on_cmd_submit_comp; io_u->rsp->request = req; io_u->rsp->user_context = io_u; io_u->rsp->out.data_iovlen = 1; /* issues request to bs */ retval = -raio_bs_cmd_submit(pd->bs_dev, &io_u->iocmd); if (retval) goto reject; return 0; reject: TAILQ_INSERT_TAIL(&pd->io_u_free_list, io_u, io_u_list); pd->io_u_free_nr++; msg_reset(&pd->rsp); ans.command = RAIO_CMD_IO_SUBMIT; ans.data_len = 0; ans.ret = -1; ans.ret_errno = retval; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); pd->rsp.out.header.iov_len = sizeof(struct raio_answer); pd->rsp.request = req; xio_send_response(&pd->rsp); return 0; }
static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_user_context) { struct xio_msg *rsp; struct io_worker_data *wdata; struct xio_iovec_ex *in_sglist; struct xio_iovec_ex *out_sglist; struct rdb_req_hdr *req_hdr; void *ptr; int *status; char *value; size_t key_size, value_size; // int len; wdata = cb_user_context; rsp = &wdata->rsp; in_sglist = vmsg_sglist(&req->in); req_hdr = in_sglist[0].iov_base; ptr = in_sglist[0].iov_base; ptr += sizeof (*req_hdr); switch (req_hdr->rdb_command) { case RDB_CMD_PUT: { struct rdb_put_req_hdr *put_hdr; put_hdr = ptr; struct __attribute__((__packed__)) rdb_put_req { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[put_hdr->key_size]; } key; struct rdb_value { struct rdb_value_hdr value_hdr; char value_data[put_hdr->value_size]; } value; } *put_req; ptr += sizeof (*put_hdr); put_req = ptr; key_size = sizeof (struct rdb_key); value_size = sizeof (struct rdb_value); if (!null_mode) if (!rocksdb_server_put(wdata->rdb, (char *)&put_req->key, &key_size, (char *)&put_req->value, &value_size)) { fprintf(stderr, "rocksdb put failed\n"); } // len = (int) in_sglist[0].iov_len; break; } case RDB_CMD_MPUT: { struct rdb_mput_req_hdr *mput_hdr; char *records; mput_hdr = ptr; struct __attribute__((__packed__)) rdb_mput_req { struct multi_kv_pairs { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[mput_hdr->key_size]; } key; struct rdb_value { struct rdb_value_hdr value_hdr; char value_data[mput_hdr->value_size]; } value; } m_kv_pairs[mput_hdr->num_records]; } *mput_req; ptr += sizeof (*mput_hdr); mput_req = ptr; key_size = sizeof (struct rdb_key); value_size = sizeof (struct rdb_value); records = (char *)mput_req->m_kv_pairs; if (!null_mode) if (!rocksdb_server_mput(wdata->rdb, records, &key_size, &value_size, &mput_hdr->num_records)) { fprintf(stderr, "rocksdb mput failed\n"); } // len = (int) in_sglist[0].iov_len; break; } case RDB_CMD_GET: { struct rdb_get_req_hdr *get_hdr; get_hdr = ptr; struct __attribute__((__packed__)) rdb_get_req { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[get_hdr->key_size]; } key; } *get_req; ptr += sizeof (*get_hdr); get_req = ptr; key_size = sizeof (get_req->key); out_sglist = vmsg_sglist(&rsp->out); out_sglist[0].iov_base = wdata->reg_mem.addr; out_sglist[0].mr = wdata->reg_mem.mr; if (!null_mode) { status = wdata->reg_mem.addr; value = wdata->reg_mem.addr + sizeof (*status); *status = rocksdb_server_get(wdata->rdb, (char *)&get_req->key, &key_size, value, &value_size); if (*status) out_sglist[0].iov_len = value_size + sizeof (*status); else out_sglist[0].iov_len = sizeof (*status); } else { status = wdata->reg_mem.addr; *status = 1; out_sglist[0].iov_len = sizeof (*status); } // len = (int) out_sglist[0].iov_len; vmsg_sglist_set_nents(&rsp->out, 1); break; } case RDB_CMD_MGET: { struct rdb_mget_req_hdr *mget_hdr; char *records; mget_hdr = ptr; struct __attribute__((__packed__)) rdb_mget_req { struct multi_k_pairs { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[mget_hdr->key_size]; } key; } m_k_pairs[mget_hdr->num_records]; } *mget_req; ptr += sizeof (*mget_hdr); mget_req = ptr; key_size = sizeof (struct rdb_key); records = (char *) mget_req->m_k_pairs; out_sglist = vmsg_sglist(&rsp->out); out_sglist[0].iov_base = wdata->reg_mem.addr; out_sglist[0].mr = wdata->reg_mem.mr; if (!null_mode) { status = wdata->reg_mem.addr; value = wdata->reg_mem.addr + sizeof (*status); *status = rocksdb_server_mget(wdata->rdb, records, &key_size, value, &value_size, &mget_hdr->num_records); if (*status) out_sglist[0].iov_len = value_size + sizeof (*status); else out_sglist[0].iov_len = sizeof (*status); } else { status = wdata->reg_mem.addr; *status = 1; out_sglist[0].iov_len = sizeof (*status); } // len = (int) out_sglist[0].iov_len; vmsg_sglist_set_nents(&rsp->out, 1); break; } default: break; }; /*printf("thread : portal : %s, command : %d, version : %d, key : %s, value : %s, len : %d\n", wdata->portal, *payload_cmd, *payload_version, key, value, len);*/ in_sglist[0].iov_base = NULL; in_sglist[0].iov_len = 0; vmsg_sglist_set_nents(&req->in, 0); rsp->request = req; if (xio_send_response(rsp) == -1) { fprintf(stderr, "failed to send response for thread %s. reason %d - (%s)\n", wdata->portal, xio_errno(), xio_strerror(xio_errno())); } return (0); }
/*---------------------------------------------------------------------------*/ static int raio_handle_setup(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { int fd, j; struct raio_io_session_data *sd = prv_session_data; struct raio_io_portal_data *pd = prv_portal_data; if (3*sizeof(int) != cmd->data_len) { errno = EINVAL; printf("io setup request rejected\n"); goto reject; } unpack_u32((uint32_t *)&pd->iodepth, unpack_u32((uint32_t *)&fd, cmd_data)); pd->io_u_free_nr = pd->iodepth + EXTRA_MSGS; pd->io_us_free = calloc(pd->io_u_free_nr, sizeof(struct raio_io_u)); pd->rsp_pool = msg_pool_create(512, MAXBLOCKSIZE, pd->io_u_free_nr); TAILQ_INIT(&pd->io_u_free_list); /* register each io_u in the free list */ for (j = 0; j < pd->io_u_free_nr; j++) { pd->io_us_free[j].rsp = msg_pool_get(pd->rsp_pool); TAILQ_INSERT_TAIL(&pd->io_u_free_list, &pd->io_us_free[j], io_u_list); } if (sd->is_null) pd->bs_dev = raio_bs_init(pd->ctx, "null"); else pd->bs_dev = raio_bs_init(pd->ctx, "aio"); errno = -raio_bs_open(pd->bs_dev, fd); reject: if (errno) { struct raio_answer ans = { RAIO_CMD_IO_SETUP, 0, -1, errno }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); } else { struct raio_answer ans = { RAIO_CMD_IO_SETUP, 0, 0, 0 }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); } pd->rsp.out.header.iov_len = sizeof(struct raio_answer); pd->rsp.request = req; xio_send_response(&pd->rsp); return 0; }
/*---------------------------------------------------------------------------*/ static int raio_handle_fstat(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { struct raio_io_session_data *sd = prv_session_data; struct raio_io_portal_data *pd = prv_portal_data; int fd; int retval = 0; struct stat64 stbuf; unpack_u32((uint32_t *)&fd, cmd_data); if (sizeof(fd) != cmd->data_len) { retval = -1; errno = EINVAL; printf("open request rejected\n"); goto reject; } if (sd->is_null) { stbuf.st_size = NULL_BS_DEV_SIZE; sd->fsize = stbuf.st_size; } else { retval = fstat64(fd, &stbuf); if (retval == 0) { if (S_ISBLK(stbuf.st_mode)) { retval = ioctl(fd, BLKGETSIZE64, &stbuf.st_size); if (retval < 0) fprintf(stderr, "Cannot get size %m\n"); } sd->fsize = stbuf.st_size; } } reject: if (retval != 0) { struct raio_answer ans = { RAIO_CMD_FSTAT, 0, -1, errno }; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); } else { struct raio_answer ans = {RAIO_CMD_FSTAT, STAT_BLOCK_SIZE, 0, 0}; pack_stat64(&stbuf, pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr))))); } pd->rsp.out.header.iov_len = sizeof(struct raio_answer) + STAT_BLOCK_SIZE; pd->rsp.request = req; xio_send_response(&pd->rsp); return 0; }
/*---------------------------------------------------------------------------*/ static int raio_handle_open(void *prv_session_data, void *prv_portal_data, struct raio_command *cmd, char *cmd_data, struct xio_msg *req) { struct raio_io_session_data *sd = prv_session_data; struct raio_io_portal_data *pd = prv_portal_data; const char *pathname; uint32_t flags = 0; unsigned overall_size; int fd; int retval; struct stat64 stbuf; overall_size = sizeof(fd); pathname = unpack_u32(&flags, cmd_data); if (sizeof(flags) + strlen(pathname) + 1 != cmd->data_len) { fd = -1; errno = EINVAL; printf("open request rejected\n"); goto reject; } if (strcmp(pathname, "/dev/null")) { fd = open(pathname, flags); if (fd == -1) goto reject; } else { sd->is_null = 1; fd = 0; } /* get file size */ if (sd->is_null) { sd->fsize = NULL_BS_DEV_SIZE; } else { retval = fstat64(fd, &stbuf); if (retval == 0) { if (S_ISBLK(stbuf.st_mode)) { retval = ioctl(fd, BLKGETSIZE64, &stbuf.st_size); if (retval < 0) fprintf(stderr, "Cannot get size, %m\n"); } sd->fsize = stbuf.st_size; } } reject: if (fd == -1) { struct raio_answer ans = {RAIO_CMD_OPEN, 0, -1, errno}; pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr)))); fprintf(stderr, "open %s failed %m\n", pathname); } else { unsigned overall_size = sizeof(fd); struct raio_answer ans = {RAIO_CMD_OPEN, overall_size, 0, 0}; pack_u32((uint32_t *)&fd, pack_u32((uint32_t *)&ans.ret_errno, pack_u32((uint32_t *)&ans.ret, pack_u32(&ans.data_len, pack_u32(&ans.command, pd->rsp_hdr))))); } pd->rsp.out.header.iov_len = (sizeof(struct raio_answer) + overall_size); pd->rsp.request = req; xio_send_response(&pd->rsp); return 0; }