Skip to content

Commit d53e292

Browse files
longlimsftSteve French
authored andcommitted
CIFS: Fix an issue with re-sending wdata when transport returning -EAGAIN
When sending a wdata, transport may return -EAGAIN. In this case we should re-obtain credits because the session may have been reconnected. Change in v2: adjust_credits before re-sending Signed-off-by: Long Li <longli@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
1 parent a5ed1e9 commit d53e292

File tree

1 file changed

+45
-32
lines changed

1 file changed

+45
-32
lines changed

fs/cifs/file.c

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
26322632
struct TCP_Server_Info *server =
26332633
tlink_tcon(wdata->cfile->tlink)->ses->server;
26342634

2635-
/*
2636-
* Wait for credits to resend this wdata.
2637-
* Note: we are attempting to resend the whole wdata not in segments
2638-
*/
26392635
do {
2640-
rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize,
2641-
&credits);
2636+
if (wdata->cfile->invalidHandle) {
2637+
rc = cifs_reopen_file(wdata->cfile, false);
2638+
if (rc == -EAGAIN)
2639+
continue;
2640+
else if (rc)
2641+
break;
2642+
}
26422643

2643-
if (rc)
2644-
goto out;
26452644

2646-
if (wsize < wdata->bytes) {
2647-
add_credits_and_wake_if(server, &credits, 0);
2648-
msleep(1000);
2649-
}
2650-
} while (wsize < wdata->bytes);
2645+
/*
2646+
* Wait for credits to resend this wdata.
2647+
* Note: we are attempting to resend the whole wdata not in
2648+
* segments
2649+
*/
2650+
do {
2651+
rc = server->ops->wait_mtu_credits(server, wdata->bytes,
2652+
&wsize, &credits);
2653+
if (rc)
2654+
goto fail;
2655+
2656+
if (wsize < wdata->bytes) {
2657+
add_credits_and_wake_if(server, &credits, 0);
2658+
msleep(1000);
2659+
}
2660+
} while (wsize < wdata->bytes);
2661+
wdata->credits = credits;
26512662

2652-
wdata->credits = credits;
2653-
rc = -EAGAIN;
2654-
while (rc == -EAGAIN) {
2655-
rc = 0;
2656-
if (wdata->cfile->invalidHandle)
2657-
rc = cifs_reopen_file(wdata->cfile, false);
2658-
if (!rc)
2659-
rc = server->ops->async_writev(wdata,
2663+
rc = adjust_credits(server, &wdata->credits, wdata->bytes);
2664+
2665+
if (!rc) {
2666+
if (wdata->cfile->invalidHandle)
2667+
rc = -EAGAIN;
2668+
else
2669+
rc = server->ops->async_writev(wdata,
26602670
cifs_uncached_writedata_release);
2661-
}
2671+
}
26622672

2663-
if (!rc) {
2664-
list_add_tail(&wdata->list, wdata_list);
2665-
return 0;
2666-
}
2673+
/* If the write was successfully sent, we are done */
2674+
if (!rc) {
2675+
list_add_tail(&wdata->list, wdata_list);
2676+
return 0;
2677+
}
26672678

2668-
add_credits_and_wake_if(server, &wdata->credits, 0);
2669-
out:
2670-
kref_put(&wdata->refcount, cifs_uncached_writedata_release);
2679+
/* Roll back credits and retry if needed */
2680+
add_credits_and_wake_if(server, &wdata->credits, 0);
2681+
} while (rc == -EAGAIN);
26712682

2683+
fail:
2684+
kref_put(&wdata->refcount, cifs_uncached_writedata_release);
26722685
return rc;
26732686
}
26742687

@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx)
28962909
wdata->bytes, &tmp_from,
28972910
ctx->cfile, cifs_sb, &tmp_list,
28982911
ctx);
2912+
2913+
kref_put(&wdata->refcount,
2914+
cifs_uncached_writedata_release);
28992915
}
29002916

29012917
list_splice(&tmp_list, &ctx->list);
2902-
2903-
kref_put(&wdata->refcount,
2904-
cifs_uncached_writedata_release);
29052918
goto restart_loop;
29062919
}
29072920
}

0 commit comments

Comments
 (0)