aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:30 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:28 -0400
commit009d344398bb3e844b31eb9e6a7860748c6f6dd3 (patch)
treeaa999b974fd42753976be22c2596d1f1fcf83511 /fs/cifs
parentba9ad7257ae50b8aa72a3f44da839830e065363c (diff)
CIFS: Add writepage support for SMB2
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/smb2ops.c12
-rw-r--r--fs/cifs/smb2pdu.c61
-rw-r--r--fs/cifs/smb2proto.h2
3 files changed, 75 insertions, 0 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index fb289d2abae7..f9c3dbee9010 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -404,6 +404,17 @@ smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
404 return SMB2_read(xid, parms, bytes_read, buf, buf_type); 404 return SMB2_read(xid, parms, bytes_read, buf, buf_type);
405} 405}
406 406
407static int
408smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
409 struct cifs_io_parms *parms, unsigned int *written,
410 struct kvec *iov, unsigned long nr_segs)
411{
412
413 parms->persistent_fid = cfile->fid.persistent_fid;
414 parms->volatile_fid = cfile->fid.volatile_fid;
415 return SMB2_write(xid, parms, written, iov, nr_segs);
416}
417
407struct smb_version_operations smb21_operations = { 418struct smb_version_operations smb21_operations = {
408 .setup_request = smb2_setup_request, 419 .setup_request = smb2_setup_request,
409 .setup_async_request = smb2_setup_async_request, 420 .setup_async_request = smb2_setup_async_request,
@@ -447,6 +458,7 @@ struct smb_version_operations smb21_operations = {
447 .async_readv = smb2_async_readv, 458 .async_readv = smb2_async_readv,
448 .async_writev = smb2_async_writev, 459 .async_writev = smb2_async_writev,
449 .sync_read = smb2_sync_read, 460 .sync_read = smb2_sync_read,
461 .sync_write = smb2_sync_write,
450}; 462};
451 463
452struct smb_version_values smb21_values = { 464struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 23c569386f32..00dc45a7881c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1501,3 +1501,64 @@ async_writev_out:
1501 kfree(iov); 1501 kfree(iov);
1502 return rc; 1502 return rc;
1503} 1503}
1504
1505/*
1506 * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
1507 * The length field from io_parms must be at least 1 and indicates a number of
1508 * elements with data to write that begins with position 1 in iov array. All
1509 * data length is specified by count.
1510 */
1511int
1512SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
1513 unsigned int *nbytes, struct kvec *iov, int n_vec)
1514{
1515 int rc = 0;
1516 struct smb2_write_req *req = NULL;
1517 struct smb2_write_rsp *rsp = NULL;
1518 int resp_buftype;
1519 *nbytes = 0;
1520
1521 if (n_vec < 1)
1522 return rc;
1523
1524 rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
1525 if (rc)
1526 return rc;
1527
1528 if (io_parms->tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
1531 req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
1532
1533 req->PersistentFileId = io_parms->persistent_fid;
1534 req->VolatileFileId = io_parms->volatile_fid;
1535 req->WriteChannelInfoOffset = 0;
1536 req->WriteChannelInfoLength = 0;
1537 req->Channel = 0;
1538 req->Length = cpu_to_le32(io_parms->length);
1539 req->Offset = cpu_to_le64(io_parms->offset);
1540 /* 4 for rfc1002 length field */
1541 req->DataOffset = cpu_to_le16(
1542 offsetof(struct smb2_write_req, Buffer) - 4);
1543 req->RemainingBytes = 0;
1544
1545 iov[0].iov_base = (char *)req;
1546 /* 4 for rfc1002 length field and 1 for Buffer */
1547 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
1548
1549 /* length of entire message including data to be written */
1550 inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
1551
1552 rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
1553 &resp_buftype, 0);
1554
1555 if (rc) {
1556 cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
1557 cERROR(1, "Send error in write = %d", rc);
1558 } else {
1559 rsp = (struct smb2_write_rsp *)iov[0].iov_base;
1560 *nbytes = le32_to_cpu(rsp->DataLength);
1561 free_rsp_buf(resp_buftype, rsp);
1562 }
1563 return rc;
1564}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 97e62f3df410..192d0c7d91eb 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -101,6 +101,8 @@ extern int smb2_async_readv(struct cifs_readdata *rdata);
101extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, 101extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
102 unsigned int *nbytes, char **buf, int *buf_type); 102 unsigned int *nbytes, char **buf, int *buf_type);
103extern int smb2_async_writev(struct cifs_writedata *wdata); 103extern int smb2_async_writev(struct cifs_writedata *wdata);
104extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
105 unsigned int *nbytes, struct kvec *iov, int n_vec);
104extern int SMB2_echo(struct TCP_Server_Info *server); 106extern int SMB2_echo(struct TCP_Server_Info *server);
105 107
106#endif /* _SMB2PROTO_H */ 108#endif /* _SMB2PROTO_H */