CIFS: Avoid returning EBUSY to upper layer VFS
authorLong Li <longli@microsoft.com>
Thu, 6 Dec 2018 04:51:06 +0000 (04:51 +0000)
committerSteve French <stfrench@microsoft.com>
Fri, 7 Dec 2018 06:59:23 +0000 (00:59 -0600)
EBUSY is not handled by VFS, and will be passed to user-mode. This is not
correct as we need to wait for more credits.

This patch also fixes a bug where rsize or wsize is used uninitialized when
the call to server->ops->wait_mtu_credits() fails.

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Long Li <longli@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
fs/cifs/file.c

index 74c33d5..c9bc56b 100644 (file)
@@ -2541,14 +2541,13 @@ static int
 cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
        struct cifs_aio_ctx *ctx)
 {
-       int wait_retry = 0;
        unsigned int wsize, credits;
        int rc;
        struct TCP_Server_Info *server =
                tlink_tcon(wdata->cfile->tlink)->ses->server;
 
        /*
-        * Try to resend this wdata, waiting for credits up to 3 seconds.
+        * Wait for credits to resend this wdata.
         * Note: we are attempting to resend the whole wdata not in segments
         */
        do {
@@ -2556,19 +2555,13 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
                        server, wdata->bytes, &wsize, &credits);
 
                if (rc)
-                       break;
+                       goto out;
 
                if (wsize < wdata->bytes) {
                        add_credits_and_wake_if(server, credits, 0);
                        msleep(1000);
-                       wait_retry++;
                }
-       } while (wsize < wdata->bytes && wait_retry < 3);
-
-       if (wsize < wdata->bytes) {
-               rc = -EBUSY;
-               goto out;
-       }
+       } while (wsize < wdata->bytes);
 
        rc = -EAGAIN;
        while (rc == -EAGAIN) {
@@ -3234,14 +3227,13 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
                        struct list_head *rdata_list,
                        struct cifs_aio_ctx *ctx)
 {
-       int wait_retry = 0;
        unsigned int rsize, credits;
        int rc;
        struct TCP_Server_Info *server =
                tlink_tcon(rdata->cfile->tlink)->ses->server;
 
        /*
-        * Try to resend this rdata, waiting for credits up to 3 seconds.
+        * Wait for credits to resend this rdata.
         * Note: we are attempting to resend the whole rdata not in segments
         */
        do {
@@ -3249,24 +3241,13 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
                                                &rsize, &credits);
 
                if (rc)
-                       break;
+                       goto out;
 
                if (rsize < rdata->bytes) {
                        add_credits_and_wake_if(server, credits, 0);
                        msleep(1000);
-                       wait_retry++;
                }
-       } while (rsize < rdata->bytes && wait_retry < 3);
-
-       /*
-        * If we can't find enough credits to send this rdata
-        * release the rdata and return failure, this will pass
-        * whatever I/O amount we have finished to VFS.
-        */
-       if (rsize < rdata->bytes) {
-               rc = -EBUSY;
-               goto out;
-       }
+       } while (rsize < rdata->bytes);
 
        rc = -EAGAIN;
        while (rc == -EAGAIN) {