CIFS: Add readpage support for SMB2
authorPavel Shilovsky <pshilovsky@samba.org>
Tue, 18 Sep 2012 23:20:30 +0000 (16:20 -0700)
committerSteve French <smfrench@gmail.com>
Tue, 25 Sep 2012 02:46:28 +0000 (21:46 -0500)
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h

index da31235023fbafe361e9f2f5eca3f99e72200dba..fb289d2abae7cd0e917d491ffe27e2d65098311c 100644 (file)
@@ -393,6 +393,17 @@ smb2_read_data_length(char *buf)
        return le32_to_cpu(rsp->DataLength);
 }
 
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+              struct cifs_io_parms *parms, unsigned int *bytes_read,
+              char **buf, int *buf_type)
+{
+       parms->persistent_fid = cfile->fid.persistent_fid;
+       parms->volatile_fid = cfile->fid.volatile_fid;
+       return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
 struct smb_version_operations smb21_operations = {
        .setup_request = smb2_setup_request,
        .setup_async_request = smb2_setup_async_request,
@@ -435,6 +446,7 @@ struct smb_version_operations smb21_operations = {
        .flush = smb2_flush_file,
        .async_readv = smb2_async_readv,
        .async_writev = smb2_async_writev,
+       .sync_read = smb2_sync_read,
 };
 
 struct smb_version_values smb21_values = {
index cb6acc7b1ca8181b0ec1f096344cc6e666329aa0..23c569386f32c7048e28848258e9682e55989027 100644 (file)
@@ -1329,6 +1329,57 @@ smb2_async_readv(struct cifs_readdata *rdata)
        return rc;
 }
 
+int
+SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+         unsigned int *nbytes, char **buf, int *buf_type)
+{
+       int resp_buftype, rc = -EACCES;
+       struct smb2_read_rsp *rsp = NULL;
+       struct kvec iov[1];
+
+       *nbytes = 0;
+       rc = smb2_new_read_req(iov, io_parms, 0, 0);
+       if (rc)
+               return rc;
+
+       rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
+                         &resp_buftype, CIFS_LOG_ERROR);
+
+       rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+
+       if (rsp->hdr.Status == STATUS_END_OF_FILE) {
+               free_rsp_buf(resp_buftype, iov[0].iov_base);
+               return 0;
+       }
+
+       if (rc) {
+               cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+               cERROR(1, "Send error in read = %d", rc);
+       } else {
+               *nbytes = le32_to_cpu(rsp->DataLength);
+               if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+                   (*nbytes > io_parms->length)) {
+                       cFYI(1, "bad length %d for count %d", *nbytes,
+                               io_parms->length);
+                       rc = -EIO;
+                       *nbytes = 0;
+               }
+       }
+
+       if (*buf) {
+               memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
+                      *nbytes);
+               free_rsp_buf(resp_buftype, iov[0].iov_base);
+       } else if (resp_buftype != CIFS_NO_BUFFER) {
+               *buf = iov[0].iov_base;
+               if (resp_buftype == CIFS_SMALL_BUFFER)
+                       *buf_type = CIFS_SMALL_BUFFER;
+               else if (resp_buftype == CIFS_LARGE_BUFFER)
+                       *buf_type = CIFS_LARGE_BUFFER;
+       }
+       return rc;
+}
+
 /*
  * Check the mid_state and signature on received buffer (if any), and queue the
  * workqueue completion task.
index ec983be0ba318906dbfbd3d60b5d542fc15c3dbd..97e62f3df410d5af9f95a3b0fac7de10c2a25e9a 100644 (file)
@@ -98,6 +98,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
                            u64 persistent_fid, u64 volatile_fid,
                            __le64 *uniqueid);
 extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+                    unsigned int *nbytes, char **buf, int *buf_type);
 extern int smb2_async_writev(struct cifs_writedata *wdata);
 extern int SMB2_echo(struct TCP_Server_Info *server);