diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index dbb2d939bc44..20faa6d7f514 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -697,6 +697,15 @@ static void smbd_post_send_credits(struct work_struct *work) atomic_add(posted, &sc->recv_io.credits.available); + /* + * If the last send credit is waiting for credits + * it can grant we need to wake it up + */ + if (posted && + atomic_read(&sc->send_io.bcredits.count) == 0 && + atomic_read(&sc->send_io.credits.count) == 0) + wake_up(&sc->send_io.credits.wait_queue); + /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target - 1) { @@ -1394,6 +1403,26 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, goto err_wait_credit; } + 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); + rc = 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) + rc = -ENOTCONN; + if (rc < 0) { + log_outgoing(ERR, "disconnected not sending on last credit\n"); + rc = -EAGAIN; + goto err_wait_credit; + } + + new_credits = manage_credits_prior_sending(sc); + } + request = smbd_alloc_send_io(sc); if (IS_ERR(request)) { rc = PTR_ERR(request); @@ -1448,8 +1477,6 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, /* Fill in the packet header */ packet->credits_requested = cpu_to_le16(sp->send_credit_target); - - new_credits = manage_credits_prior_sending(sc); packet->credits_granted = cpu_to_le16(new_credits); packet->flags = 0;