atomic_add(credits, &sc->recv_io.credits.available);
+ /*
+ * If the last send credit is waiting for credits
+ * it can grant we need to wake it up
+ */
+ if (credits &&
+ atomic_read(&sc->send_io.bcredits.count) == 0 &&
+ atomic_read(&sc->send_io.credits.count) == 0)
+ wake_up(&sc->send_io.credits.wait_queue);
+
if (credits)
queue_work(sc->workqueue, &sc->idle.immediate_work);
}
static int smb_direct_create_header(struct smbdirect_socket *sc,
int size, int remaining_data_length,
+ int new_credits,
struct smbdirect_send_io **sendmsg_out)
{
struct smbdirect_socket_parameters *sp = &sc->parameters;
/* Fill in the packet header */
packet = (struct smbdirect_data_transfer *)sendmsg->packet;
packet->credits_requested = cpu_to_le16(sp->send_credit_target);
- packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(sc));
+ packet->credits_granted = cpu_to_le16(new_credits);
packet->flags = 0;
if (manage_keep_alive_before_sending(sc))
int data_length;
struct scatterlist sg[SMBDIRECT_SEND_IO_MAX_SGE - 1];
struct smbdirect_send_batch _send_ctx;
+ int new_credits;
if (!send_ctx) {
smb_direct_send_ctx_init(&_send_ctx, false, 0);
if (ret)
goto credit_failed;
+ new_credits = manage_credits_prior_sending(sc);
+ if (new_credits == 0 &&
+ atomic_read(&sc->send_io.credits.count) == 0 &&
+ atomic_read(&sc->recv_io.credits.count) == 0) {
+ queue_work(sc->workqueue, &sc->recv_io.posted.refill_work);
+ ret = wait_event_interruptible(sc->send_io.credits.wait_queue,
+ atomic_read(&sc->send_io.credits.count) >= 1 ||
+ atomic_read(&sc->recv_io.credits.available) >= 1 ||
+ sc->status != SMBDIRECT_SOCKET_CONNECTED);
+ if (sc->status != SMBDIRECT_SOCKET_CONNECTED)
+ ret = -ENOTCONN;
+ if (ret < 0)
+ goto credit_failed;
+
+ new_credits = manage_credits_prior_sending(sc);
+ }
+
data_length = 0;
for (i = 0; i < niov; i++)
data_length += iov[i].iov_len;
ret = smb_direct_create_header(sc, data_length, remaining_data_length,
- &msg);
+ new_credits, &msg);
if (ret)
goto header_failed;