aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-01-11 07:24:01 -0500
committerSteve French <sfrench@us.ibm.com>2011-01-19 12:52:29 -0500
commit941b853d779de3298e39f1eb4e252984464eaea8 (patch)
treea1e41bb06debf22349f010a1c9427c9b89bb79b4
parent12fed00de963433128b5366a21a55808fab2f756 (diff)
cifs: don't fail writepages on -EAGAIN errors
If CIFSSMBWrite2 returns -EAGAIN, then the error should be considered temporary. CIFS should retry the write instead of setting an error on the mapping and returning. For WB_SYNC_ALL, just retry the write immediately. In the WB_SYNC_NONE case, call redirty_page_for_writeback on all of the pages that didn't get written out and then move on. Also, fix up the handling of a short write with a successful return code. MS-CIFS says that 0 bytes_written means ENOSPC or EFBIG. It doesn't mention what a short, but non-zero write means, so for now treat it as we would an -EAGAIN return. Reviewed-by: Suresh Jayaraman <sjayaraman@suse.de> Reviewed-by: Pavel Shilovsky <piastryyy@gmail.com> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/file.c49
1 files changed, 37 insertions, 12 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index af371910f543..cfa2e5ebcafe 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1377,6 +1377,7 @@ retry:
1377 break; 1377 break;
1378 } 1378 }
1379 if (n_iov) { 1379 if (n_iov) {
1380retry_write:
1380 open_file = find_writable_file(CIFS_I(mapping->host), 1381 open_file = find_writable_file(CIFS_I(mapping->host),
1381 false); 1382 false);
1382 if (!open_file) { 1383 if (!open_file) {
@@ -1389,31 +1390,55 @@ retry:
1389 &bytes_written, iov, n_iov, 1390 &bytes_written, iov, n_iov,
1390 long_op); 1391 long_op);
1391 cifsFileInfo_put(open_file); 1392 cifsFileInfo_put(open_file);
1392 cifs_update_eof(cifsi, offset, bytes_written);
1393 } 1393 }
1394 1394
1395 if (rc || bytes_written < bytes_to_write) { 1395 cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
1396 cERROR(1, "Write2 ret %d, wrote %d", 1396
1397 rc, bytes_written); 1397 /*
1398 mapping_set_error(mapping, rc); 1398 * For now, treat a short write as if nothing got
1399 } else { 1399 * written. A zero length write however indicates
1400 * ENOSPC or EFBIG. We have no way to know which
1401 * though, so call it ENOSPC for now. EFBIG would
1402 * get translated to AS_EIO anyway.
1403 *
1404 * FIXME: make it take into account the data that did
1405 * get written
1406 */
1407 if (rc == 0) {
1408 if (bytes_written == 0)
1409 rc = -ENOSPC;
1410 else if (bytes_written < bytes_to_write)
1411 rc = -EAGAIN;
1412 }
1413
1414 /* retry on data-integrity flush */
1415 if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
1416 goto retry_write;
1417
1418 /* fix the stats and EOF */
1419 if (bytes_written > 0) {
1400 cifs_stats_bytes_written(tcon, bytes_written); 1420 cifs_stats_bytes_written(tcon, bytes_written);
1421 cifs_update_eof(cifsi, offset, bytes_written);
1401 } 1422 }
1402 1423
1403 for (i = 0; i < n_iov; i++) { 1424 for (i = 0; i < n_iov; i++) {
1404 page = pvec.pages[first + i]; 1425 page = pvec.pages[first + i];
1405 /* Should we also set page error on 1426 /* on retryable write error, redirty page */
1406 success rc but too little data written? */ 1427 if (rc == -EAGAIN)
1407 /* BB investigate retry logic on temporary 1428 redirty_page_for_writepage(wbc, page);
1408 server crash cases and how recovery works 1429 else if (rc != 0)
1409 when page marked as error */
1410 if (rc)
1411 SetPageError(page); 1430 SetPageError(page);
1412 kunmap(page); 1431 kunmap(page);
1413 unlock_page(page); 1432 unlock_page(page);
1414 end_page_writeback(page); 1433 end_page_writeback(page);
1415 page_cache_release(page); 1434 page_cache_release(page);
1416 } 1435 }
1436
1437 if (rc != -EAGAIN)
1438 mapping_set_error(mapping, rc);
1439 else
1440 rc = 0;
1441
1417 if ((wbc->nr_to_write -= n_iov) <= 0) 1442 if ((wbc->nr_to_write -= n_iov) <= 0)
1418 done = 1; 1443 done = 1;
1419 index = next; 1444 index = next;