/* * Send a SMB request and set the callback function in the mid to handle * the result. Caller is responsible for dealing with timeouts. */ int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, mid_receive_t *receive, mid_callback_t *callback, mid_handle_t *handle, void *cbdata, const int flags) { int rc, timeout, optype; struct mid_q_entry *mid; unsigned int credits = 0; timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; if ((flags & CIFS_HAS_CREDITS) == 0) { rc = wait_for_free_request(server, timeout, optype); if (rc) return rc; credits = 1; } mutex_lock(&server->srv_mutex); mid = server->ops->setup_async_request(server, rqst); if (IS_ERR(mid)) { mutex_unlock(&server->srv_mutex); add_credits_and_wake_if(server, credits, optype); return PTR_ERR(mid); } mid->receive = receive; mid->callback = callback; mid->callback_data = cbdata; mid->handle = handle; mid->mid_state = MID_REQUEST_SUBMITTED; /* put it on the pending_mid_q */ spin_lock(&GlobalMid_Lock); list_add_tail(&mid->qhead, &server->pending_mid_q); spin_unlock(&GlobalMid_Lock); /* * Need to store the time in mid before calling I/O. For call_async, * I/O response may come back and free the mid entry on another thread. */ cifs_save_when_sent(mid); cifs_in_send_inc(server); rc = smb_send_rqst(server, 1, rqst, flags); cifs_in_send_dec(server); if (rc < 0) { server->sequence_number -= 2; cifs_delete_mid(mid); } mutex_unlock(&server->srv_mutex); if (rc == 0) return 0; add_credits_and_wake_if(server, credits, optype); return rc; }
/* * Send a SMB request and set the callback function in the mid to handle * the result. Caller is responsible for dealing with timeouts. */ int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, mid_receive_t *receive, mid_callback_t *callback, mid_handle_t *handle, void *cbdata, const int flags, const struct cifs_credits *exist_credits) { int rc; struct mid_q_entry *mid; struct cifs_credits credits = { .value = 0, .instance = 0 }; unsigned int instance; int optype; optype = flags & CIFS_OP_MASK; if ((flags & CIFS_HAS_CREDITS) == 0) { rc = wait_for_free_request(server, flags, &instance); if (rc) return rc; credits.value = 1; credits.instance = instance; } else instance = exist_credits->instance; mutex_lock(&server->srv_mutex); /* * We can't use credits obtained from the previous session to send this * request. Check if there were reconnects after we obtained credits and * return -EAGAIN in such cases to let callers handle it. */ if (instance != server->reconnect_instance) { mutex_unlock(&server->srv_mutex); add_credits_and_wake_if(server, &credits, optype); return -EAGAIN; } mid = server->ops->setup_async_request(server, rqst); if (IS_ERR(mid)) { mutex_unlock(&server->srv_mutex); add_credits_and_wake_if(server, &credits, optype); return PTR_ERR(mid); } mid->receive = receive; mid->callback = callback; mid->callback_data = cbdata; mid->handle = handle; mid->mid_state = MID_REQUEST_SUBMITTED; /* put it on the pending_mid_q */ spin_lock(&GlobalMid_Lock); list_add_tail(&mid->qhead, &server->pending_mid_q); spin_unlock(&GlobalMid_Lock); /* * Need to store the time in mid before calling I/O. For call_async, * I/O response may come back and free the mid entry on another thread. */ cifs_save_when_sent(mid); cifs_in_send_inc(server); rc = smb_send_rqst(server, 1, rqst, flags); cifs_in_send_dec(server); if (rc < 0) { revert_current_mid(server, mid->credits); server->sequence_number -= 2; cifs_delete_mid(mid); } mutex_unlock(&server->srv_mutex); if (rc == 0) return 0; add_credits_and_wake_if(server, &credits, optype); return rc; } /* * * Send an SMB Request. No response info (other than return code) * needs to be parsed. * * flags indicate the type of request buffer and how long to wait * and whether to log NT STATUS code (error) before mapping it to POSIX error * */ int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, char *in_buf, int flags) { int rc; struct kvec iov[1]; struct kvec rsp_iov; int resp_buf_type; iov[0].iov_base = in_buf; iov[0].iov_len = get_rfc1002_length(in_buf) + 4; flags |= CIFS_NO_RSP_BUF; rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc); return rc; }