Commit 133672efbc1085f9af990bdc145e1822ea93bcf3
1 parent
9418d5dc9b
Exists in
master
and in
7 other branches
[CIFS] Fix buffer overflow if server sends corrupt response to small
request In SendReceive() function in transport.c - it memcpy's message payload into a buffer passed via out_buf param. The function assumes that all buffers are of size (CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) , unfortunately it is also called with smaller (MAX_CIFS_SMALL_BUFFER_SIZE) buffers. There are eight callers (SMB worker functions) which are primarily affected by this change: TreeDisconnect, uLogoff, Close, findClose, SetFileSize, SetFileTimes, Lock and PosixLock CC: Dave Kleikamp <shaggy@austin.ibm.com> CC: Przemyslaw Wegrzyn <czajnik@czajsoft.pl> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Showing 7 changed files with 133 additions and 96 deletions Side-by-side Diff
fs/cifs/cifsglob.h
... | ... | @@ -471,6 +471,17 @@ |
471 | 471 | #define CIFS_LARGE_BUFFER 2 |
472 | 472 | #define CIFS_IOVEC 4 /* array of response buffers */ |
473 | 473 | |
474 | +/* Type of Request to SendReceive2 */ | |
475 | +#define CIFS_STD_OP 0 /* normal request timeout */ | |
476 | +#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ | |
477 | +#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ | |
478 | +#define CIFS_BLOCKING_OP 4 /* operation can block */ | |
479 | +#define CIFS_ASYNC_OP 8 /* do not wait for response */ | |
480 | +#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ | |
481 | +#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ | |
482 | +#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ | |
483 | +#define CIFS_NO_RESP 0x040 /* no response buffer required */ | |
484 | + | |
474 | 485 | /* Security Flags: indicate type of session setup needed */ |
475 | 486 | #define CIFSSEC_MAY_SIGN 0x00001 |
476 | 487 | #define CIFSSEC_MAY_NTLM 0x00002 |
fs/cifs/cifsproto.h
... | ... | @@ -48,10 +48,11 @@ |
48 | 48 | struct smb_hdr * /* input */ , |
49 | 49 | struct smb_hdr * /* out */ , |
50 | 50 | int * /* bytes returned */ , const int long_op); |
51 | +extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |
52 | + struct smb_hdr *in_buf, int flags); | |
51 | 53 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
52 | 54 | struct kvec *, int /* nvec to send */, |
53 | - int * /* type of buf returned */ , const int long_op, | |
54 | - const int logError /* whether to log status code*/ ); | |
55 | + int * /* type of buf returned */ , const int flags); | |
55 | 56 | extern int SendReceiveBlockingLock(const unsigned int /* xid */ , |
56 | 57 | struct cifsTconInfo *, |
57 | 58 | struct smb_hdr * /* input */ , |
fs/cifs/cifssmb.c
... | ... | @@ -698,9 +698,7 @@ |
698 | 698 | CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) |
699 | 699 | { |
700 | 700 | struct smb_hdr *smb_buffer; |
701 | - struct smb_hdr *smb_buffer_response; /* BB removeme BB */ | |
702 | 701 | int rc = 0; |
703 | - int length; | |
704 | 702 | |
705 | 703 | cFYI(1, ("In tree disconnect")); |
706 | 704 | /* |
707 | 705 | |
708 | 706 | |
... | ... | @@ -737,16 +735,12 @@ |
737 | 735 | if (rc) { |
738 | 736 | up(&tcon->tconSem); |
739 | 737 | return rc; |
740 | - } else { | |
741 | - smb_buffer_response = smb_buffer; /* BB removeme BB */ | |
742 | 738 | } |
743 | - rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, | |
744 | - &length, 0); | |
739 | + | |
740 | + rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); | |
745 | 741 | if (rc) |
746 | 742 | cFYI(1, ("Tree disconnect failed %d", rc)); |
747 | 743 | |
748 | - if (smb_buffer) | |
749 | - cifs_small_buf_release(smb_buffer); | |
750 | 744 | up(&tcon->tconSem); |
751 | 745 | |
752 | 746 | /* No need to return error on this operation if tid invalidated and |
753 | 747 | |
... | ... | @@ -760,10 +754,8 @@ |
760 | 754 | int |
761 | 755 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
762 | 756 | { |
763 | - struct smb_hdr *smb_buffer_response; | |
764 | 757 | LOGOFF_ANDX_REQ *pSMB; |
765 | 758 | int rc = 0; |
766 | - int length; | |
767 | 759 | |
768 | 760 | cFYI(1, ("In SMBLogoff for session disconnect")); |
769 | 761 | if (ses) |
... | ... | @@ -782,8 +774,6 @@ |
782 | 774 | return rc; |
783 | 775 | } |
784 | 776 | |
785 | - smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | |
786 | - | |
787 | 777 | if (ses->server) { |
788 | 778 | pSMB->hdr.Mid = GetNextMid(ses->server); |
789 | 779 | |
... | ... | @@ -795,8 +785,7 @@ |
795 | 785 | pSMB->hdr.Uid = ses->Suid; |
796 | 786 | |
797 | 787 | pSMB->AndXCommand = 0xFF; |
798 | - rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | |
799 | - smb_buffer_response, &length, 0); | |
788 | + rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); | |
800 | 789 | if (ses->server) { |
801 | 790 | atomic_dec(&ses->server->socketUseCount); |
802 | 791 | if (atomic_read(&ses->server->socketUseCount) == 0) { |
... | ... | @@ -807,7 +796,6 @@ |
807 | 796 | } |
808 | 797 | } |
809 | 798 | up(&ses->sesSem); |
810 | - cifs_small_buf_release(pSMB); | |
811 | 799 | |
812 | 800 | /* if session dead then we do not need to do ulogoff, |
813 | 801 | since server closed smb session, no sense reporting |
... | ... | @@ -1255,7 +1243,7 @@ |
1255 | 1243 | pSMB->ByteCount = cpu_to_le16(count); |
1256 | 1244 | /* long_op set to 1 to allow for oplock break timeouts */ |
1257 | 1245 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1258 | - (struct smb_hdr *) pSMBr, &bytes_returned, 1); | |
1246 | + (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | |
1259 | 1247 | cifs_stats_inc(&tcon->num_opens); |
1260 | 1248 | if (rc) { |
1261 | 1249 | cFYI(1, ("Error in Open = %d", rc)); |
... | ... | @@ -1368,7 +1356,7 @@ |
1368 | 1356 | pSMB->ByteCount = cpu_to_le16(count); |
1369 | 1357 | /* long_op set to 1 to allow for oplock break timeouts */ |
1370 | 1358 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1371 | - (struct smb_hdr *) pSMBr, &bytes_returned, 1); | |
1359 | + (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | |
1372 | 1360 | cifs_stats_inc(&tcon->num_opens); |
1373 | 1361 | if (rc) { |
1374 | 1362 | cFYI(1, ("Error in Open = %d", rc)); |
... | ... | @@ -1446,7 +1434,7 @@ |
1446 | 1434 | iov[0].iov_base = (char *)pSMB; |
1447 | 1435 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
1448 | 1436 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
1449 | - &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); | |
1437 | + &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | |
1450 | 1438 | cifs_stats_inc(&tcon->num_reads); |
1451 | 1439 | pSMBr = (READ_RSP *)iov[0].iov_base; |
1452 | 1440 | if (rc) { |
... | ... | @@ -1665,7 +1653,7 @@ |
1665 | 1653 | |
1666 | 1654 | |
1667 | 1655 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, |
1668 | - long_op, 0 /* do not log STATUS code */ ); | |
1656 | + long_op); | |
1669 | 1657 | cifs_stats_inc(&tcon->num_writes); |
1670 | 1658 | if (rc) { |
1671 | 1659 | cFYI(1, ("Send error Write2 = %d", rc)); |
... | ... | @@ -1707,7 +1695,7 @@ |
1707 | 1695 | int timeout = 0; |
1708 | 1696 | __u16 count; |
1709 | 1697 | |
1710 | - cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock)); | |
1698 | + cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock)); | |
1711 | 1699 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); |
1712 | 1700 | |
1713 | 1701 | if (rc) |
1714 | 1702 | |
... | ... | @@ -1716,10 +1704,10 @@ |
1716 | 1704 | pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ |
1717 | 1705 | |
1718 | 1706 | if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { |
1719 | - timeout = -1; /* no response expected */ | |
1707 | + timeout = CIFS_ASYNC_OP; /* no response expected */ | |
1720 | 1708 | pSMB->Timeout = 0; |
1721 | 1709 | } else if (waitFlag == TRUE) { |
1722 | - timeout = 3; /* blocking operation, no timeout */ | |
1710 | + timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ | |
1723 | 1711 | pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ |
1724 | 1712 | } else { |
1725 | 1713 | pSMB->Timeout = 0; |
1726 | 1714 | |
1727 | 1715 | |
... | ... | @@ -1749,15 +1737,16 @@ |
1749 | 1737 | if (waitFlag) { |
1750 | 1738 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
1751 | 1739 | (struct smb_hdr *) pSMBr, &bytes_returned); |
1740 | + cifs_small_buf_release(pSMB); | |
1752 | 1741 | } else { |
1753 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
1754 | - (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | |
1742 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, | |
1743 | + timeout); | |
1744 | + /* SMB buffer freed by function above */ | |
1755 | 1745 | } |
1756 | 1746 | cifs_stats_inc(&tcon->num_locks); |
1757 | 1747 | if (rc) { |
1758 | 1748 | cFYI(1, ("Send error in Lock = %d", rc)); |
1759 | 1749 | } |
1760 | - cifs_small_buf_release(pSMB); | |
1761 | 1750 | |
1762 | 1751 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1763 | 1752 | since file handle passed in no longer valid */ |
1764 | 1753 | |
... | ... | @@ -1776,7 +1765,9 @@ |
1776 | 1765 | int rc = 0; |
1777 | 1766 | int timeout = 0; |
1778 | 1767 | int bytes_returned = 0; |
1768 | + int resp_buf_type = 0; | |
1779 | 1769 | __u16 params, param_offset, offset, byte_count, count; |
1770 | + struct kvec iov[1]; | |
1780 | 1771 | |
1781 | 1772 | cFYI(1, ("Posix Lock")); |
1782 | 1773 | |
... | ... | @@ -1818,7 +1809,7 @@ |
1818 | 1809 | |
1819 | 1810 | parm_data->lock_type = cpu_to_le16(lock_type); |
1820 | 1811 | if (waitFlag) { |
1821 | - timeout = 3; /* blocking operation, no timeout */ | |
1812 | + timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ | |
1822 | 1813 | parm_data->lock_flags = cpu_to_le16(1); |
1823 | 1814 | pSMB->Timeout = cpu_to_le32(-1); |
1824 | 1815 | } else |
... | ... | @@ -1838,8 +1829,13 @@ |
1838 | 1829 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
1839 | 1830 | (struct smb_hdr *) pSMBr, &bytes_returned); |
1840 | 1831 | } else { |
1841 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
1842 | - (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | |
1832 | + iov[0].iov_base = (char *)pSMB; | |
1833 | + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | |
1834 | + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | |
1835 | + &resp_buf_type, timeout); | |
1836 | + pSMB = NULL; /* request buf already freed by SendReceive2. Do | |
1837 | + not try to free it twice below on exit */ | |
1838 | + pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base; | |
1843 | 1839 | } |
1844 | 1840 | |
1845 | 1841 | if (rc) { |
... | ... | @@ -1874,6 +1870,11 @@ |
1874 | 1870 | if (pSMB) |
1875 | 1871 | cifs_small_buf_release(pSMB); |
1876 | 1872 | |
1873 | + if (resp_buf_type == CIFS_SMALL_BUFFER) | |
1874 | + cifs_small_buf_release(iov[0].iov_base); | |
1875 | + else if (resp_buf_type == CIFS_LARGE_BUFFER) | |
1876 | + cifs_buf_release(iov[0].iov_base); | |
1877 | + | |
1877 | 1878 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1878 | 1879 | since file handle passed in no longer valid */ |
1879 | 1880 | |
... | ... | @@ -1886,8 +1887,6 @@ |
1886 | 1887 | { |
1887 | 1888 | int rc = 0; |
1888 | 1889 | CLOSE_REQ *pSMB = NULL; |
1889 | - CLOSE_RSP *pSMBr = NULL; | |
1890 | - int bytes_returned; | |
1891 | 1890 | cFYI(1, ("In CIFSSMBClose")); |
1892 | 1891 | |
1893 | 1892 | /* do not retry on dead session on close */ |
1894 | 1893 | |
... | ... | @@ -1897,13 +1896,10 @@ |
1897 | 1896 | if (rc) |
1898 | 1897 | return rc; |
1899 | 1898 | |
1900 | - pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | |
1901 | - | |
1902 | 1899 | pSMB->FileID = (__u16) smb_file_id; |
1903 | 1900 | pSMB->LastWriteTime = 0xFFFFFFFF; |
1904 | 1901 | pSMB->ByteCount = 0; |
1905 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
1906 | - (struct smb_hdr *) pSMBr, &bytes_returned, 0); | |
1902 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | |
1907 | 1903 | cifs_stats_inc(&tcon->num_closes); |
1908 | 1904 | if (rc) { |
1909 | 1905 | if (rc != -EINTR) { |
... | ... | @@ -1912,8 +1908,6 @@ |
1912 | 1908 | } |
1913 | 1909 | } |
1914 | 1910 | |
1915 | - cifs_small_buf_release(pSMB); | |
1916 | - | |
1917 | 1911 | /* Since session is dead, file will be closed on server already */ |
1918 | 1912 | if (rc == -EAGAIN) |
1919 | 1913 | rc = 0; |
... | ... | @@ -3102,7 +3096,7 @@ |
3102 | 3096 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
3103 | 3097 | |
3104 | 3098 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
3105 | - 0 /* not long op */, 0 /* do not log STATUS codes */ ); | |
3099 | + CIFS_STD_OP); | |
3106 | 3100 | cifs_stats_inc(&tcon->num_acl_get); |
3107 | 3101 | if (rc) { |
3108 | 3102 | cFYI(1, ("Send error in QuerySecDesc = %d", rc)); |
... | ... | @@ -3763,8 +3757,6 @@ |
3763 | 3757 | { |
3764 | 3758 | int rc = 0; |
3765 | 3759 | FINDCLOSE_REQ *pSMB = NULL; |
3766 | - CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */ | |
3767 | - int bytes_returned; | |
3768 | 3760 | |
3769 | 3761 | cFYI(1, ("In CIFSSMBFindClose")); |
3770 | 3762 | rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); |
3771 | 3763 | |
3772 | 3764 | |
... | ... | @@ -3776,16 +3768,13 @@ |
3776 | 3768 | if (rc) |
3777 | 3769 | return rc; |
3778 | 3770 | |
3779 | - pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | |
3780 | 3771 | pSMB->FileID = searchHandle; |
3781 | 3772 | pSMB->ByteCount = 0; |
3782 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
3783 | - (struct smb_hdr *) pSMBr, &bytes_returned, 0); | |
3773 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | |
3784 | 3774 | if (rc) { |
3785 | 3775 | cERROR(1, ("Send error in FindClose = %d", rc)); |
3786 | 3776 | } |
3787 | 3777 | cifs_stats_inc(&tcon->num_fclose); |
3788 | - cifs_small_buf_release(pSMB); | |
3789 | 3778 | |
3790 | 3779 | /* Since session is dead, search handle closed on server already */ |
3791 | 3780 | if (rc == -EAGAIN) |
3792 | 3781 | |
... | ... | @@ -4707,11 +4696,9 @@ |
4707 | 4696 | __u16 fid, __u32 pid_of_opener, int SetAllocation) |
4708 | 4697 | { |
4709 | 4698 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
4710 | - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | |
4711 | 4699 | char *data_offset; |
4712 | 4700 | struct file_end_of_file_info *parm_data; |
4713 | 4701 | int rc = 0; |
4714 | - int bytes_returned = 0; | |
4715 | 4702 | __u16 params, param_offset, offset, byte_count, count; |
4716 | 4703 | |
4717 | 4704 | cFYI(1, ("SetFileSize (via SetFileInfo) %lld", |
... | ... | @@ -4721,8 +4708,6 @@ |
4721 | 4708 | if (rc) |
4722 | 4709 | return rc; |
4723 | 4710 | |
4724 | - pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; | |
4725 | - | |
4726 | 4711 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); |
4727 | 4712 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); |
4728 | 4713 | |
4729 | 4714 | |
... | ... | @@ -4773,17 +4758,13 @@ |
4773 | 4758 | pSMB->Reserved4 = 0; |
4774 | 4759 | pSMB->hdr.smb_buf_length += byte_count; |
4775 | 4760 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4776 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
4777 | - (struct smb_hdr *) pSMBr, &bytes_returned, 0); | |
4761 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | |
4778 | 4762 | if (rc) { |
4779 | 4763 | cFYI(1, |
4780 | 4764 | ("Send error in SetFileInfo (SetFileSize) = %d", |
4781 | 4765 | rc)); |
4782 | 4766 | } |
4783 | 4767 | |
4784 | - if (pSMB) | |
4785 | - cifs_small_buf_release(pSMB); | |
4786 | - | |
4787 | 4768 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
4788 | 4769 | since file handle passed in no longer valid */ |
4789 | 4770 | |
4790 | 4771 | |
... | ... | @@ -4801,10 +4782,8 @@ |
4801 | 4782 | const FILE_BASIC_INFO *data, __u16 fid) |
4802 | 4783 | { |
4803 | 4784 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
4804 | - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | |
4805 | 4785 | char *data_offset; |
4806 | 4786 | int rc = 0; |
4807 | - int bytes_returned = 0; | |
4808 | 4787 | __u16 params, param_offset, offset, byte_count, count; |
4809 | 4788 | |
4810 | 4789 | cFYI(1, ("Set Times (via SetFileInfo)")); |
... | ... | @@ -4813,8 +4792,6 @@ |
4813 | 4792 | if (rc) |
4814 | 4793 | return rc; |
4815 | 4794 | |
4816 | - pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; | |
4817 | - | |
4818 | 4795 | /* At this point there is no need to override the current pid |
4819 | 4796 | with the pid of the opener, but that could change if we someday |
4820 | 4797 | use an existing handle (rather than opening one on the fly) */ |
4821 | 4798 | |
... | ... | @@ -4854,14 +4831,11 @@ |
4854 | 4831 | pSMB->hdr.smb_buf_length += byte_count; |
4855 | 4832 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4856 | 4833 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); |
4857 | - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | |
4858 | - (struct smb_hdr *) pSMBr, &bytes_returned, 0); | |
4834 | + rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | |
4859 | 4835 | if (rc) { |
4860 | 4836 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); |
4861 | 4837 | } |
4862 | 4838 | |
4863 | - cifs_small_buf_release(pSMB); | |
4864 | - | |
4865 | 4839 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
4866 | 4840 | since file handle passed in no longer valid */ |
4867 | 4841 | |
... | ... | @@ -5152,7 +5126,8 @@ |
5152 | 5126 | pSMB->ByteCount = 0; |
5153 | 5127 | |
5154 | 5128 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
5155 | - (struct smb_hdr *) pSMBr, &bytes_returned, -1); | |
5129 | + (struct smb_hdr *)pSMBr, &bytes_returned, | |
5130 | + CIFS_ASYNC_OP); | |
5156 | 5131 | if (rc) { |
5157 | 5132 | cFYI(1, ("Error in Notify = %d", rc)); |
5158 | 5133 | } else { |
fs/cifs/connect.c
... | ... | @@ -2374,7 +2374,7 @@ |
2374 | 2374 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); |
2375 | 2375 | |
2376 | 2376 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
2377 | - &bytes_returned, 1); | |
2377 | + &bytes_returned, CIFS_LONG_OP); | |
2378 | 2378 | if (rc) { |
2379 | 2379 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ |
2380 | 2380 | } else if ((smb_buffer_response->WordCount == 3) |
... | ... | @@ -2678,7 +2678,7 @@ |
2678 | 2678 | pSMB->req.ByteCount = cpu_to_le16(count); |
2679 | 2679 | |
2680 | 2680 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
2681 | - &bytes_returned, 1); | |
2681 | + &bytes_returned, CIFS_LONG_OP); | |
2682 | 2682 | |
2683 | 2683 | if (smb_buffer_response->Status.CifsError == |
2684 | 2684 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) |
... | ... | @@ -3105,7 +3105,7 @@ |
3105 | 3105 | pSMB->req.ByteCount = cpu_to_le16(count); |
3106 | 3106 | |
3107 | 3107 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
3108 | - &bytes_returned, 1); | |
3108 | + &bytes_returned, CIFS_LONG_OP); | |
3109 | 3109 | if (rc) { |
3110 | 3110 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ |
3111 | 3111 | } else if ((smb_buffer_response->WordCount == 3) || |
... | ... | @@ -3381,7 +3381,8 @@ |
3381 | 3381 | pSMB->hdr.smb_buf_length += count; |
3382 | 3382 | pSMB->ByteCount = cpu_to_le16(count); |
3383 | 3383 | |
3384 | - rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); | |
3384 | + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | |
3385 | + CIFS_STD_OP); | |
3385 | 3386 | |
3386 | 3387 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ |
3387 | 3388 | /* above now done in SendReceive */ |
fs/cifs/file.c
... | ... | @@ -835,9 +835,9 @@ |
835 | 835 | xid = GetXid(); |
836 | 836 | |
837 | 837 | if (*poffset > file->f_path.dentry->d_inode->i_size) |
838 | - long_op = 2; /* writes past end of file can take a long time */ | |
838 | + long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ | |
839 | 839 | else |
840 | - long_op = 1; | |
840 | + long_op = CIFS_LONG_OP; | |
841 | 841 | |
842 | 842 | for (total_written = 0; write_size > total_written; |
843 | 843 | total_written += bytes_written) { |
... | ... | @@ -884,7 +884,7 @@ |
884 | 884 | } |
885 | 885 | } else |
886 | 886 | *poffset += bytes_written; |
887 | - long_op = FALSE; /* subsequent writes fast - | |
887 | + long_op = CIFS_STD_OP; /* subsequent writes fast - | |
888 | 888 | 15 seconds is plenty */ |
889 | 889 | } |
890 | 890 | |
891 | 891 | |
... | ... | @@ -934,9 +934,9 @@ |
934 | 934 | xid = GetXid(); |
935 | 935 | |
936 | 936 | if (*poffset > file->f_path.dentry->d_inode->i_size) |
937 | - long_op = 2; /* writes past end of file can take a long time */ | |
937 | + long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ | |
938 | 938 | else |
939 | - long_op = 1; | |
939 | + long_op = CIFS_LONG_OP; | |
940 | 940 | |
941 | 941 | for (total_written = 0; write_size > total_written; |
942 | 942 | total_written += bytes_written) { |
... | ... | @@ -1002,7 +1002,7 @@ |
1002 | 1002 | } |
1003 | 1003 | } else |
1004 | 1004 | *poffset += bytes_written; |
1005 | - long_op = FALSE; /* subsequent writes fast - | |
1005 | + long_op = CIFS_STD_OP; /* subsequent writes fast - | |
1006 | 1006 | 15 seconds is plenty */ |
1007 | 1007 | } |
1008 | 1008 | |
... | ... | @@ -1360,7 +1360,7 @@ |
1360 | 1360 | open_file->netfid, |
1361 | 1361 | bytes_to_write, offset, |
1362 | 1362 | &bytes_written, iov, n_iov, |
1363 | - 1); | |
1363 | + CIFS_LONG_OP); | |
1364 | 1364 | atomic_dec(&open_file->wrtPending); |
1365 | 1365 | if (rc || bytes_written < bytes_to_write) { |
1366 | 1366 | cERROR(1, ("Write2 ret %d, wrote %d", |
fs/cifs/sess.c
... | ... | @@ -514,7 +514,7 @@ |
514 | 514 | iov[1].iov_base = str_area; |
515 | 515 | iov[1].iov_len = count; |
516 | 516 | rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, |
517 | - 0 /* not long op */, 1 /* log NT STATUS if any */ ); | |
517 | + CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | |
518 | 518 | /* SMB request buf freed in SendReceive2 */ |
519 | 519 | |
520 | 520 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
fs/cifs/transport.c
... | ... | @@ -308,7 +308,7 @@ |
308 | 308 | |
309 | 309 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) |
310 | 310 | { |
311 | - if (long_op == -1) { | |
311 | + if (long_op == CIFS_ASYNC_OP) { | |
312 | 312 | /* oplock breaks must not be held up */ |
313 | 313 | atomic_inc(&ses->server->inFlight); |
314 | 314 | } else { |
... | ... | @@ -337,7 +337,7 @@ |
337 | 337 | as they are allowed to block on server */ |
338 | 338 | |
339 | 339 | /* update # of requests on the wire to server */ |
340 | - if (long_op < 3) | |
340 | + if (long_op != CIFS_BLOCKING_OP) | |
341 | 341 | atomic_inc(&ses->server->inFlight); |
342 | 342 | spin_unlock(&GlobalMid_Lock); |
343 | 343 | break; |
344 | 344 | |
345 | 345 | |
346 | 346 | |
347 | 347 | |
... | ... | @@ -415,17 +415,48 @@ |
415 | 415 | } |
416 | 416 | } |
417 | 417 | |
418 | + | |
419 | +/* | |
420 | + * | |
421 | + * Send an SMB Request. No response info (other than return code) | |
422 | + * needs to be parsed. | |
423 | + * | |
424 | + * flags indicate the type of request buffer and how long to wait | |
425 | + * and whether to log NT STATUS code (error) before mapping it to POSIX error | |
426 | + * | |
427 | + */ | |
418 | 428 | int |
429 | +SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |
430 | + struct smb_hdr *in_buf, int flags) | |
431 | +{ | |
432 | + int rc; | |
433 | + struct kvec iov[1]; | |
434 | + int resp_buf_type; | |
435 | + | |
436 | + iov[0].iov_base = (char *)in_buf; | |
437 | + iov[0].iov_len = in_buf->smb_buf_length + 4; | |
438 | + flags |= CIFS_NO_RESP; | |
439 | + rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); | |
440 | +#ifdef CONFIG_CIFS_DEBUG2 | |
441 | + cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc)); | |
442 | +#endif | |
443 | + return rc; | |
444 | +} | |
445 | + | |
446 | +int | |
419 | 447 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
420 | 448 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
421 | - const int long_op, const int logError) | |
449 | + const int flags) | |
422 | 450 | { |
423 | 451 | int rc = 0; |
452 | + int long_op; | |
424 | 453 | unsigned int receive_len; |
425 | 454 | unsigned long timeout; |
426 | 455 | struct mid_q_entry *midQ; |
427 | 456 | struct smb_hdr *in_buf = iov[0].iov_base; |
428 | 457 | |
458 | + long_op = flags & CIFS_TIMEOUT_MASK; | |
459 | + | |
429 | 460 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ |
430 | 461 | |
431 | 462 | if ((ses == NULL) || (ses->server == NULL)) { |
432 | 463 | |
433 | 464 | |
... | ... | @@ -483,15 +514,22 @@ |
483 | 514 | if (rc < 0) |
484 | 515 | goto out; |
485 | 516 | |
486 | - if (long_op == -1) | |
487 | - goto out; | |
488 | - else if (long_op == 2) /* writes past end of file can take loong time */ | |
517 | + if (long_op == CIFS_STD_OP) | |
518 | + timeout = 15 * HZ; | |
519 | + else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ | |
489 | 520 | timeout = 180 * HZ; |
490 | - else if (long_op == 1) | |
521 | + else if (long_op == CIFS_LONG_OP) | |
491 | 522 | timeout = 45 * HZ; /* should be greater than |
492 | 523 | servers oplock break timeout (about 43 seconds) */ |
493 | - else | |
494 | - timeout = 15 * HZ; | |
524 | + else if (long_op == CIFS_ASYNC_OP) | |
525 | + goto out; | |
526 | + else if (long_op == CIFS_BLOCKING_OP) | |
527 | + timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | |
528 | + else { | |
529 | + cERROR(1, ("unknown timeout flag %d", long_op)); | |
530 | + rc = -EIO; | |
531 | + goto out; | |
532 | + } | |
495 | 533 | |
496 | 534 | /* wait for 15 seconds or until woken up due to response arriving or |
497 | 535 | due to last connection to this server being unmounted */ |
... | ... | @@ -566,7 +604,8 @@ |
566 | 604 | } |
567 | 605 | |
568 | 606 | /* BB special case reconnect tid and uid here? */ |
569 | - rc = map_smb_to_linux_error(midQ->resp_buf, logError); | |
607 | + rc = map_smb_to_linux_error(midQ->resp_buf, | |
608 | + flags & CIFS_LOG_ERROR); | |
570 | 609 | |
571 | 610 | /* convert ByteCount if necessary */ |
572 | 611 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
... | ... | @@ -574,8 +613,10 @@ |
574 | 613 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
575 | 614 | BCC(midQ->resp_buf) = |
576 | 615 | le16_to_cpu(BCC_LE(midQ->resp_buf)); |
577 | - midQ->resp_buf = NULL; /* mark it so will not be freed | |
578 | - by DeleteMidQEntry */ | |
616 | + if ((flags & CIFS_NO_RESP) == 0) | |
617 | + midQ->resp_buf = NULL; /* mark it so buf will | |
618 | + not be freed by | |
619 | + DeleteMidQEntry */ | |
579 | 620 | } else { |
580 | 621 | rc = -EIO; |
581 | 622 | cFYI(1, ("Bad MID state?")); |
582 | 623 | |
583 | 624 | |
584 | 625 | |
... | ... | @@ -663,17 +704,25 @@ |
663 | 704 | if (rc < 0) |
664 | 705 | goto out; |
665 | 706 | |
666 | - if (long_op == -1) | |
707 | + if (long_op == CIFS_STD_OP) | |
708 | + timeout = 15 * HZ; | |
709 | + /* wait for 15 seconds or until woken up due to response arriving or | |
710 | + due to last connection to this server being unmounted */ | |
711 | + else if (long_op == CIFS_ASYNC_OP) | |
667 | 712 | goto out; |
668 | - else if (long_op == 2) /* writes past end of file can take loong time */ | |
713 | + else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ | |
669 | 714 | timeout = 180 * HZ; |
670 | - else if (long_op == 1) | |
715 | + else if (long_op == CIFS_LONG_OP) | |
671 | 716 | timeout = 45 * HZ; /* should be greater than |
672 | 717 | servers oplock break timeout (about 43 seconds) */ |
673 | - else | |
674 | - timeout = 15 * HZ; | |
675 | - /* wait for 15 seconds or until woken up due to response arriving or | |
676 | - due to last connection to this server being unmounted */ | |
718 | + else if (long_op == CIFS_BLOCKING_OP) | |
719 | + timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ | |
720 | + else { | |
721 | + cERROR(1, ("unknown timeout flag %d", long_op)); | |
722 | + rc = -EIO; | |
723 | + goto out; | |
724 | + } | |
725 | + | |
677 | 726 | if (signal_pending(current)) { |
678 | 727 | /* if signal pending do not hold up user for full smb timeout |
679 | 728 | but we still give response a chance to complete */ |
... | ... | @@ -812,7 +861,7 @@ |
812 | 861 | pSMB->hdr.Mid = GetNextMid(ses->server); |
813 | 862 | |
814 | 863 | return SendReceive(xid, ses, in_buf, out_buf, |
815 | - &bytes_returned, 0); | |
864 | + &bytes_returned, CIFS_STD_OP); | |
816 | 865 | } |
817 | 866 | |
818 | 867 | int |
... | ... | @@ -844,7 +893,7 @@ |
844 | 893 | to the same server. We may make this configurable later or |
845 | 894 | use ses->maxReq */ |
846 | 895 | |
847 | - rc = wait_for_free_request(ses, 3); | |
896 | + rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | |
848 | 897 | if (rc) |
849 | 898 | return rc; |
850 | 899 |