diff options
author | Steve French <sfrench@us.ibm.com> | 2005-10-03 16:37:24 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-10-03 16:37:24 -0400 |
commit | 3e84469d0101456caceffc6b22218a49017fcd3f (patch) | |
tree | 2e52687ade7f3e52b5621142997ca6e7b38df70a /fs/cifs/cifssmb.c | |
parent | 70ca734a14366b634224a1e4586d43b36b65ab67 (diff) |
[CIFS] Add writepages support to shrink memory usage on writes,
eliminate the double copy, and improve cifs write performance and
help the server by upping the typical write size from 4K to 16K
(or even larger if wsize set explicitly) for servers which support this.
Part 1 of 2
Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 41 |
1 files changed, 17 insertions, 24 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 52caac063a77..365949c14646 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon | 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon |
126 | , nls_codepage); | 126 | , nls_codepage); |
127 | up(&tcon->ses->sesSem); | 127 | up(&tcon->ses->sesSem); |
128 | /* BB FIXME add code to check if wsize needs | ||
129 | update due to negotiated smb buffer size | ||
130 | shrinking */ | ||
128 | if(rc == 0) | 131 | if(rc == 0) |
129 | atomic_inc(&tconInfoReconnectCount); | 132 | atomic_inc(&tconInfoReconnectCount); |
130 | 133 | ||
@@ -220,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
220 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 223 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
221 | tcon, nls_codepage); | 224 | tcon, nls_codepage); |
222 | up(&tcon->ses->sesSem); | 225 | up(&tcon->ses->sesSem); |
226 | /* BB FIXME add code to check if wsize needs | ||
227 | update due to negotiated smb buffer size | ||
228 | shrinking */ | ||
223 | if(rc == 0) | 229 | if(rc == 0) |
224 | atomic_inc(&tconInfoReconnectCount); | 230 | atomic_inc(&tconInfoReconnectCount); |
225 | 231 | ||
@@ -1128,15 +1134,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1128 | int | 1134 | int |
1129 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1135 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
1130 | const int netfid, const unsigned int count, | 1136 | const int netfid, const unsigned int count, |
1131 | const __u64 offset, unsigned int *nbytes, const char *buf, | 1137 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, |
1132 | const int long_op) | 1138 | int n_vec, const int long_op) |
1133 | { | 1139 | { |
1134 | int rc = -EACCES; | 1140 | int rc = -EACCES; |
1135 | WRITE_REQ *pSMB = NULL; | 1141 | WRITE_REQ *pSMB = NULL; |
1136 | int bytes_returned; | 1142 | int bytes_returned; |
1137 | int smb_hdr_len; | 1143 | int smb_hdr_len; |
1138 | __u32 bytes_sent; | ||
1139 | __u16 byte_count; | ||
1140 | 1144 | ||
1141 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ | 1145 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ |
1142 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1146 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); |
@@ -1154,31 +1158,20 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1154 | pSMB->WriteMode = 0; | 1158 | pSMB->WriteMode = 0; |
1155 | pSMB->Remaining = 0; | 1159 | pSMB->Remaining = 0; |
1156 | 1160 | ||
1157 | /* Can increase buffer size if buffer is big enough in some cases - ie | ||
1158 | can send more if LARGE_WRITE_X capability returned by the server and if | ||
1159 | our buffer is big enough or if we convert to iovecs on socket writes | ||
1160 | and eliminate the copy to the CIFS buffer */ | ||
1161 | if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | ||
1162 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | ||
1163 | } else { | ||
1164 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | ||
1165 | & ~0xFF; | ||
1166 | } | ||
1167 | |||
1168 | if (bytes_sent > count) | ||
1169 | bytes_sent = count; | ||
1170 | pSMB->DataOffset = | 1161 | pSMB->DataOffset = |
1171 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1162 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
1172 | 1163 | ||
1173 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | 1164 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
1174 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1165 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
1175 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | ||
1176 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ | 1166 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
1177 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1167 | pSMB->hdr.smb_buf_length += count+1; |
1178 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1168 | pSMB->ByteCount = cpu_to_le16(count + 1); |
1169 | |||
1170 | iov[0].iov_base = pSMB; | ||
1171 | iov[0].iov_len = smb_hdr_len + 4; | ||
1179 | 1172 | ||
1180 | rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len, | 1173 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, |
1181 | buf, bytes_sent, &bytes_returned, long_op); | 1174 | long_op); |
1182 | cifs_stats_inc(&tcon->num_writes); | 1175 | cifs_stats_inc(&tcon->num_writes); |
1183 | if (rc) { | 1176 | if (rc) { |
1184 | cFYI(1, ("Send error in write = %d", rc)); | 1177 | cFYI(1, ("Send error in write = %d", rc)); |