diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ff374063f4e2..e18671852d41 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
34 | #include <linux/task_io_accounting_ops.h> | ||
34 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
35 | #include <linux/xattr.h> | 36 | #include <linux/xattr.h> |
36 | #include "smb2pdu.h" | 37 | #include "smb2pdu.h" |
@@ -42,6 +43,7 @@ | |||
42 | #include "cifs_debug.h" | 43 | #include "cifs_debug.h" |
43 | #include "ntlmssp.h" | 44 | #include "ntlmssp.h" |
44 | #include "smb2status.h" | 45 | #include "smb2status.h" |
46 | #include "smb2glob.h" | ||
45 | 47 | ||
46 | /* | 48 | /* |
47 | * The following table defines the expected "StructureSize" of SMB2 requests | 49 | * The following table defines the expected "StructureSize" of SMB2 requests |
@@ -1190,3 +1192,138 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
1190 | free_rsp_buf(resp_buftype, iov[0].iov_base); | 1192 | free_rsp_buf(resp_buftype, iov[0].iov_base); |
1191 | return rc; | 1193 | return rc; |
1192 | } | 1194 | } |
1195 | |||
1196 | /* | ||
1197 | * To form a chain of read requests, any read requests after the first should | ||
1198 | * have the end_of_chain boolean set to true. | ||
1199 | */ | ||
1200 | static int | ||
1201 | smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms, | ||
1202 | unsigned int remaining_bytes, int request_type) | ||
1203 | { | ||
1204 | int rc = -EACCES; | ||
1205 | struct smb2_read_req *req = NULL; | ||
1206 | |||
1207 | rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req); | ||
1208 | if (rc) | ||
1209 | return rc; | ||
1210 | if (io_parms->tcon->ses->server == NULL) | ||
1211 | return -ECONNABORTED; | ||
1212 | |||
1213 | req->hdr.ProcessId = cpu_to_le32(io_parms->pid); | ||
1214 | |||
1215 | req->PersistentFileId = io_parms->persistent_fid; | ||
1216 | req->VolatileFileId = io_parms->volatile_fid; | ||
1217 | req->ReadChannelInfoOffset = 0; /* reserved */ | ||
1218 | req->ReadChannelInfoLength = 0; /* reserved */ | ||
1219 | req->Channel = 0; /* reserved */ | ||
1220 | req->MinimumCount = 0; | ||
1221 | req->Length = cpu_to_le32(io_parms->length); | ||
1222 | req->Offset = cpu_to_le64(io_parms->offset); | ||
1223 | |||
1224 | if (request_type & CHAINED_REQUEST) { | ||
1225 | if (!(request_type & END_OF_CHAIN)) { | ||
1226 | /* 4 for rfc1002 length field */ | ||
1227 | req->hdr.NextCommand = | ||
1228 | cpu_to_le32(get_rfc1002_length(req) + 4); | ||
1229 | } else /* END_OF_CHAIN */ | ||
1230 | req->hdr.NextCommand = 0; | ||
1231 | if (request_type & RELATED_REQUEST) { | ||
1232 | req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS; | ||
1233 | /* | ||
1234 | * Related requests use info from previous read request | ||
1235 | * in chain. | ||
1236 | */ | ||
1237 | req->hdr.SessionId = 0xFFFFFFFF; | ||
1238 | req->hdr.TreeId = 0xFFFFFFFF; | ||
1239 | req->PersistentFileId = 0xFFFFFFFF; | ||
1240 | req->VolatileFileId = 0xFFFFFFFF; | ||
1241 | } | ||
1242 | } | ||
1243 | if (remaining_bytes > io_parms->length) | ||
1244 | req->RemainingBytes = cpu_to_le32(remaining_bytes); | ||
1245 | else | ||
1246 | req->RemainingBytes = 0; | ||
1247 | |||
1248 | iov[0].iov_base = (char *)req; | ||
1249 | /* 4 for rfc1002 length field */ | ||
1250 | iov[0].iov_len = get_rfc1002_length(req) + 4; | ||
1251 | return rc; | ||
1252 | } | ||
1253 | |||
1254 | static void | ||
1255 | smb2_readv_callback(struct mid_q_entry *mid) | ||
1256 | { | ||
1257 | struct cifs_readdata *rdata = mid->callback_data; | ||
1258 | struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink); | ||
1259 | struct TCP_Server_Info *server = tcon->ses->server; | ||
1260 | struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov[0].iov_base; | ||
1261 | unsigned int credits_received = 1; | ||
1262 | |||
1263 | cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__, | ||
1264 | mid->mid, mid->mid_state, rdata->result, rdata->bytes); | ||
1265 | |||
1266 | switch (mid->mid_state) { | ||
1267 | case MID_RESPONSE_RECEIVED: | ||
1268 | credits_received = le16_to_cpu(buf->CreditRequest); | ||
1269 | /* result already set, check signature */ | ||
1270 | /* if (server->sec_mode & | ||
1271 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1272 | if (smb2_verify_signature(mid->resp_buf, server)) | ||
1273 | cERROR(1, "Unexpected SMB signature"); */ | ||
1274 | /* FIXME: should this be counted toward the initiating task? */ | ||
1275 | task_io_account_read(rdata->bytes); | ||
1276 | cifs_stats_bytes_read(tcon, rdata->bytes); | ||
1277 | break; | ||
1278 | case MID_REQUEST_SUBMITTED: | ||
1279 | case MID_RETRY_NEEDED: | ||
1280 | rdata->result = -EAGAIN; | ||
1281 | break; | ||
1282 | default: | ||
1283 | if (rdata->result != -ENODATA) | ||
1284 | rdata->result = -EIO; | ||
1285 | } | ||
1286 | |||
1287 | if (rdata->result) | ||
1288 | cifs_stats_fail_inc(tcon, SMB2_READ_HE); | ||
1289 | |||
1290 | queue_work(cifsiod_wq, &rdata->work); | ||
1291 | DeleteMidQEntry(mid); | ||
1292 | add_credits(server, credits_received, 0); | ||
1293 | } | ||
1294 | |||
1295 | /* smb2_async_readv - send an async write, and set up mid to handle result */ | ||
1296 | int | ||
1297 | smb2_async_readv(struct cifs_readdata *rdata) | ||
1298 | { | ||
1299 | int rc; | ||
1300 | struct smb2_hdr *buf; | ||
1301 | struct cifs_io_parms io_parms; | ||
1302 | |||
1303 | cFYI(1, "%s: offset=%llu bytes=%u", __func__, | ||
1304 | rdata->offset, rdata->bytes); | ||
1305 | |||
1306 | io_parms.tcon = tlink_tcon(rdata->cfile->tlink); | ||
1307 | io_parms.offset = rdata->offset; | ||
1308 | io_parms.length = rdata->bytes; | ||
1309 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; | ||
1310 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; | ||
1311 | io_parms.pid = rdata->pid; | ||
1312 | rc = smb2_new_read_req(&rdata->iov[0], &io_parms, 0, 0); | ||
1313 | if (rc) | ||
1314 | return rc; | ||
1315 | |||
1316 | buf = (struct smb2_hdr *)rdata->iov[0].iov_base; | ||
1317 | /* 4 for rfc1002 length field */ | ||
1318 | rdata->iov[0].iov_len = get_rfc1002_length(rdata->iov[0].iov_base) + 4; | ||
1319 | |||
1320 | kref_get(&rdata->refcount); | ||
1321 | rc = cifs_call_async(io_parms.tcon->ses->server, rdata->iov, 1, | ||
1322 | cifs_readv_receive, smb2_readv_callback, | ||
1323 | rdata, 0); | ||
1324 | if (rc) | ||
1325 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
1326 | |||
1327 | cifs_small_buf_release(buf); | ||
1328 | return rc; | ||
1329 | } | ||