summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2014-07-10 11:31:48 +0400
committerSteve French <smfrench@gmail.com>2014-08-02 01:23:04 -0500
commitd913ed17f0a7d74e2847695bc920d77a33f2490b (patch)
tree2c511ecc0304b341b370834fc989d4b9d3c42d60 /fs/cifs
parentfb8a3e52559ad52829c6838d304f5b75c140b97a (diff)
CIFS: Optimize cifs_user_read() in a short read case on reconnects
by filling the output buffer with a data got from a partially received response and requesting the remaining data from the server. This is suitable for non-signed connections. Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifssmb.c6
-rw-r--r--fs/cifs/file.c23
-rw-r--r--fs/cifs/smb2pdu.c6
3 files changed, 32 insertions, 3 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 57d447c56d83..66f65001a6d8 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1561,6 +1561,12 @@ cifs_readv_callback(struct mid_q_entry *mid)
case MID_REQUEST_SUBMITTED:
case MID_RETRY_NEEDED:
rdata->result = -EAGAIN;
+ if (server->sign && rdata->got_bytes)
+ /* reset bytes number since we can not check a sign */
+ rdata->got_bytes = 0;
+ /* FIXME: should this be counted toward the initiating task? */
+ task_io_account_read(rdata->got_bytes);
+ cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
default:
rdata->result = -EIO;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e17012817d9d..5d2501df8f6b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3030,13 +3030,30 @@ again:
else if (rdata->result == -EAGAIN) {
/* resend call if it's a retryable error */
struct list_head tmp_list;
+ unsigned int got_bytes = rdata->got_bytes;
list_del_init(&rdata->list);
INIT_LIST_HEAD(&tmp_list);
- rc = cifs_send_async_read(rdata->offset,
- rdata->bytes, rdata->cfile,
- cifs_sb, &tmp_list);
+ /*
+ * Got a part of data and then reconnect has
+ * happened -- fill the buffer and continue
+ * reading.
+ */
+ if (got_bytes && got_bytes < rdata->bytes) {
+ rc = cifs_readdata_to_iov(rdata, to);
+ if (rc) {
+ kref_put(&rdata->refcount,
+ cifs_uncached_readdata_release);
+ continue;
+ }
+ }
+
+ rc = cifs_send_async_read(
+ rdata->offset + got_bytes,
+ rdata->bytes - got_bytes,
+ rdata->cfile, cifs_sb,
+ &tmp_list);
list_splice(&tmp_list, &rdata_list);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index c66ae4183bd3..cde943d61fb6 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1729,6 +1729,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
case MID_REQUEST_SUBMITTED:
case MID_RETRY_NEEDED:
rdata->result = -EAGAIN;
+ if (server->sign && rdata->got_bytes)
+ /* reset bytes number since we can not check a sign */
+ rdata->got_bytes = 0;
+ /* FIXME: should this be counted toward the initiating task? */
+ task_io_account_read(rdata->got_bytes);
+ cifs_stats_bytes_read(tcon, rdata->got_bytes);
break;
default:
if (rdata->result != -ENODATA)