.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * SMB2 version specific operations |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> |
---|
5 | | - * |
---|
6 | | - * This library is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License v2 as published |
---|
8 | | - * by the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This library is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
---|
13 | | - * the GNU Lesser General Public License for more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU Lesser General Public License |
---|
16 | | - * along with this library; if not, write to the Free Software |
---|
17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
18 | 6 | */ |
---|
19 | 7 | |
---|
20 | 8 | #include <linux/pagemap.h> |
---|
.. | .. |
---|
22 | 10 | #include <linux/falloc.h> |
---|
23 | 11 | #include <linux/scatterlist.h> |
---|
24 | 12 | #include <linux/uuid.h> |
---|
| 13 | +#include <linux/sort.h> |
---|
25 | 14 | #include <crypto/aead.h> |
---|
| 15 | +#include <linux/fiemap.h> |
---|
| 16 | +#include "cifsfs.h" |
---|
26 | 17 | #include "cifsglob.h" |
---|
27 | 18 | #include "smb2pdu.h" |
---|
28 | 19 | #include "smb2proto.h" |
---|
.. | .. |
---|
67 | 58 | } |
---|
68 | 59 | |
---|
69 | 60 | static void |
---|
70 | | -smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, |
---|
71 | | - const int optype) |
---|
| 61 | +smb2_add_credits(struct TCP_Server_Info *server, |
---|
| 62 | + const struct cifs_credits *credits, const int optype) |
---|
72 | 63 | { |
---|
73 | 64 | int *val, rc = -1; |
---|
| 65 | + unsigned int add = credits->value; |
---|
| 66 | + unsigned int instance = credits->instance; |
---|
| 67 | + bool reconnect_detected = false; |
---|
74 | 68 | |
---|
75 | 69 | spin_lock(&server->req_lock); |
---|
76 | 70 | val = server->ops->get_credits_field(server, optype); |
---|
77 | | - *val += add; |
---|
| 71 | + |
---|
| 72 | + /* eg found case where write overlapping reconnect messed up credits */ |
---|
| 73 | + if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) |
---|
| 74 | + trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, |
---|
| 75 | + server->hostname, *val, add); |
---|
| 76 | + if ((instance == 0) || (instance == server->reconnect_instance)) |
---|
| 77 | + *val += add; |
---|
| 78 | + else |
---|
| 79 | + reconnect_detected = true; |
---|
| 80 | + |
---|
78 | 81 | if (*val > 65000) { |
---|
79 | 82 | *val = 65000; /* Don't get near 64K credits, avoid srv bugs */ |
---|
80 | | - printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); |
---|
| 83 | + pr_warn_once("server overflowed SMB3 credits\n"); |
---|
81 | 84 | } |
---|
82 | 85 | server->in_flight--; |
---|
83 | 86 | if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) |
---|
.. | .. |
---|
96 | 99 | spin_unlock(&server->req_lock); |
---|
97 | 100 | wake_up(&server->request_q); |
---|
98 | 101 | |
---|
99 | | - if (server->tcpStatus == CifsNeedReconnect) |
---|
| 102 | + if (reconnect_detected) |
---|
| 103 | + cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n", |
---|
| 104 | + add, instance); |
---|
| 105 | + |
---|
| 106 | + if (server->tcpStatus == CifsNeedReconnect |
---|
| 107 | + || server->tcpStatus == CifsExiting) |
---|
100 | 108 | return; |
---|
101 | 109 | |
---|
102 | 110 | switch (rc) { |
---|
.. | .. |
---|
104 | 112 | /* change_conf hasn't been executed */ |
---|
105 | 113 | break; |
---|
106 | 114 | case 0: |
---|
107 | | - cifs_dbg(VFS, "Possible client or server bug - zero credits\n"); |
---|
| 115 | + cifs_server_dbg(VFS, "Possible client or server bug - zero credits\n"); |
---|
108 | 116 | break; |
---|
109 | 117 | case 1: |
---|
110 | | - cifs_dbg(VFS, "disabling echoes and oplocks\n"); |
---|
| 118 | + cifs_server_dbg(VFS, "disabling echoes and oplocks\n"); |
---|
111 | 119 | break; |
---|
112 | 120 | case 2: |
---|
113 | 121 | cifs_dbg(FYI, "disabling oplocks\n"); |
---|
114 | 122 | break; |
---|
115 | 123 | default: |
---|
| 124 | + trace_smb3_add_credits(server->CurrentMid, |
---|
| 125 | + server->hostname, rc, add); |
---|
116 | 126 | cifs_dbg(FYI, "add %u credits total=%d\n", add, rc); |
---|
117 | 127 | } |
---|
118 | 128 | } |
---|
.. | .. |
---|
122 | 132 | { |
---|
123 | 133 | spin_lock(&server->req_lock); |
---|
124 | 134 | server->credits = val; |
---|
| 135 | + if (val == 1) |
---|
| 136 | + server->reconnect_instance++; |
---|
125 | 137 | spin_unlock(&server->req_lock); |
---|
| 138 | + /* don't log while holding the lock */ |
---|
| 139 | + if (val == 1) |
---|
| 140 | + cifs_dbg(FYI, "set credits to 1 due to smb2 reconnect\n"); |
---|
126 | 141 | } |
---|
127 | 142 | |
---|
128 | 143 | static int * |
---|
.. | .. |
---|
141 | 156 | static unsigned int |
---|
142 | 157 | smb2_get_credits(struct mid_q_entry *mid) |
---|
143 | 158 | { |
---|
144 | | - struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf; |
---|
145 | | - |
---|
146 | | - return le16_to_cpu(shdr->CreditRequest); |
---|
| 159 | + return mid->credits_received; |
---|
147 | 160 | } |
---|
148 | 161 | |
---|
149 | 162 | static int |
---|
150 | 163 | smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, |
---|
151 | | - unsigned int *num, unsigned int *credits) |
---|
| 164 | + unsigned int *num, struct cifs_credits *credits) |
---|
152 | 165 | { |
---|
153 | 166 | int rc = 0; |
---|
154 | 167 | unsigned int scredits; |
---|
.. | .. |
---|
159 | 172 | spin_unlock(&server->req_lock); |
---|
160 | 173 | cifs_num_waiters_inc(server); |
---|
161 | 174 | rc = wait_event_killable(server->request_q, |
---|
162 | | - has_credits(server, &server->credits)); |
---|
| 175 | + has_credits(server, &server->credits, 1)); |
---|
163 | 176 | cifs_num_waiters_dec(server); |
---|
164 | 177 | if (rc) |
---|
165 | 178 | return rc; |
---|
.. | .. |
---|
174 | 187 | /* can deadlock with reopen */ |
---|
175 | 188 | if (scredits <= 8) { |
---|
176 | 189 | *num = SMB2_MAX_BUFFER_SIZE; |
---|
177 | | - *credits = 0; |
---|
| 190 | + credits->value = 0; |
---|
| 191 | + credits->instance = 0; |
---|
178 | 192 | break; |
---|
179 | 193 | } |
---|
180 | 194 | |
---|
.. | .. |
---|
183 | 197 | *num = min_t(unsigned int, size, |
---|
184 | 198 | scredits * SMB2_MAX_BUFFER_SIZE); |
---|
185 | 199 | |
---|
186 | | - *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); |
---|
187 | | - server->credits -= *credits; |
---|
| 200 | + credits->value = |
---|
| 201 | + DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); |
---|
| 202 | + credits->instance = server->reconnect_instance; |
---|
| 203 | + server->credits -= credits->value; |
---|
188 | 204 | server->in_flight++; |
---|
| 205 | + if (server->in_flight > server->max_in_flight) |
---|
| 206 | + server->max_in_flight = server->in_flight; |
---|
189 | 207 | break; |
---|
190 | 208 | } |
---|
191 | 209 | } |
---|
192 | 210 | spin_unlock(&server->req_lock); |
---|
193 | 211 | return rc; |
---|
| 212 | +} |
---|
| 213 | + |
---|
| 214 | +static int |
---|
| 215 | +smb2_adjust_credits(struct TCP_Server_Info *server, |
---|
| 216 | + struct cifs_credits *credits, |
---|
| 217 | + const unsigned int payload_size) |
---|
| 218 | +{ |
---|
| 219 | + int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); |
---|
| 220 | + |
---|
| 221 | + if (!credits->value || credits->value == new_val) |
---|
| 222 | + return 0; |
---|
| 223 | + |
---|
| 224 | + if (credits->value < new_val) { |
---|
| 225 | + WARN_ONCE(1, "request has less credits (%d) than required (%d)", |
---|
| 226 | + credits->value, new_val); |
---|
| 227 | + return -ENOTSUPP; |
---|
| 228 | + } |
---|
| 229 | + |
---|
| 230 | + spin_lock(&server->req_lock); |
---|
| 231 | + |
---|
| 232 | + if (server->reconnect_instance != credits->instance) { |
---|
| 233 | + spin_unlock(&server->req_lock); |
---|
| 234 | + cifs_server_dbg(VFS, "trying to return %d credits to old session\n", |
---|
| 235 | + credits->value - new_val); |
---|
| 236 | + return -EAGAIN; |
---|
| 237 | + } |
---|
| 238 | + |
---|
| 239 | + server->credits += credits->value - new_val; |
---|
| 240 | + spin_unlock(&server->req_lock); |
---|
| 241 | + wake_up(&server->request_q); |
---|
| 242 | + credits->value = new_val; |
---|
| 243 | + return 0; |
---|
194 | 244 | } |
---|
195 | 245 | |
---|
196 | 246 | static __u64 |
---|
.. | .. |
---|
214 | 264 | } |
---|
215 | 265 | |
---|
216 | 266 | static struct mid_q_entry * |
---|
217 | | -smb2_find_mid(struct TCP_Server_Info *server, char *buf) |
---|
| 267 | +__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue) |
---|
218 | 268 | { |
---|
219 | 269 | struct mid_q_entry *mid; |
---|
220 | 270 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; |
---|
221 | 271 | __u64 wire_mid = le64_to_cpu(shdr->MessageId); |
---|
222 | 272 | |
---|
223 | 273 | if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { |
---|
224 | | - cifs_dbg(VFS, "encrypted frame parsing not supported yet"); |
---|
| 274 | + cifs_server_dbg(VFS, "Encrypted frame parsing not supported yet\n"); |
---|
225 | 275 | return NULL; |
---|
226 | 276 | } |
---|
227 | 277 | |
---|
.. | .. |
---|
231 | 281 | (mid->mid_state == MID_REQUEST_SUBMITTED) && |
---|
232 | 282 | (mid->command == shdr->Command)) { |
---|
233 | 283 | kref_get(&mid->refcount); |
---|
| 284 | + if (dequeue) { |
---|
| 285 | + list_del_init(&mid->qhead); |
---|
| 286 | + mid->mid_flags |= MID_DELETED; |
---|
| 287 | + } |
---|
234 | 288 | spin_unlock(&GlobalMid_Lock); |
---|
235 | 289 | return mid; |
---|
236 | 290 | } |
---|
.. | .. |
---|
239 | 293 | return NULL; |
---|
240 | 294 | } |
---|
241 | 295 | |
---|
| 296 | +static struct mid_q_entry * |
---|
| 297 | +smb2_find_mid(struct TCP_Server_Info *server, char *buf) |
---|
| 298 | +{ |
---|
| 299 | + return __smb2_find_mid(server, buf, false); |
---|
| 300 | +} |
---|
| 301 | + |
---|
| 302 | +static struct mid_q_entry * |
---|
| 303 | +smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf) |
---|
| 304 | +{ |
---|
| 305 | + return __smb2_find_mid(server, buf, true); |
---|
| 306 | +} |
---|
| 307 | + |
---|
242 | 308 | static void |
---|
243 | 309 | smb2_dump_detail(void *buf, struct TCP_Server_Info *server) |
---|
244 | 310 | { |
---|
245 | 311 | #ifdef CONFIG_CIFS_DEBUG2 |
---|
246 | 312 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; |
---|
247 | 313 | |
---|
248 | | - cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", |
---|
| 314 | + cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", |
---|
249 | 315 | shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId, |
---|
250 | 316 | shdr->ProcessId); |
---|
251 | | - cifs_dbg(VFS, "smb buf %p len %u\n", buf, |
---|
| 317 | + cifs_server_dbg(VFS, "smb buf %p len %u\n", buf, |
---|
252 | 318 | server->ops->calc_smb_size(buf, server)); |
---|
253 | 319 | #endif |
---|
254 | 320 | } |
---|
.. | .. |
---|
263 | 329 | smb2_negotiate(const unsigned int xid, struct cifs_ses *ses) |
---|
264 | 330 | { |
---|
265 | 331 | int rc; |
---|
266 | | - ses->server->CurrentMid = 0; |
---|
| 332 | + |
---|
| 333 | + cifs_ses_server(ses)->CurrentMid = 0; |
---|
267 | 334 | rc = SMB2_negotiate(xid, ses); |
---|
268 | 335 | /* BB we probably don't need to retry with modern servers */ |
---|
269 | 336 | if (rc == -EAGAIN) |
---|
.. | .. |
---|
280 | 347 | /* start with specified wsize, or default */ |
---|
281 | 348 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; |
---|
282 | 349 | wsize = min_t(unsigned int, wsize, server->max_write); |
---|
| 350 | + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
---|
| 351 | + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); |
---|
| 352 | + |
---|
| 353 | + return wsize; |
---|
| 354 | +} |
---|
| 355 | + |
---|
| 356 | +static unsigned int |
---|
| 357 | +smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) |
---|
| 358 | +{ |
---|
| 359 | + struct TCP_Server_Info *server = tcon->ses->server; |
---|
| 360 | + unsigned int wsize; |
---|
| 361 | + |
---|
| 362 | + /* start with specified wsize, or default */ |
---|
| 363 | + wsize = volume_info->wsize ? volume_info->wsize : SMB3_DEFAULT_IOSIZE; |
---|
| 364 | + wsize = min_t(unsigned int, wsize, server->max_write); |
---|
283 | 365 | #ifdef CONFIG_CIFS_SMB_DIRECT |
---|
284 | 366 | if (server->rdma) { |
---|
285 | 367 | if (server->sign) |
---|
| 368 | + /* |
---|
| 369 | + * Account for SMB2 data transfer packet header and |
---|
| 370 | + * possible encryption header |
---|
| 371 | + */ |
---|
286 | 372 | wsize = min_t(unsigned int, |
---|
287 | | - wsize, server->smbd_conn->max_fragmented_send_size); |
---|
| 373 | + wsize, |
---|
| 374 | + server->smbd_conn->max_fragmented_send_size - |
---|
| 375 | + SMB2_READWRITE_PDU_HEADER_SIZE - |
---|
| 376 | + sizeof(struct smb2_transform_hdr)); |
---|
288 | 377 | else |
---|
289 | 378 | wsize = min_t(unsigned int, |
---|
290 | 379 | wsize, server->smbd_conn->max_readwrite_size); |
---|
.. | .. |
---|
305 | 394 | /* start with specified rsize, or default */ |
---|
306 | 395 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; |
---|
307 | 396 | rsize = min_t(unsigned int, rsize, server->max_read); |
---|
| 397 | + |
---|
| 398 | + if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
---|
| 399 | + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); |
---|
| 400 | + |
---|
| 401 | + return rsize; |
---|
| 402 | +} |
---|
| 403 | + |
---|
| 404 | +static unsigned int |
---|
| 405 | +smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) |
---|
| 406 | +{ |
---|
| 407 | + struct TCP_Server_Info *server = tcon->ses->server; |
---|
| 408 | + unsigned int rsize; |
---|
| 409 | + |
---|
| 410 | + /* start with specified rsize, or default */ |
---|
| 411 | + rsize = volume_info->rsize ? volume_info->rsize : SMB3_DEFAULT_IOSIZE; |
---|
| 412 | + rsize = min_t(unsigned int, rsize, server->max_read); |
---|
308 | 413 | #ifdef CONFIG_CIFS_SMB_DIRECT |
---|
309 | 414 | if (server->rdma) { |
---|
310 | 415 | if (server->sign) |
---|
| 416 | + /* |
---|
| 417 | + * Account for SMB2 data transfer packet header and |
---|
| 418 | + * possible encryption header |
---|
| 419 | + */ |
---|
311 | 420 | rsize = min_t(unsigned int, |
---|
312 | | - rsize, server->smbd_conn->max_fragmented_recv_size); |
---|
| 421 | + rsize, |
---|
| 422 | + server->smbd_conn->max_fragmented_recv_size - |
---|
| 423 | + SMB2_READWRITE_PDU_HEADER_SIZE - |
---|
| 424 | + sizeof(struct smb2_transform_hdr)); |
---|
313 | 425 | else |
---|
314 | 426 | rsize = min_t(unsigned int, |
---|
315 | 427 | rsize, server->smbd_conn->max_readwrite_size); |
---|
.. | .. |
---|
321 | 433 | |
---|
322 | 434 | return rsize; |
---|
323 | 435 | } |
---|
324 | | - |
---|
325 | 436 | |
---|
326 | 437 | static int |
---|
327 | 438 | parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, |
---|
.. | .. |
---|
457 | 568 | return rc; |
---|
458 | 569 | } |
---|
459 | 570 | |
---|
| 571 | +static int compare_iface(const void *ia, const void *ib) |
---|
| 572 | +{ |
---|
| 573 | + const struct cifs_server_iface *a = (struct cifs_server_iface *)ia; |
---|
| 574 | + const struct cifs_server_iface *b = (struct cifs_server_iface *)ib; |
---|
| 575 | + |
---|
| 576 | + return a->speed == b->speed ? 0 : (a->speed > b->speed ? -1 : 1); |
---|
| 577 | +} |
---|
460 | 578 | |
---|
461 | 579 | static int |
---|
462 | 580 | SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) |
---|
.. | .. |
---|
469 | 587 | struct cifs_ses *ses = tcon->ses; |
---|
470 | 588 | |
---|
471 | 589 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
---|
472 | | - FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, |
---|
| 590 | + FSCTL_QUERY_NETWORK_INTERFACE_INFO, |
---|
473 | 591 | NULL /* no data input */, 0 /* no data input */, |
---|
474 | | - (char **)&out_buf, &ret_data_len); |
---|
| 592 | + CIFSMaxBufSize, (char **)&out_buf, &ret_data_len); |
---|
475 | 593 | if (rc == -EOPNOTSUPP) { |
---|
476 | 594 | cifs_dbg(FYI, |
---|
477 | 595 | "server does not support query network interfaces\n"); |
---|
478 | | - goto out; |
---|
| 596 | + ret_data_len = 0; |
---|
479 | 597 | } else if (rc != 0) { |
---|
480 | | - cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc); |
---|
| 598 | + cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc); |
---|
481 | 599 | goto out; |
---|
482 | 600 | } |
---|
483 | 601 | |
---|
.. | .. |
---|
485 | 603 | &iface_list, &iface_count); |
---|
486 | 604 | if (rc) |
---|
487 | 605 | goto out; |
---|
| 606 | + |
---|
| 607 | + /* sort interfaces from fastest to slowest */ |
---|
| 608 | + sort(iface_list, iface_count, sizeof(*iface_list), compare_iface, NULL); |
---|
488 | 609 | |
---|
489 | 610 | spin_lock(&ses->iface_lock); |
---|
490 | 611 | kfree(ses->iface_list); |
---|
.. | .. |
---|
509 | 630 | SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid, |
---|
510 | 631 | cfid->fid->volatile_fid); |
---|
511 | 632 | cfid->is_valid = false; |
---|
| 633 | + cfid->file_all_info_is_valid = false; |
---|
| 634 | + cfid->has_lease = false; |
---|
512 | 635 | } |
---|
513 | 636 | } |
---|
514 | 637 | |
---|
.. | .. |
---|
519 | 642 | mutex_unlock(&cfid->fid_mutex); |
---|
520 | 643 | } |
---|
521 | 644 | |
---|
| 645 | +void close_shroot_lease_locked(struct cached_fid *cfid) |
---|
| 646 | +{ |
---|
| 647 | + if (cfid->has_lease) { |
---|
| 648 | + cfid->has_lease = false; |
---|
| 649 | + kref_put(&cfid->refcount, smb2_close_cached_fid); |
---|
| 650 | + } |
---|
| 651 | +} |
---|
| 652 | + |
---|
| 653 | +void close_shroot_lease(struct cached_fid *cfid) |
---|
| 654 | +{ |
---|
| 655 | + mutex_lock(&cfid->fid_mutex); |
---|
| 656 | + close_shroot_lease_locked(cfid); |
---|
| 657 | + mutex_unlock(&cfid->fid_mutex); |
---|
| 658 | +} |
---|
| 659 | + |
---|
522 | 660 | void |
---|
523 | 661 | smb2_cached_lease_break(struct work_struct *work) |
---|
524 | 662 | { |
---|
525 | 663 | struct cached_fid *cfid = container_of(work, |
---|
526 | 664 | struct cached_fid, lease_break); |
---|
527 | 665 | |
---|
528 | | - close_shroot(cfid); |
---|
| 666 | + close_shroot_lease(cfid); |
---|
529 | 667 | } |
---|
530 | 668 | |
---|
531 | 669 | /* |
---|
532 | 670 | * Open the directory at the root of a share |
---|
533 | 671 | */ |
---|
534 | | -int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) |
---|
| 672 | +int open_shroot(unsigned int xid, struct cifs_tcon *tcon, |
---|
| 673 | + struct cifs_sb_info *cifs_sb, |
---|
| 674 | + struct cached_fid **cfid) |
---|
535 | 675 | { |
---|
536 | | - struct cifs_open_parms oparams; |
---|
537 | | - int rc; |
---|
538 | | - __le16 srch_path = 0; /* Null - since an open of top of share */ |
---|
| 676 | + struct cifs_ses *ses = tcon->ses; |
---|
| 677 | + struct TCP_Server_Info *server = ses->server; |
---|
| 678 | + struct cifs_open_parms oparms; |
---|
| 679 | + struct smb2_create_rsp *o_rsp = NULL; |
---|
| 680 | + struct smb2_query_info_rsp *qi_rsp = NULL; |
---|
| 681 | + int resp_buftype[2]; |
---|
| 682 | + struct smb_rqst rqst[2]; |
---|
| 683 | + struct kvec rsp_iov[2]; |
---|
| 684 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 685 | + struct kvec qi_iov[1]; |
---|
| 686 | + int rc, flags = 0; |
---|
| 687 | + __le16 utf16_path = 0; /* Null - since an open of top of share */ |
---|
539 | 688 | u8 oplock = SMB2_OPLOCK_LEVEL_II; |
---|
| 689 | + struct cifs_fid *pfid; |
---|
540 | 690 | |
---|
541 | 691 | mutex_lock(&tcon->crfid.fid_mutex); |
---|
542 | 692 | if (tcon->crfid.is_valid) { |
---|
543 | 693 | cifs_dbg(FYI, "found a cached root file handle\n"); |
---|
544 | | - memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid)); |
---|
| 694 | + *cfid = &tcon->crfid; |
---|
545 | 695 | kref_get(&tcon->crfid.refcount); |
---|
546 | 696 | mutex_unlock(&tcon->crfid.fid_mutex); |
---|
547 | 697 | return 0; |
---|
548 | 698 | } |
---|
549 | | - |
---|
550 | | - oparams.tcon = tcon; |
---|
551 | | - oparams.create_options = 0; |
---|
552 | | - oparams.desired_access = FILE_READ_ATTRIBUTES; |
---|
553 | | - oparams.disposition = FILE_OPEN; |
---|
554 | | - oparams.fid = pfid; |
---|
555 | | - oparams.reconnect = false; |
---|
556 | 699 | |
---|
557 | 700 | /* |
---|
558 | 701 | * We do not hold the lock for the open because in case |
---|
.. | .. |
---|
560 | 703 | * cifs_mark_open_files_invalid() which takes the lock again |
---|
561 | 704 | * thus causing a deadlock |
---|
562 | 705 | */ |
---|
| 706 | + |
---|
563 | 707 | mutex_unlock(&tcon->crfid.fid_mutex); |
---|
564 | | - rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL); |
---|
| 708 | + |
---|
| 709 | + if (smb3_encryption_required(tcon)) |
---|
| 710 | + flags |= CIFS_TRANSFORM_REQ; |
---|
| 711 | + |
---|
| 712 | + if (!server->ops->new_lease_key) |
---|
| 713 | + return -EIO; |
---|
| 714 | + |
---|
| 715 | + pfid = tcon->crfid.fid; |
---|
| 716 | + server->ops->new_lease_key(pfid); |
---|
| 717 | + |
---|
| 718 | + memset(rqst, 0, sizeof(rqst)); |
---|
| 719 | + resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER; |
---|
| 720 | + memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
| 721 | + |
---|
| 722 | + /* Open */ |
---|
| 723 | + memset(&open_iov, 0, sizeof(open_iov)); |
---|
| 724 | + rqst[0].rq_iov = open_iov; |
---|
| 725 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 726 | + |
---|
| 727 | + oparms.tcon = tcon; |
---|
| 728 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
| 729 | + oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
| 730 | + oparms.disposition = FILE_OPEN; |
---|
| 731 | + oparms.fid = pfid; |
---|
| 732 | + oparms.reconnect = false; |
---|
| 733 | + |
---|
| 734 | + rc = SMB2_open_init(tcon, server, |
---|
| 735 | + &rqst[0], &oplock, &oparms, &utf16_path); |
---|
| 736 | + if (rc) |
---|
| 737 | + goto oshr_free; |
---|
| 738 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
| 739 | + |
---|
| 740 | + memset(&qi_iov, 0, sizeof(qi_iov)); |
---|
| 741 | + rqst[1].rq_iov = qi_iov; |
---|
| 742 | + rqst[1].rq_nvec = 1; |
---|
| 743 | + |
---|
| 744 | + rc = SMB2_query_info_init(tcon, server, |
---|
| 745 | + &rqst[1], COMPOUND_FID, |
---|
| 746 | + COMPOUND_FID, FILE_ALL_INFORMATION, |
---|
| 747 | + SMB2_O_INFO_FILE, 0, |
---|
| 748 | + sizeof(struct smb2_file_all_info) + |
---|
| 749 | + PATH_MAX * 2, 0, NULL); |
---|
| 750 | + if (rc) |
---|
| 751 | + goto oshr_free; |
---|
| 752 | + |
---|
| 753 | + smb2_set_related(&rqst[1]); |
---|
| 754 | + |
---|
| 755 | + rc = compound_send_recv(xid, ses, server, |
---|
| 756 | + flags, 2, rqst, |
---|
| 757 | + resp_buftype, rsp_iov); |
---|
565 | 758 | mutex_lock(&tcon->crfid.fid_mutex); |
---|
566 | 759 | |
---|
567 | 760 | /* |
---|
.. | .. |
---|
579 | 772 | }; |
---|
580 | 773 | |
---|
581 | 774 | /* |
---|
582 | | - * Caller expects this func to set pfid to a valid |
---|
| 775 | + * caller expects this func to set pfid to a valid |
---|
583 | 776 | * cached root, so we copy the existing one and get a |
---|
584 | | - * reference |
---|
| 777 | + * reference. |
---|
585 | 778 | */ |
---|
586 | 779 | memcpy(pfid, tcon->crfid.fid, sizeof(*pfid)); |
---|
587 | 780 | kref_get(&tcon->crfid.refcount); |
---|
.. | .. |
---|
589 | 782 | mutex_unlock(&tcon->crfid.fid_mutex); |
---|
590 | 783 | |
---|
591 | 784 | if (rc == 0) { |
---|
592 | | - /* close extra handle outside of critical section */ |
---|
593 | | - SMB2_close(xid, tcon, fid.persistent_fid, |
---|
594 | | - fid.volatile_fid); |
---|
| 785 | + /* close extra handle outside of crit sec */ |
---|
| 786 | + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
595 | 787 | } |
---|
596 | | - return 0; |
---|
| 788 | + rc = 0; |
---|
| 789 | + goto oshr_free; |
---|
597 | 790 | } |
---|
598 | 791 | |
---|
599 | 792 | /* Cached root is still invalid, continue normaly */ |
---|
600 | 793 | |
---|
601 | | - if (rc == 0) { |
---|
602 | | - memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); |
---|
603 | | - tcon->crfid.tcon = tcon; |
---|
604 | | - tcon->crfid.is_valid = true; |
---|
605 | | - kref_init(&tcon->crfid.refcount); |
---|
606 | | - kref_get(&tcon->crfid.refcount); |
---|
| 794 | + if (rc) { |
---|
| 795 | + if (rc == -EREMCHG) { |
---|
| 796 | + tcon->need_reconnect = true; |
---|
| 797 | + pr_warn_once("server share %s deleted\n", |
---|
| 798 | + tcon->treeName); |
---|
| 799 | + } |
---|
| 800 | + goto oshr_exit; |
---|
607 | 801 | } |
---|
608 | 802 | |
---|
| 803 | + atomic_inc(&tcon->num_remote_opens); |
---|
| 804 | + |
---|
| 805 | + o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; |
---|
| 806 | + oparms.fid->persistent_fid = o_rsp->PersistentFileId; |
---|
| 807 | + oparms.fid->volatile_fid = o_rsp->VolatileFileId; |
---|
| 808 | +#ifdef CONFIG_CIFS_DEBUG2 |
---|
| 809 | + oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId); |
---|
| 810 | +#endif /* CIFS_DEBUG2 */ |
---|
| 811 | + |
---|
| 812 | + memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); |
---|
| 813 | + tcon->crfid.tcon = tcon; |
---|
| 814 | + tcon->crfid.is_valid = true; |
---|
| 815 | + kref_init(&tcon->crfid.refcount); |
---|
| 816 | + |
---|
| 817 | + /* BB TBD check to see if oplock level check can be removed below */ |
---|
| 818 | + if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { |
---|
| 819 | + kref_get(&tcon->crfid.refcount); |
---|
| 820 | + tcon->crfid.has_lease = true; |
---|
| 821 | + smb2_parse_contexts(server, o_rsp, |
---|
| 822 | + &oparms.fid->epoch, |
---|
| 823 | + oparms.fid->lease_key, &oplock, |
---|
| 824 | + NULL, NULL); |
---|
| 825 | + } else |
---|
| 826 | + goto oshr_exit; |
---|
| 827 | + |
---|
| 828 | + qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; |
---|
| 829 | + if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) |
---|
| 830 | + goto oshr_exit; |
---|
| 831 | + if (!smb2_validate_and_copy_iov( |
---|
| 832 | + le16_to_cpu(qi_rsp->OutputBufferOffset), |
---|
| 833 | + sizeof(struct smb2_file_all_info), |
---|
| 834 | + &rsp_iov[1], sizeof(struct smb2_file_all_info), |
---|
| 835 | + (char *)&tcon->crfid.file_all_info)) |
---|
| 836 | + tcon->crfid.file_all_info_is_valid = true; |
---|
| 837 | + |
---|
| 838 | +oshr_exit: |
---|
609 | 839 | mutex_unlock(&tcon->crfid.fid_mutex); |
---|
| 840 | +oshr_free: |
---|
| 841 | + SMB2_open_free(&rqst[0]); |
---|
| 842 | + SMB2_query_info_free(&rqst[1]); |
---|
| 843 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 844 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 845 | + if (rc == 0) |
---|
| 846 | + *cfid = &tcon->crfid; |
---|
610 | 847 | return rc; |
---|
611 | 848 | } |
---|
612 | 849 | |
---|
613 | 850 | static void |
---|
614 | | -smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) |
---|
| 851 | +smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 852 | + struct cifs_sb_info *cifs_sb) |
---|
615 | 853 | { |
---|
616 | 854 | int rc; |
---|
617 | 855 | __le16 srch_path = 0; /* Null - open root of share */ |
---|
.. | .. |
---|
619 | 857 | struct cifs_open_parms oparms; |
---|
620 | 858 | struct cifs_fid fid; |
---|
621 | 859 | bool no_cached_open = tcon->nohandlecache; |
---|
| 860 | + struct cached_fid *cfid = NULL; |
---|
622 | 861 | |
---|
623 | | - oparms.tcon = tcon; |
---|
624 | | - oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
625 | | - oparms.disposition = FILE_OPEN; |
---|
626 | | - oparms.create_options = 0; |
---|
627 | | - oparms.fid = &fid; |
---|
628 | | - oparms.reconnect = false; |
---|
| 862 | + oparms = (struct cifs_open_parms) { |
---|
| 863 | + .tcon = tcon, |
---|
| 864 | + .desired_access = FILE_READ_ATTRIBUTES, |
---|
| 865 | + .disposition = FILE_OPEN, |
---|
| 866 | + .create_options = cifs_create_options(cifs_sb, 0), |
---|
| 867 | + .fid = &fid, |
---|
| 868 | + }; |
---|
629 | 869 | |
---|
630 | | - if (no_cached_open) |
---|
| 870 | + if (no_cached_open) { |
---|
631 | 871 | rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, |
---|
632 | | - NULL); |
---|
633 | | - else |
---|
634 | | - rc = open_shroot(xid, tcon, &fid); |
---|
635 | | - |
---|
| 872 | + NULL, NULL); |
---|
| 873 | + } else { |
---|
| 874 | + rc = open_shroot(xid, tcon, cifs_sb, &cfid); |
---|
| 875 | + if (rc == 0) |
---|
| 876 | + memcpy(&fid, cfid->fid, sizeof(struct cifs_fid)); |
---|
| 877 | + } |
---|
636 | 878 | if (rc) |
---|
637 | 879 | return; |
---|
638 | 880 | |
---|
.. | .. |
---|
649 | 891 | if (no_cached_open) |
---|
650 | 892 | SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
651 | 893 | else |
---|
652 | | - close_shroot(&tcon->crfid); |
---|
653 | | - |
---|
654 | | - return; |
---|
| 894 | + close_shroot(cfid); |
---|
655 | 895 | } |
---|
656 | 896 | |
---|
657 | 897 | static void |
---|
658 | | -smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) |
---|
| 898 | +smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 899 | + struct cifs_sb_info *cifs_sb) |
---|
659 | 900 | { |
---|
660 | 901 | int rc; |
---|
661 | 902 | __le16 srch_path = 0; /* Null - open root of share */ |
---|
.. | .. |
---|
666 | 907 | oparms.tcon = tcon; |
---|
667 | 908 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
668 | 909 | oparms.disposition = FILE_OPEN; |
---|
669 | | - oparms.create_options = 0; |
---|
| 910 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
670 | 911 | oparms.fid = &fid; |
---|
671 | 912 | oparms.reconnect = false; |
---|
672 | 913 | |
---|
673 | | - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); |
---|
| 914 | + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, |
---|
| 915 | + NULL, NULL); |
---|
674 | 916 | if (rc) |
---|
675 | 917 | return; |
---|
676 | 918 | |
---|
.. | .. |
---|
679 | 921 | SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, |
---|
680 | 922 | FS_DEVICE_INFORMATION); |
---|
681 | 923 | SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
682 | | - return; |
---|
683 | 924 | } |
---|
684 | 925 | |
---|
685 | 926 | static int |
---|
.. | .. |
---|
702 | 943 | oparms.tcon = tcon; |
---|
703 | 944 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
704 | 945 | oparms.disposition = FILE_OPEN; |
---|
705 | | - if (backup_cred(cifs_sb)) |
---|
706 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
707 | | - else |
---|
708 | | - oparms.create_options = 0; |
---|
| 946 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
709 | 947 | oparms.fid = &fid; |
---|
710 | 948 | oparms.reconnect = false; |
---|
711 | 949 | |
---|
712 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
| 950 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL, |
---|
| 951 | + NULL); |
---|
713 | 952 | if (rc) { |
---|
714 | 953 | kfree(utf16_path); |
---|
715 | 954 | return rc; |
---|
.. | .. |
---|
762 | 1001 | size_t name_len, value_len, user_name_len; |
---|
763 | 1002 | |
---|
764 | 1003 | while (src_size > 0) { |
---|
765 | | - name = &src->ea_data[0]; |
---|
766 | 1004 | name_len = (size_t)src->ea_name_length; |
---|
767 | | - value = &src->ea_data[src->ea_name_length + 1]; |
---|
768 | 1005 | value_len = (size_t)le16_to_cpu(src->ea_value_length); |
---|
769 | 1006 | |
---|
770 | | - if (name_len == 0) { |
---|
| 1007 | + if (name_len == 0) |
---|
771 | 1008 | break; |
---|
772 | | - } |
---|
773 | 1009 | |
---|
774 | 1010 | if (src_size < 8 + name_len + 1 + value_len) { |
---|
775 | 1011 | cifs_dbg(FYI, "EA entry goes beyond length of list\n"); |
---|
776 | 1012 | rc = -EIO; |
---|
777 | 1013 | goto out; |
---|
778 | 1014 | } |
---|
| 1015 | + |
---|
| 1016 | + name = &src->ea_data[0]; |
---|
| 1017 | + value = &src->ea_data[src->ea_name_length + 1]; |
---|
779 | 1018 | |
---|
780 | 1019 | if (ea_name) { |
---|
781 | 1020 | if (ea_name_len == name_len && |
---|
.. | .. |
---|
842 | 1081 | { |
---|
843 | 1082 | int rc; |
---|
844 | 1083 | __le16 *utf16_path; |
---|
845 | | - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
846 | | - struct cifs_open_parms oparms; |
---|
847 | | - struct cifs_fid fid; |
---|
848 | | - struct smb2_file_full_ea_info *smb2_data; |
---|
849 | | - int ea_buf_size = SMB2_MIN_EA_BUF; |
---|
| 1084 | + struct kvec rsp_iov = {NULL, 0}; |
---|
| 1085 | + int buftype = CIFS_NO_BUFFER; |
---|
| 1086 | + struct smb2_query_info_rsp *rsp; |
---|
| 1087 | + struct smb2_file_full_ea_info *info = NULL; |
---|
850 | 1088 | |
---|
851 | 1089 | utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
---|
852 | 1090 | if (!utf16_path) |
---|
853 | 1091 | return -ENOMEM; |
---|
854 | 1092 | |
---|
855 | | - oparms.tcon = tcon; |
---|
856 | | - oparms.desired_access = FILE_READ_EA; |
---|
857 | | - oparms.disposition = FILE_OPEN; |
---|
858 | | - if (backup_cred(cifs_sb)) |
---|
859 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
860 | | - else |
---|
861 | | - oparms.create_options = 0; |
---|
862 | | - oparms.fid = &fid; |
---|
863 | | - oparms.reconnect = false; |
---|
864 | | - |
---|
865 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
866 | | - kfree(utf16_path); |
---|
| 1093 | + rc = smb2_query_info_compound(xid, tcon, utf16_path, |
---|
| 1094 | + FILE_READ_EA, |
---|
| 1095 | + FILE_FULL_EA_INFORMATION, |
---|
| 1096 | + SMB2_O_INFO_FILE, |
---|
| 1097 | + CIFSMaxBufSize - |
---|
| 1098 | + MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 1099 | + MAX_SMB2_CLOSE_RESPONSE_SIZE, |
---|
| 1100 | + &rsp_iov, &buftype, cifs_sb); |
---|
867 | 1101 | if (rc) { |
---|
868 | | - cifs_dbg(FYI, "open failed rc=%d\n", rc); |
---|
869 | | - return rc; |
---|
| 1102 | + /* |
---|
| 1103 | + * If ea_name is NULL (listxattr) and there are no EAs, |
---|
| 1104 | + * return 0 as it's not an error. Otherwise, the specified |
---|
| 1105 | + * ea_name was not found. |
---|
| 1106 | + */ |
---|
| 1107 | + if (!ea_name && rc == -ENODATA) |
---|
| 1108 | + rc = 0; |
---|
| 1109 | + goto qeas_exit; |
---|
870 | 1110 | } |
---|
871 | 1111 | |
---|
872 | | - while (1) { |
---|
873 | | - smb2_data = kzalloc(ea_buf_size, GFP_KERNEL); |
---|
874 | | - if (smb2_data == NULL) { |
---|
875 | | - SMB2_close(xid, tcon, fid.persistent_fid, |
---|
876 | | - fid.volatile_fid); |
---|
877 | | - return -ENOMEM; |
---|
878 | | - } |
---|
| 1112 | + rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
---|
| 1113 | + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
---|
| 1114 | + le32_to_cpu(rsp->OutputBufferLength), |
---|
| 1115 | + &rsp_iov, |
---|
| 1116 | + sizeof(struct smb2_file_full_ea_info)); |
---|
| 1117 | + if (rc) |
---|
| 1118 | + goto qeas_exit; |
---|
879 | 1119 | |
---|
880 | | - rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, |
---|
881 | | - fid.volatile_fid, |
---|
882 | | - ea_buf_size, smb2_data); |
---|
| 1120 | + info = (struct smb2_file_full_ea_info *)( |
---|
| 1121 | + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); |
---|
| 1122 | + rc = move_smb2_ea_to_cifs(ea_data, buf_size, info, |
---|
| 1123 | + le32_to_cpu(rsp->OutputBufferLength), ea_name); |
---|
883 | 1124 | |
---|
884 | | - if (rc != -E2BIG) |
---|
885 | | - break; |
---|
886 | | - |
---|
887 | | - kfree(smb2_data); |
---|
888 | | - ea_buf_size <<= 1; |
---|
889 | | - |
---|
890 | | - if (ea_buf_size > SMB2_MAX_EA_BUF) { |
---|
891 | | - cifs_dbg(VFS, "EA size is too large\n"); |
---|
892 | | - SMB2_close(xid, tcon, fid.persistent_fid, |
---|
893 | | - fid.volatile_fid); |
---|
894 | | - return -ENOMEM; |
---|
895 | | - } |
---|
896 | | - } |
---|
897 | | - |
---|
898 | | - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
899 | | - |
---|
900 | | - /* |
---|
901 | | - * If ea_name is NULL (listxattr) and there are no EAs, return 0 as it's |
---|
902 | | - * not an error. Otherwise, the specified ea_name was not found. |
---|
903 | | - */ |
---|
904 | | - if (!rc) |
---|
905 | | - rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data, |
---|
906 | | - SMB2_MAX_EA_BUF, ea_name); |
---|
907 | | - else if (!ea_name && rc == -ENODATA) |
---|
908 | | - rc = 0; |
---|
909 | | - |
---|
910 | | - kfree(smb2_data); |
---|
| 1125 | + qeas_exit: |
---|
| 1126 | + kfree(utf16_path); |
---|
| 1127 | + free_rsp_buf(buftype, rsp_iov.iov_base); |
---|
911 | 1128 | return rc; |
---|
912 | 1129 | } |
---|
913 | 1130 | |
---|
.. | .. |
---|
918 | 1135 | const __u16 ea_value_len, const struct nls_table *nls_codepage, |
---|
919 | 1136 | struct cifs_sb_info *cifs_sb) |
---|
920 | 1137 | { |
---|
921 | | - int rc; |
---|
922 | | - __le16 *utf16_path; |
---|
923 | | - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
924 | | - struct cifs_open_parms oparms; |
---|
925 | | - struct cifs_fid fid; |
---|
926 | | - struct smb2_file_full_ea_info *ea; |
---|
| 1138 | + struct cifs_ses *ses = tcon->ses; |
---|
| 1139 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
---|
| 1140 | + __le16 *utf16_path = NULL; |
---|
927 | 1141 | int ea_name_len = strlen(ea_name); |
---|
| 1142 | + int flags = CIFS_CP_CREATE_CLOSE_OP; |
---|
928 | 1143 | int len; |
---|
| 1144 | + struct smb_rqst rqst[3]; |
---|
| 1145 | + int resp_buftype[3]; |
---|
| 1146 | + struct kvec rsp_iov[3]; |
---|
| 1147 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 1148 | + struct cifs_open_parms oparms; |
---|
| 1149 | + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
| 1150 | + struct cifs_fid fid; |
---|
| 1151 | + struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; |
---|
| 1152 | + unsigned int size[1]; |
---|
| 1153 | + void *data[1]; |
---|
| 1154 | + struct smb2_file_full_ea_info *ea = NULL; |
---|
| 1155 | + struct kvec close_iov[1]; |
---|
| 1156 | + struct smb2_query_info_rsp *rsp; |
---|
| 1157 | + int rc, used_len = 0; |
---|
| 1158 | + |
---|
| 1159 | + if (smb3_encryption_required(tcon)) |
---|
| 1160 | + flags |= CIFS_TRANSFORM_REQ; |
---|
929 | 1161 | |
---|
930 | 1162 | if (ea_name_len > 255) |
---|
931 | 1163 | return -EINVAL; |
---|
.. | .. |
---|
934 | 1166 | if (!utf16_path) |
---|
935 | 1167 | return -ENOMEM; |
---|
936 | 1168 | |
---|
| 1169 | + memset(rqst, 0, sizeof(rqst)); |
---|
| 1170 | + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
---|
| 1171 | + memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
| 1172 | + |
---|
| 1173 | + if (ses->server->ops->query_all_EAs) { |
---|
| 1174 | + if (!ea_value) { |
---|
| 1175 | + rc = ses->server->ops->query_all_EAs(xid, tcon, path, |
---|
| 1176 | + ea_name, NULL, 0, |
---|
| 1177 | + cifs_sb); |
---|
| 1178 | + if (rc == -ENODATA) |
---|
| 1179 | + goto sea_exit; |
---|
| 1180 | + } else { |
---|
| 1181 | + /* If we are adding a attribute we should first check |
---|
| 1182 | + * if there will be enough space available to store |
---|
| 1183 | + * the new EA. If not we should not add it since we |
---|
| 1184 | + * would not be able to even read the EAs back. |
---|
| 1185 | + */ |
---|
| 1186 | + rc = smb2_query_info_compound(xid, tcon, utf16_path, |
---|
| 1187 | + FILE_READ_EA, |
---|
| 1188 | + FILE_FULL_EA_INFORMATION, |
---|
| 1189 | + SMB2_O_INFO_FILE, |
---|
| 1190 | + CIFSMaxBufSize - |
---|
| 1191 | + MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 1192 | + MAX_SMB2_CLOSE_RESPONSE_SIZE, |
---|
| 1193 | + &rsp_iov[1], &resp_buftype[1], cifs_sb); |
---|
| 1194 | + if (rc == 0) { |
---|
| 1195 | + rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; |
---|
| 1196 | + used_len = le32_to_cpu(rsp->OutputBufferLength); |
---|
| 1197 | + } |
---|
| 1198 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 1199 | + resp_buftype[1] = CIFS_NO_BUFFER; |
---|
| 1200 | + memset(&rsp_iov[1], 0, sizeof(rsp_iov[1])); |
---|
| 1201 | + rc = 0; |
---|
| 1202 | + |
---|
| 1203 | + /* Use a fudge factor of 256 bytes in case we collide |
---|
| 1204 | + * with a different set_EAs command. |
---|
| 1205 | + */ |
---|
| 1206 | + if(CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 1207 | + MAX_SMB2_CLOSE_RESPONSE_SIZE - 256 < |
---|
| 1208 | + used_len + ea_name_len + ea_value_len + 1) { |
---|
| 1209 | + rc = -ENOSPC; |
---|
| 1210 | + goto sea_exit; |
---|
| 1211 | + } |
---|
| 1212 | + } |
---|
| 1213 | + } |
---|
| 1214 | + |
---|
| 1215 | + /* Open */ |
---|
| 1216 | + memset(&open_iov, 0, sizeof(open_iov)); |
---|
| 1217 | + rqst[0].rq_iov = open_iov; |
---|
| 1218 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 1219 | + |
---|
| 1220 | + memset(&oparms, 0, sizeof(oparms)); |
---|
937 | 1221 | oparms.tcon = tcon; |
---|
938 | 1222 | oparms.desired_access = FILE_WRITE_EA; |
---|
939 | 1223 | oparms.disposition = FILE_OPEN; |
---|
940 | | - if (backup_cred(cifs_sb)) |
---|
941 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
942 | | - else |
---|
943 | | - oparms.create_options = 0; |
---|
| 1224 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
944 | 1225 | oparms.fid = &fid; |
---|
945 | 1226 | oparms.reconnect = false; |
---|
946 | 1227 | |
---|
947 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
948 | | - kfree(utf16_path); |
---|
949 | | - if (rc) { |
---|
950 | | - cifs_dbg(FYI, "open failed rc=%d\n", rc); |
---|
951 | | - return rc; |
---|
952 | | - } |
---|
| 1228 | + rc = SMB2_open_init(tcon, server, |
---|
| 1229 | + &rqst[0], &oplock, &oparms, utf16_path); |
---|
| 1230 | + if (rc) |
---|
| 1231 | + goto sea_exit; |
---|
| 1232 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
| 1233 | + |
---|
| 1234 | + |
---|
| 1235 | + /* Set Info */ |
---|
| 1236 | + memset(&si_iov, 0, sizeof(si_iov)); |
---|
| 1237 | + rqst[1].rq_iov = si_iov; |
---|
| 1238 | + rqst[1].rq_nvec = 1; |
---|
953 | 1239 | |
---|
954 | 1240 | len = sizeof(*ea) + ea_name_len + ea_value_len + 1; |
---|
955 | 1241 | ea = kzalloc(len, GFP_KERNEL); |
---|
956 | 1242 | if (ea == NULL) { |
---|
957 | | - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
958 | | - return -ENOMEM; |
---|
| 1243 | + rc = -ENOMEM; |
---|
| 1244 | + goto sea_exit; |
---|
959 | 1245 | } |
---|
960 | 1246 | |
---|
961 | 1247 | ea->ea_name_length = ea_name_len; |
---|
.. | .. |
---|
963 | 1249 | memcpy(ea->ea_data, ea_name, ea_name_len + 1); |
---|
964 | 1250 | memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len); |
---|
965 | 1251 | |
---|
966 | | - rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea, |
---|
967 | | - len); |
---|
| 1252 | + size[0] = len; |
---|
| 1253 | + data[0] = ea; |
---|
| 1254 | + |
---|
| 1255 | + rc = SMB2_set_info_init(tcon, server, |
---|
| 1256 | + &rqst[1], COMPOUND_FID, |
---|
| 1257 | + COMPOUND_FID, current->tgid, |
---|
| 1258 | + FILE_FULL_EA_INFORMATION, |
---|
| 1259 | + SMB2_O_INFO_FILE, 0, data, size); |
---|
| 1260 | + if (rc) |
---|
| 1261 | + goto sea_exit; |
---|
| 1262 | + smb2_set_next_command(tcon, &rqst[1]); |
---|
| 1263 | + smb2_set_related(&rqst[1]); |
---|
| 1264 | + |
---|
| 1265 | + |
---|
| 1266 | + /* Close */ |
---|
| 1267 | + memset(&close_iov, 0, sizeof(close_iov)); |
---|
| 1268 | + rqst[2].rq_iov = close_iov; |
---|
| 1269 | + rqst[2].rq_nvec = 1; |
---|
| 1270 | + rc = SMB2_close_init(tcon, server, |
---|
| 1271 | + &rqst[2], COMPOUND_FID, COMPOUND_FID, false); |
---|
| 1272 | + if (rc) |
---|
| 1273 | + goto sea_exit; |
---|
| 1274 | + smb2_set_related(&rqst[2]); |
---|
| 1275 | + |
---|
| 1276 | + rc = compound_send_recv(xid, ses, server, |
---|
| 1277 | + flags, 3, rqst, |
---|
| 1278 | + resp_buftype, rsp_iov); |
---|
| 1279 | + /* no need to bump num_remote_opens because handle immediately closed */ |
---|
| 1280 | + |
---|
| 1281 | + sea_exit: |
---|
968 | 1282 | kfree(ea); |
---|
969 | | - |
---|
970 | | - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
971 | | - |
---|
| 1283 | + kfree(utf16_path); |
---|
| 1284 | + SMB2_open_free(&rqst[0]); |
---|
| 1285 | + SMB2_set_info_free(&rqst[1]); |
---|
| 1286 | + SMB2_close_free(&rqst[2]); |
---|
| 1287 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 1288 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 1289 | + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
---|
972 | 1290 | return rc; |
---|
973 | 1291 | } |
---|
974 | 1292 | #endif |
---|
.. | .. |
---|
983 | 1301 | smb2_clear_stats(struct cifs_tcon *tcon) |
---|
984 | 1302 | { |
---|
985 | 1303 | int i; |
---|
| 1304 | + |
---|
986 | 1305 | for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) { |
---|
987 | 1306 | atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0); |
---|
988 | 1307 | atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0); |
---|
.. | .. |
---|
1035 | 1354 | seq_printf(m, "\nBytes read: %llu Bytes written: %llu", |
---|
1036 | 1355 | (long long)(tcon->bytes_read), |
---|
1037 | 1356 | (long long)(tcon->bytes_written)); |
---|
| 1357 | + seq_printf(m, "\nOpen files: %d total (local), %d open on server", |
---|
| 1358 | + atomic_read(&tcon->num_local_opens), |
---|
| 1359 | + atomic_read(&tcon->num_remote_opens)); |
---|
1038 | 1360 | seq_printf(m, "\nTreeConnects: %d total %d failed", |
---|
1039 | 1361 | atomic_read(&sent[SMB2_TREE_CONNECT_HE]), |
---|
1040 | 1362 | atomic_read(&failed[SMB2_TREE_CONNECT_HE])); |
---|
.. | .. |
---|
1087 | 1409 | |
---|
1088 | 1410 | cfile->fid.persistent_fid = fid->persistent_fid; |
---|
1089 | 1411 | cfile->fid.volatile_fid = fid->volatile_fid; |
---|
| 1412 | + cfile->fid.access = fid->access; |
---|
| 1413 | +#ifdef CONFIG_CIFS_DEBUG2 |
---|
| 1414 | + cfile->fid.mid = fid->mid; |
---|
| 1415 | +#endif /* CIFS_DEBUG2 */ |
---|
1090 | 1416 | server->ops->set_oplock_level(cinode, oplock, fid->epoch, |
---|
1091 | 1417 | &fid->purge_cache); |
---|
1092 | 1418 | cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); |
---|
.. | .. |
---|
1100 | 1426 | SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); |
---|
1101 | 1427 | } |
---|
1102 | 1428 | |
---|
| 1429 | +static void |
---|
| 1430 | +smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 1431 | + struct cifsFileInfo *cfile) |
---|
| 1432 | +{ |
---|
| 1433 | + struct smb2_file_network_open_info file_inf; |
---|
| 1434 | + struct inode *inode; |
---|
| 1435 | + int rc; |
---|
| 1436 | + |
---|
| 1437 | + rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid, |
---|
| 1438 | + cfile->fid.volatile_fid, &file_inf); |
---|
| 1439 | + if (rc) |
---|
| 1440 | + return; |
---|
| 1441 | + |
---|
| 1442 | + inode = d_inode(cfile->dentry); |
---|
| 1443 | + |
---|
| 1444 | + spin_lock(&inode->i_lock); |
---|
| 1445 | + CIFS_I(inode)->time = jiffies; |
---|
| 1446 | + |
---|
| 1447 | + /* Creation time should not need to be updated on close */ |
---|
| 1448 | + if (file_inf.LastWriteTime) |
---|
| 1449 | + inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime); |
---|
| 1450 | + if (file_inf.ChangeTime) |
---|
| 1451 | + inode->i_ctime = cifs_NTtimeToUnix(file_inf.ChangeTime); |
---|
| 1452 | + if (file_inf.LastAccessTime) |
---|
| 1453 | + inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime); |
---|
| 1454 | + |
---|
| 1455 | + /* |
---|
| 1456 | + * i_blocks is not related to (i_size / i_blksize), |
---|
| 1457 | + * but instead 512 byte (2**9) size is required for |
---|
| 1458 | + * calculating num blocks. |
---|
| 1459 | + */ |
---|
| 1460 | + if (le64_to_cpu(file_inf.AllocationSize) > 4096) |
---|
| 1461 | + inode->i_blocks = |
---|
| 1462 | + (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9; |
---|
| 1463 | + |
---|
| 1464 | + /* End of file and Attributes should not have to be updated on close */ |
---|
| 1465 | + spin_unlock(&inode->i_lock); |
---|
| 1466 | +} |
---|
| 1467 | + |
---|
1103 | 1468 | static int |
---|
1104 | 1469 | SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, |
---|
1105 | 1470 | u64 persistent_fid, u64 volatile_fid, |
---|
.. | .. |
---|
1110 | 1475 | struct resume_key_req *res_key; |
---|
1111 | 1476 | |
---|
1112 | 1477 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, |
---|
1113 | | - FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */, |
---|
1114 | | - NULL, 0 /* no input */, |
---|
1115 | | - (char **)&res_key, &ret_data_len); |
---|
| 1478 | + FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */, |
---|
| 1479 | + CIFSMaxBufSize, (char **)&res_key, &ret_data_len); |
---|
1116 | 1480 | |
---|
1117 | 1481 | if (rc) { |
---|
1118 | | - cifs_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); |
---|
| 1482 | + cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); |
---|
1119 | 1483 | goto req_res_key_exit; |
---|
1120 | 1484 | } |
---|
1121 | 1485 | if (ret_data_len < sizeof(struct resume_key_req)) { |
---|
1122 | | - cifs_dbg(VFS, "Invalid refcopy resume key length\n"); |
---|
| 1486 | + cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n"); |
---|
1123 | 1487 | rc = -EINVAL; |
---|
1124 | 1488 | goto req_res_key_exit; |
---|
1125 | 1489 | } |
---|
.. | .. |
---|
1127 | 1491 | |
---|
1128 | 1492 | req_res_key_exit: |
---|
1129 | 1493 | kfree(res_key); |
---|
| 1494 | + return rc; |
---|
| 1495 | +} |
---|
| 1496 | + |
---|
| 1497 | +struct iqi_vars { |
---|
| 1498 | + struct smb_rqst rqst[3]; |
---|
| 1499 | + struct kvec rsp_iov[3]; |
---|
| 1500 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 1501 | + struct kvec qi_iov[1]; |
---|
| 1502 | + struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; |
---|
| 1503 | + struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; |
---|
| 1504 | + struct kvec close_iov[1]; |
---|
| 1505 | +}; |
---|
| 1506 | + |
---|
| 1507 | +static int |
---|
| 1508 | +smb2_ioctl_query_info(const unsigned int xid, |
---|
| 1509 | + struct cifs_tcon *tcon, |
---|
| 1510 | + struct cifs_sb_info *cifs_sb, |
---|
| 1511 | + __le16 *path, int is_dir, |
---|
| 1512 | + unsigned long p) |
---|
| 1513 | +{ |
---|
| 1514 | + struct iqi_vars *vars; |
---|
| 1515 | + struct smb_rqst *rqst; |
---|
| 1516 | + struct kvec *rsp_iov; |
---|
| 1517 | + struct cifs_ses *ses = tcon->ses; |
---|
| 1518 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
---|
| 1519 | + char __user *arg = (char __user *)p; |
---|
| 1520 | + struct smb_query_info qi; |
---|
| 1521 | + struct smb_query_info __user *pqi; |
---|
| 1522 | + int rc = 0; |
---|
| 1523 | + int flags = CIFS_CP_CREATE_CLOSE_OP; |
---|
| 1524 | + struct smb2_query_info_rsp *qi_rsp = NULL; |
---|
| 1525 | + struct smb2_ioctl_rsp *io_rsp = NULL; |
---|
| 1526 | + void *buffer = NULL; |
---|
| 1527 | + int resp_buftype[3]; |
---|
| 1528 | + struct cifs_open_parms oparms; |
---|
| 1529 | + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
| 1530 | + struct cifs_fid fid; |
---|
| 1531 | + unsigned int size[2]; |
---|
| 1532 | + void *data[2]; |
---|
| 1533 | + int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; |
---|
| 1534 | + void (*free_req1_func)(struct smb_rqst *r); |
---|
| 1535 | + |
---|
| 1536 | + vars = kzalloc(sizeof(*vars), GFP_ATOMIC); |
---|
| 1537 | + if (vars == NULL) |
---|
| 1538 | + return -ENOMEM; |
---|
| 1539 | + rqst = &vars->rqst[0]; |
---|
| 1540 | + rsp_iov = &vars->rsp_iov[0]; |
---|
| 1541 | + |
---|
| 1542 | + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
---|
| 1543 | + |
---|
| 1544 | + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) { |
---|
| 1545 | + rc = -EFAULT; |
---|
| 1546 | + goto free_vars; |
---|
| 1547 | + } |
---|
| 1548 | + if (qi.output_buffer_length > 1024) { |
---|
| 1549 | + rc = -EINVAL; |
---|
| 1550 | + goto free_vars; |
---|
| 1551 | + } |
---|
| 1552 | + |
---|
| 1553 | + if (!ses || !server) { |
---|
| 1554 | + rc = -EIO; |
---|
| 1555 | + goto free_vars; |
---|
| 1556 | + } |
---|
| 1557 | + |
---|
| 1558 | + if (smb3_encryption_required(tcon)) |
---|
| 1559 | + flags |= CIFS_TRANSFORM_REQ; |
---|
| 1560 | + |
---|
| 1561 | + if (qi.output_buffer_length) { |
---|
| 1562 | + buffer = memdup_user(arg + sizeof(struct smb_query_info), qi.output_buffer_length); |
---|
| 1563 | + if (IS_ERR(buffer)) { |
---|
| 1564 | + rc = PTR_ERR(buffer); |
---|
| 1565 | + goto free_vars; |
---|
| 1566 | + } |
---|
| 1567 | + } |
---|
| 1568 | + |
---|
| 1569 | + /* Open */ |
---|
| 1570 | + rqst[0].rq_iov = &vars->open_iov[0]; |
---|
| 1571 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 1572 | + |
---|
| 1573 | + memset(&oparms, 0, sizeof(oparms)); |
---|
| 1574 | + oparms.tcon = tcon; |
---|
| 1575 | + oparms.disposition = FILE_OPEN; |
---|
| 1576 | + oparms.create_options = cifs_create_options(cifs_sb, create_options); |
---|
| 1577 | + oparms.fid = &fid; |
---|
| 1578 | + oparms.reconnect = false; |
---|
| 1579 | + |
---|
| 1580 | + if (qi.flags & PASSTHRU_FSCTL) { |
---|
| 1581 | + switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) { |
---|
| 1582 | + case FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS: |
---|
| 1583 | + oparms.desired_access = FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE; |
---|
| 1584 | + break; |
---|
| 1585 | + case FSCTL_DEVICE_ACCESS_FILE_ANY_ACCESS: |
---|
| 1586 | + oparms.desired_access = GENERIC_ALL; |
---|
| 1587 | + break; |
---|
| 1588 | + case FSCTL_DEVICE_ACCESS_FILE_READ_ACCESS: |
---|
| 1589 | + oparms.desired_access = GENERIC_READ; |
---|
| 1590 | + break; |
---|
| 1591 | + case FSCTL_DEVICE_ACCESS_FILE_WRITE_ACCESS: |
---|
| 1592 | + oparms.desired_access = GENERIC_WRITE; |
---|
| 1593 | + break; |
---|
| 1594 | + } |
---|
| 1595 | + } else if (qi.flags & PASSTHRU_SET_INFO) { |
---|
| 1596 | + oparms.desired_access = GENERIC_WRITE; |
---|
| 1597 | + } else { |
---|
| 1598 | + oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL; |
---|
| 1599 | + } |
---|
| 1600 | + |
---|
| 1601 | + rc = SMB2_open_init(tcon, server, |
---|
| 1602 | + &rqst[0], &oplock, &oparms, path); |
---|
| 1603 | + if (rc) |
---|
| 1604 | + goto free_output_buffer; |
---|
| 1605 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
| 1606 | + |
---|
| 1607 | + /* Query */ |
---|
| 1608 | + if (qi.flags & PASSTHRU_FSCTL) { |
---|
| 1609 | + /* Can eventually relax perm check since server enforces too */ |
---|
| 1610 | + if (!capable(CAP_SYS_ADMIN)) { |
---|
| 1611 | + rc = -EPERM; |
---|
| 1612 | + goto free_open_req; |
---|
| 1613 | + } |
---|
| 1614 | + rqst[1].rq_iov = &vars->io_iov[0]; |
---|
| 1615 | + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; |
---|
| 1616 | + |
---|
| 1617 | + rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, |
---|
| 1618 | + qi.info_type, buffer, qi.output_buffer_length, |
---|
| 1619 | + CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 1620 | + MAX_SMB2_CLOSE_RESPONSE_SIZE); |
---|
| 1621 | + free_req1_func = SMB2_ioctl_free; |
---|
| 1622 | + } else if (qi.flags == PASSTHRU_SET_INFO) { |
---|
| 1623 | + /* Can eventually relax perm check since server enforces too */ |
---|
| 1624 | + if (!capable(CAP_SYS_ADMIN)) { |
---|
| 1625 | + rc = -EPERM; |
---|
| 1626 | + goto free_open_req; |
---|
| 1627 | + } |
---|
| 1628 | + if (qi.output_buffer_length < 8) { |
---|
| 1629 | + rc = -EINVAL; |
---|
| 1630 | + goto free_open_req; |
---|
| 1631 | + } |
---|
| 1632 | + rqst[1].rq_iov = &vars->si_iov[0]; |
---|
| 1633 | + rqst[1].rq_nvec = 1; |
---|
| 1634 | + |
---|
| 1635 | + /* MS-FSCC 2.4.13 FileEndOfFileInformation */ |
---|
| 1636 | + size[0] = 8; |
---|
| 1637 | + data[0] = buffer; |
---|
| 1638 | + |
---|
| 1639 | + rc = SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, |
---|
| 1640 | + current->tgid, FILE_END_OF_FILE_INFORMATION, |
---|
| 1641 | + SMB2_O_INFO_FILE, 0, data, size); |
---|
| 1642 | + free_req1_func = SMB2_set_info_free; |
---|
| 1643 | + } else if (qi.flags == PASSTHRU_QUERY_INFO) { |
---|
| 1644 | + rqst[1].rq_iov = &vars->qi_iov[0]; |
---|
| 1645 | + rqst[1].rq_nvec = 1; |
---|
| 1646 | + |
---|
| 1647 | + rc = SMB2_query_info_init(tcon, server, |
---|
| 1648 | + &rqst[1], COMPOUND_FID, |
---|
| 1649 | + COMPOUND_FID, qi.file_info_class, |
---|
| 1650 | + qi.info_type, qi.additional_information, |
---|
| 1651 | + qi.input_buffer_length, |
---|
| 1652 | + qi.output_buffer_length, buffer); |
---|
| 1653 | + free_req1_func = SMB2_query_info_free; |
---|
| 1654 | + } else { /* unknown flags */ |
---|
| 1655 | + cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n", |
---|
| 1656 | + qi.flags); |
---|
| 1657 | + rc = -EINVAL; |
---|
| 1658 | + } |
---|
| 1659 | + |
---|
| 1660 | + if (rc) |
---|
| 1661 | + goto free_open_req; |
---|
| 1662 | + smb2_set_next_command(tcon, &rqst[1]); |
---|
| 1663 | + smb2_set_related(&rqst[1]); |
---|
| 1664 | + |
---|
| 1665 | + /* Close */ |
---|
| 1666 | + rqst[2].rq_iov = &vars->close_iov[0]; |
---|
| 1667 | + rqst[2].rq_nvec = 1; |
---|
| 1668 | + |
---|
| 1669 | + rc = SMB2_close_init(tcon, server, |
---|
| 1670 | + &rqst[2], COMPOUND_FID, COMPOUND_FID, false); |
---|
| 1671 | + if (rc) |
---|
| 1672 | + goto free_req_1; |
---|
| 1673 | + smb2_set_related(&rqst[2]); |
---|
| 1674 | + |
---|
| 1675 | + rc = compound_send_recv(xid, ses, server, |
---|
| 1676 | + flags, 3, rqst, |
---|
| 1677 | + resp_buftype, rsp_iov); |
---|
| 1678 | + if (rc) |
---|
| 1679 | + goto out; |
---|
| 1680 | + |
---|
| 1681 | + /* No need to bump num_remote_opens since handle immediately closed */ |
---|
| 1682 | + if (qi.flags & PASSTHRU_FSCTL) { |
---|
| 1683 | + pqi = (struct smb_query_info __user *)arg; |
---|
| 1684 | + io_rsp = (struct smb2_ioctl_rsp *)rsp_iov[1].iov_base; |
---|
| 1685 | + if (le32_to_cpu(io_rsp->OutputCount) < qi.input_buffer_length) |
---|
| 1686 | + qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount); |
---|
| 1687 | + if (qi.input_buffer_length > 0 && |
---|
| 1688 | + le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length |
---|
| 1689 | + > rsp_iov[1].iov_len) { |
---|
| 1690 | + rc = -EFAULT; |
---|
| 1691 | + goto out; |
---|
| 1692 | + } |
---|
| 1693 | + |
---|
| 1694 | + if (copy_to_user(&pqi->input_buffer_length, |
---|
| 1695 | + &qi.input_buffer_length, |
---|
| 1696 | + sizeof(qi.input_buffer_length))) { |
---|
| 1697 | + rc = -EFAULT; |
---|
| 1698 | + goto out; |
---|
| 1699 | + } |
---|
| 1700 | + |
---|
| 1701 | + if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info), |
---|
| 1702 | + (const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset), |
---|
| 1703 | + qi.input_buffer_length)) |
---|
| 1704 | + rc = -EFAULT; |
---|
| 1705 | + } else { |
---|
| 1706 | + pqi = (struct smb_query_info __user *)arg; |
---|
| 1707 | + qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; |
---|
| 1708 | + if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length) |
---|
| 1709 | + qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); |
---|
| 1710 | + if (copy_to_user(&pqi->input_buffer_length, |
---|
| 1711 | + &qi.input_buffer_length, |
---|
| 1712 | + sizeof(qi.input_buffer_length))) { |
---|
| 1713 | + rc = -EFAULT; |
---|
| 1714 | + goto out; |
---|
| 1715 | + } |
---|
| 1716 | + |
---|
| 1717 | + if (copy_to_user(pqi + 1, qi_rsp->Buffer, |
---|
| 1718 | + qi.input_buffer_length)) |
---|
| 1719 | + rc = -EFAULT; |
---|
| 1720 | + } |
---|
| 1721 | + |
---|
| 1722 | +out: |
---|
| 1723 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 1724 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 1725 | + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
---|
| 1726 | + SMB2_close_free(&rqst[2]); |
---|
| 1727 | +free_req_1: |
---|
| 1728 | + free_req1_func(&rqst[1]); |
---|
| 1729 | +free_open_req: |
---|
| 1730 | + SMB2_open_free(&rqst[0]); |
---|
| 1731 | +free_output_buffer: |
---|
| 1732 | + kfree(buffer); |
---|
| 1733 | +free_vars: |
---|
| 1734 | + kfree(vars); |
---|
1130 | 1735 | return rc; |
---|
1131 | 1736 | } |
---|
1132 | 1737 | |
---|
.. | .. |
---|
1144 | 1749 | int chunks_copied = 0; |
---|
1145 | 1750 | bool chunk_sizes_updated = false; |
---|
1146 | 1751 | ssize_t bytes_written, total_bytes_written = 0; |
---|
| 1752 | + struct inode *inode; |
---|
1147 | 1753 | |
---|
1148 | 1754 | pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); |
---|
| 1755 | + |
---|
| 1756 | + /* |
---|
| 1757 | + * We need to flush all unwritten data before we can send the |
---|
| 1758 | + * copychunk ioctl to the server. |
---|
| 1759 | + */ |
---|
| 1760 | + inode = d_inode(trgtfile->dentry); |
---|
| 1761 | + filemap_write_and_wait(inode->i_mapping); |
---|
1149 | 1762 | |
---|
1150 | 1763 | if (pcchunk == NULL) |
---|
1151 | 1764 | return -ENOMEM; |
---|
1152 | 1765 | |
---|
1153 | | - cifs_dbg(FYI, "in smb2_copychunk_range - about to call request res key\n"); |
---|
| 1766 | + cifs_dbg(FYI, "%s: about to call request res key\n", __func__); |
---|
1154 | 1767 | /* Request a key from the server to identify the source of the copy */ |
---|
1155 | 1768 | rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink), |
---|
1156 | 1769 | srcfile->fid.persistent_fid, |
---|
.. | .. |
---|
1171 | 1784 | pcchunk->SourceOffset = cpu_to_le64(src_off); |
---|
1172 | 1785 | pcchunk->TargetOffset = cpu_to_le64(dest_off); |
---|
1173 | 1786 | pcchunk->Length = |
---|
1174 | | - cpu_to_le32(min_t(u32, len, tcon->max_bytes_chunk)); |
---|
| 1787 | + cpu_to_le32(min_t(u64, len, tcon->max_bytes_chunk)); |
---|
1175 | 1788 | |
---|
1176 | 1789 | /* Request server copy to target from src identified by key */ |
---|
1177 | 1790 | kfree(retbuf); |
---|
1178 | 1791 | retbuf = NULL; |
---|
1179 | 1792 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, |
---|
1180 | 1793 | trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, |
---|
1181 | | - true /* is_fsctl */, (char *)pcchunk, |
---|
1182 | | - sizeof(struct copychunk_ioctl), (char **)&retbuf, |
---|
1183 | | - &ret_data_len); |
---|
| 1794 | + (char *)pcchunk, sizeof(struct copychunk_ioctl), |
---|
| 1795 | + CIFSMaxBufSize, (char **)&retbuf, &ret_data_len); |
---|
1184 | 1796 | if (rc == 0) { |
---|
1185 | 1797 | if (ret_data_len != |
---|
1186 | 1798 | sizeof(struct copychunk_ioctl_rsp)) { |
---|
1187 | | - cifs_dbg(VFS, "invalid cchunk response size\n"); |
---|
| 1799 | + cifs_tcon_dbg(VFS, "Invalid cchunk response size\n"); |
---|
1188 | 1800 | rc = -EIO; |
---|
1189 | 1801 | goto cchunk_out; |
---|
1190 | 1802 | } |
---|
.. | .. |
---|
1198 | 1810 | */ |
---|
1199 | 1811 | if (le32_to_cpu(retbuf->TotalBytesWritten) > |
---|
1200 | 1812 | le32_to_cpu(pcchunk->Length)) { |
---|
1201 | | - cifs_dbg(VFS, "invalid copy chunk response\n"); |
---|
| 1813 | + cifs_tcon_dbg(VFS, "Invalid copy chunk response\n"); |
---|
1202 | 1814 | rc = -EIO; |
---|
1203 | 1815 | goto cchunk_out; |
---|
1204 | 1816 | } |
---|
1205 | 1817 | if (le32_to_cpu(retbuf->ChunksWritten) != 1) { |
---|
1206 | | - cifs_dbg(VFS, "invalid num chunks written\n"); |
---|
| 1818 | + cifs_tcon_dbg(VFS, "Invalid num chunks written\n"); |
---|
1207 | 1819 | rc = -EIO; |
---|
1208 | 1820 | goto cchunk_out; |
---|
1209 | 1821 | } |
---|
.. | .. |
---|
1272 | 1884 | smb2_read_data_offset(char *buf) |
---|
1273 | 1885 | { |
---|
1274 | 1886 | struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf; |
---|
| 1887 | + |
---|
1275 | 1888 | return rsp->DataOffset; |
---|
1276 | 1889 | } |
---|
1277 | 1890 | |
---|
.. | .. |
---|
1339 | 1952 | |
---|
1340 | 1953 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
1341 | 1954 | cfile->fid.volatile_fid, FSCTL_SET_SPARSE, |
---|
1342 | | - true /* is_fctl */, |
---|
1343 | | - &setsparse, 1, NULL, NULL); |
---|
| 1955 | + &setsparse, 1, CIFSMaxBufSize, NULL, NULL); |
---|
1344 | 1956 | if (rc) { |
---|
1345 | 1957 | tcon->broken_sparse_sup = true; |
---|
1346 | 1958 | cifs_dbg(FYI, "set sparse rc = %d\n", rc); |
---|
.. | .. |
---|
1376 | 1988 | } |
---|
1377 | 1989 | |
---|
1378 | 1990 | return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, |
---|
1379 | | - cfile->fid.volatile_fid, cfile->pid, &eof, false); |
---|
| 1991 | + cfile->fid.volatile_fid, cfile->pid, &eof); |
---|
1380 | 1992 | } |
---|
1381 | 1993 | |
---|
1382 | 1994 | static int |
---|
.. | .. |
---|
1387 | 1999 | { |
---|
1388 | 2000 | int rc; |
---|
1389 | 2001 | unsigned int ret_data_len; |
---|
| 2002 | + struct inode *inode; |
---|
1390 | 2003 | struct duplicate_extents_to_file dup_ext_buf; |
---|
1391 | 2004 | struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink); |
---|
1392 | 2005 | |
---|
.. | .. |
---|
1400 | 2013 | dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off); |
---|
1401 | 2014 | dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off); |
---|
1402 | 2015 | dup_ext_buf.ByteCount = cpu_to_le64(len); |
---|
1403 | | - cifs_dbg(FYI, "duplicate extents: src off %lld dst off %lld len %lld", |
---|
| 2016 | + cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n", |
---|
1404 | 2017 | src_off, dest_off, len); |
---|
1405 | 2018 | |
---|
1406 | | - rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false); |
---|
1407 | | - if (rc) |
---|
1408 | | - goto duplicate_extents_out; |
---|
| 2019 | + inode = d_inode(trgtfile->dentry); |
---|
| 2020 | + if (inode->i_size < dest_off + len) { |
---|
| 2021 | + rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false); |
---|
| 2022 | + if (rc) |
---|
| 2023 | + goto duplicate_extents_out; |
---|
1409 | 2024 | |
---|
| 2025 | + /* |
---|
| 2026 | + * Although also could set plausible allocation size (i_blocks) |
---|
| 2027 | + * here in addition to setting the file size, in reflink |
---|
| 2028 | + * it is likely that the target file is sparse. Its allocation |
---|
| 2029 | + * size will be queried on next revalidate, but it is important |
---|
| 2030 | + * to make sure that file's cached size is updated immediately |
---|
| 2031 | + */ |
---|
| 2032 | + cifs_setsize(inode, dest_off + len); |
---|
| 2033 | + } |
---|
1410 | 2034 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, |
---|
1411 | 2035 | trgtfile->fid.volatile_fid, |
---|
1412 | 2036 | FSCTL_DUPLICATE_EXTENTS_TO_FILE, |
---|
1413 | | - true /* is_fsctl */, |
---|
1414 | 2037 | (char *)&dup_ext_buf, |
---|
1415 | 2038 | sizeof(struct duplicate_extents_to_file), |
---|
1416 | | - NULL, |
---|
| 2039 | + CIFSMaxBufSize, NULL, |
---|
1417 | 2040 | &ret_data_len); |
---|
1418 | 2041 | |
---|
1419 | 2042 | if (ret_data_len > 0) |
---|
1420 | | - cifs_dbg(FYI, "non-zero response length in duplicate extents"); |
---|
| 2043 | + cifs_dbg(FYI, "Non-zero response length in duplicate extents\n"); |
---|
1421 | 2044 | |
---|
1422 | 2045 | duplicate_extents_out: |
---|
1423 | 2046 | return rc; |
---|
.. | .. |
---|
1445 | 2068 | return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
1446 | 2069 | cfile->fid.volatile_fid, |
---|
1447 | 2070 | FSCTL_SET_INTEGRITY_INFORMATION, |
---|
1448 | | - true /* is_fsctl */, |
---|
1449 | 2071 | (char *)&integr_info, |
---|
1450 | 2072 | sizeof(struct fsctl_set_integrity_information_req), |
---|
1451 | | - NULL, |
---|
| 2073 | + CIFSMaxBufSize, NULL, |
---|
1452 | 2074 | &ret_data_len); |
---|
1453 | 2075 | |
---|
1454 | 2076 | } |
---|
1455 | 2077 | |
---|
1456 | 2078 | /* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */ |
---|
1457 | 2079 | #define GMT_TOKEN_SIZE 50 |
---|
| 2080 | + |
---|
| 2081 | +#define MIN_SNAPSHOT_ARRAY_SIZE 16 /* See MS-SMB2 section 3.3.5.15.1 */ |
---|
1458 | 2082 | |
---|
1459 | 2083 | /* |
---|
1460 | 2084 | * Input buffer contains (empty) struct smb_snapshot array with size filled in |
---|
.. | .. |
---|
1467 | 2091 | char *retbuf = NULL; |
---|
1468 | 2092 | unsigned int ret_data_len = 0; |
---|
1469 | 2093 | int rc; |
---|
| 2094 | + u32 max_response_size; |
---|
1470 | 2095 | struct smb_snapshot_array snapshot_in; |
---|
| 2096 | + |
---|
| 2097 | + /* |
---|
| 2098 | + * On the first query to enumerate the list of snapshots available |
---|
| 2099 | + * for this volume the buffer begins with 0 (number of snapshots |
---|
| 2100 | + * which can be returned is zero since at that point we do not know |
---|
| 2101 | + * how big the buffer needs to be). On the second query, |
---|
| 2102 | + * it (ret_data_len) is set to number of snapshots so we can |
---|
| 2103 | + * know to set the maximum response size larger (see below). |
---|
| 2104 | + */ |
---|
| 2105 | + if (get_user(ret_data_len, (unsigned int __user *)ioc_buf)) |
---|
| 2106 | + return -EFAULT; |
---|
| 2107 | + |
---|
| 2108 | + /* |
---|
| 2109 | + * Note that for snapshot queries that servers like Azure expect that |
---|
| 2110 | + * the first query be minimal size (and just used to get the number/size |
---|
| 2111 | + * of previous versions) so response size must be specified as EXACTLY |
---|
| 2112 | + * sizeof(struct snapshot_array) which is 16 when rounded up to multiple |
---|
| 2113 | + * of eight bytes. |
---|
| 2114 | + */ |
---|
| 2115 | + if (ret_data_len == 0) |
---|
| 2116 | + max_response_size = MIN_SNAPSHOT_ARRAY_SIZE; |
---|
| 2117 | + else |
---|
| 2118 | + max_response_size = CIFSMaxBufSize; |
---|
1471 | 2119 | |
---|
1472 | 2120 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
1473 | 2121 | cfile->fid.volatile_fid, |
---|
1474 | 2122 | FSCTL_SRV_ENUMERATE_SNAPSHOTS, |
---|
1475 | | - true /* is_fsctl */, |
---|
1476 | | - NULL, 0 /* no input data */, |
---|
| 2123 | + NULL, 0 /* no input data */, max_response_size, |
---|
1477 | 2124 | (char **)&retbuf, |
---|
1478 | 2125 | &ret_data_len); |
---|
1479 | 2126 | cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n", |
---|
.. | .. |
---|
1519 | 2166 | return rc; |
---|
1520 | 2167 | } |
---|
1521 | 2168 | |
---|
| 2169 | + |
---|
| 2170 | + |
---|
| 2171 | +static int |
---|
| 2172 | +smb3_notify(const unsigned int xid, struct file *pfile, |
---|
| 2173 | + void __user *ioc_buf) |
---|
| 2174 | +{ |
---|
| 2175 | + struct smb3_notify notify; |
---|
| 2176 | + struct dentry *dentry = pfile->f_path.dentry; |
---|
| 2177 | + struct inode *inode = file_inode(pfile); |
---|
| 2178 | + struct cifs_sb_info *cifs_sb; |
---|
| 2179 | + struct cifs_open_parms oparms; |
---|
| 2180 | + struct cifs_fid fid; |
---|
| 2181 | + struct cifs_tcon *tcon; |
---|
| 2182 | + unsigned char *path = NULL; |
---|
| 2183 | + __le16 *utf16_path = NULL; |
---|
| 2184 | + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
| 2185 | + int rc = 0; |
---|
| 2186 | + |
---|
| 2187 | + path = build_path_from_dentry(dentry); |
---|
| 2188 | + if (path == NULL) |
---|
| 2189 | + return -ENOMEM; |
---|
| 2190 | + |
---|
| 2191 | + cifs_sb = CIFS_SB(inode->i_sb); |
---|
| 2192 | + |
---|
| 2193 | + utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
---|
| 2194 | + if (utf16_path == NULL) { |
---|
| 2195 | + rc = -ENOMEM; |
---|
| 2196 | + goto notify_exit; |
---|
| 2197 | + } |
---|
| 2198 | + |
---|
| 2199 | + if (copy_from_user(¬ify, ioc_buf, sizeof(struct smb3_notify))) { |
---|
| 2200 | + rc = -EFAULT; |
---|
| 2201 | + goto notify_exit; |
---|
| 2202 | + } |
---|
| 2203 | + |
---|
| 2204 | + tcon = cifs_sb_master_tcon(cifs_sb); |
---|
| 2205 | + oparms.tcon = tcon; |
---|
| 2206 | + oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA; |
---|
| 2207 | + oparms.disposition = FILE_OPEN; |
---|
| 2208 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
| 2209 | + oparms.fid = &fid; |
---|
| 2210 | + oparms.reconnect = false; |
---|
| 2211 | + |
---|
| 2212 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL, |
---|
| 2213 | + NULL); |
---|
| 2214 | + if (rc) |
---|
| 2215 | + goto notify_exit; |
---|
| 2216 | + |
---|
| 2217 | + rc = SMB2_change_notify(xid, tcon, fid.persistent_fid, fid.volatile_fid, |
---|
| 2218 | + notify.watch_tree, notify.completion_filter); |
---|
| 2219 | + |
---|
| 2220 | + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
| 2221 | + |
---|
| 2222 | + cifs_dbg(FYI, "change notify for path %s rc %d\n", path, rc); |
---|
| 2223 | + |
---|
| 2224 | +notify_exit: |
---|
| 2225 | + kfree(path); |
---|
| 2226 | + kfree(utf16_path); |
---|
| 2227 | + return rc; |
---|
| 2228 | +} |
---|
| 2229 | + |
---|
1522 | 2230 | static int |
---|
1523 | 2231 | smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, |
---|
1524 | 2232 | const char *path, struct cifs_sb_info *cifs_sb, |
---|
.. | .. |
---|
1526 | 2234 | struct cifs_search_info *srch_inf) |
---|
1527 | 2235 | { |
---|
1528 | 2236 | __le16 *utf16_path; |
---|
1529 | | - int rc; |
---|
1530 | | - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
| 2237 | + struct smb_rqst rqst[2]; |
---|
| 2238 | + struct kvec rsp_iov[2]; |
---|
| 2239 | + int resp_buftype[2]; |
---|
| 2240 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 2241 | + struct kvec qd_iov[SMB2_QUERY_DIRECTORY_IOV_SIZE]; |
---|
| 2242 | + int rc, flags = 0; |
---|
| 2243 | + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
1531 | 2244 | struct cifs_open_parms oparms; |
---|
| 2245 | + struct smb2_query_directory_rsp *qd_rsp = NULL; |
---|
| 2246 | + struct smb2_create_rsp *op_rsp = NULL; |
---|
| 2247 | + struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
---|
1532 | 2248 | |
---|
1533 | 2249 | utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
---|
1534 | 2250 | if (!utf16_path) |
---|
1535 | 2251 | return -ENOMEM; |
---|
1536 | 2252 | |
---|
| 2253 | + if (smb3_encryption_required(tcon)) |
---|
| 2254 | + flags |= CIFS_TRANSFORM_REQ; |
---|
| 2255 | + |
---|
| 2256 | + memset(rqst, 0, sizeof(rqst)); |
---|
| 2257 | + resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER; |
---|
| 2258 | + memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
| 2259 | + |
---|
| 2260 | + /* Open */ |
---|
| 2261 | + memset(&open_iov, 0, sizeof(open_iov)); |
---|
| 2262 | + rqst[0].rq_iov = open_iov; |
---|
| 2263 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 2264 | + |
---|
1537 | 2265 | oparms.tcon = tcon; |
---|
1538 | 2266 | oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA; |
---|
1539 | 2267 | oparms.disposition = FILE_OPEN; |
---|
1540 | | - if (backup_cred(cifs_sb)) |
---|
1541 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
1542 | | - else |
---|
1543 | | - oparms.create_options = 0; |
---|
| 2268 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
1544 | 2269 | oparms.fid = fid; |
---|
1545 | 2270 | oparms.reconnect = false; |
---|
1546 | 2271 | |
---|
1547 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
1548 | | - kfree(utf16_path); |
---|
1549 | | - if (rc) { |
---|
1550 | | - cifs_dbg(FYI, "open dir failed rc=%d\n", rc); |
---|
1551 | | - return rc; |
---|
1552 | | - } |
---|
| 2272 | + rc = SMB2_open_init(tcon, server, |
---|
| 2273 | + &rqst[0], &oplock, &oparms, utf16_path); |
---|
| 2274 | + if (rc) |
---|
| 2275 | + goto qdf_free; |
---|
| 2276 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
1553 | 2277 | |
---|
| 2278 | + /* Query directory */ |
---|
1554 | 2279 | srch_inf->entries_in_buffer = 0; |
---|
1555 | 2280 | srch_inf->index_of_last_entry = 2; |
---|
1556 | 2281 | |
---|
1557 | | - rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, |
---|
1558 | | - fid->volatile_fid, 0, srch_inf); |
---|
1559 | | - if (rc) { |
---|
1560 | | - cifs_dbg(FYI, "query directory failed rc=%d\n", rc); |
---|
1561 | | - SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); |
---|
| 2282 | + memset(&qd_iov, 0, sizeof(qd_iov)); |
---|
| 2283 | + rqst[1].rq_iov = qd_iov; |
---|
| 2284 | + rqst[1].rq_nvec = SMB2_QUERY_DIRECTORY_IOV_SIZE; |
---|
| 2285 | + |
---|
| 2286 | + rc = SMB2_query_directory_init(xid, tcon, server, |
---|
| 2287 | + &rqst[1], |
---|
| 2288 | + COMPOUND_FID, COMPOUND_FID, |
---|
| 2289 | + 0, srch_inf->info_level); |
---|
| 2290 | + if (rc) |
---|
| 2291 | + goto qdf_free; |
---|
| 2292 | + |
---|
| 2293 | + smb2_set_related(&rqst[1]); |
---|
| 2294 | + |
---|
| 2295 | + rc = compound_send_recv(xid, tcon->ses, server, |
---|
| 2296 | + flags, 2, rqst, |
---|
| 2297 | + resp_buftype, rsp_iov); |
---|
| 2298 | + |
---|
| 2299 | + /* If the open failed there is nothing to do */ |
---|
| 2300 | + op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; |
---|
| 2301 | + if (op_rsp == NULL || op_rsp->sync_hdr.Status != STATUS_SUCCESS) { |
---|
| 2302 | + cifs_dbg(FYI, "query_dir_first: open failed rc=%d\n", rc); |
---|
| 2303 | + goto qdf_free; |
---|
1562 | 2304 | } |
---|
| 2305 | + fid->persistent_fid = op_rsp->PersistentFileId; |
---|
| 2306 | + fid->volatile_fid = op_rsp->VolatileFileId; |
---|
| 2307 | + |
---|
| 2308 | + /* Anything else than ENODATA means a genuine error */ |
---|
| 2309 | + if (rc && rc != -ENODATA) { |
---|
| 2310 | + SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); |
---|
| 2311 | + cifs_dbg(FYI, "query_dir_first: query directory failed rc=%d\n", rc); |
---|
| 2312 | + trace_smb3_query_dir_err(xid, fid->persistent_fid, |
---|
| 2313 | + tcon->tid, tcon->ses->Suid, 0, 0, rc); |
---|
| 2314 | + goto qdf_free; |
---|
| 2315 | + } |
---|
| 2316 | + |
---|
| 2317 | + atomic_inc(&tcon->num_remote_opens); |
---|
| 2318 | + |
---|
| 2319 | + qd_rsp = (struct smb2_query_directory_rsp *)rsp_iov[1].iov_base; |
---|
| 2320 | + if (qd_rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
---|
| 2321 | + trace_smb3_query_dir_done(xid, fid->persistent_fid, |
---|
| 2322 | + tcon->tid, tcon->ses->Suid, 0, 0); |
---|
| 2323 | + srch_inf->endOfSearch = true; |
---|
| 2324 | + rc = 0; |
---|
| 2325 | + goto qdf_free; |
---|
| 2326 | + } |
---|
| 2327 | + |
---|
| 2328 | + rc = smb2_parse_query_directory(tcon, &rsp_iov[1], resp_buftype[1], |
---|
| 2329 | + srch_inf); |
---|
| 2330 | + if (rc) { |
---|
| 2331 | + trace_smb3_query_dir_err(xid, fid->persistent_fid, tcon->tid, |
---|
| 2332 | + tcon->ses->Suid, 0, 0, rc); |
---|
| 2333 | + goto qdf_free; |
---|
| 2334 | + } |
---|
| 2335 | + resp_buftype[1] = CIFS_NO_BUFFER; |
---|
| 2336 | + |
---|
| 2337 | + trace_smb3_query_dir_done(xid, fid->persistent_fid, tcon->tid, |
---|
| 2338 | + tcon->ses->Suid, 0, srch_inf->entries_in_buffer); |
---|
| 2339 | + |
---|
| 2340 | + qdf_free: |
---|
| 2341 | + kfree(utf16_path); |
---|
| 2342 | + SMB2_open_free(&rqst[0]); |
---|
| 2343 | + SMB2_query_directory_free(&rqst[1]); |
---|
| 2344 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 2345 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
1563 | 2346 | return rc; |
---|
1564 | 2347 | } |
---|
1565 | 2348 | |
---|
.. | .. |
---|
1580 | 2363 | } |
---|
1581 | 2364 | |
---|
1582 | 2365 | /* |
---|
1583 | | -* If we negotiate SMB2 protocol and get STATUS_PENDING - update |
---|
1584 | | -* the number of credits and return true. Otherwise - return false. |
---|
1585 | | -*/ |
---|
| 2366 | + * If we negotiate SMB2 protocol and get STATUS_PENDING - update |
---|
| 2367 | + * the number of credits and return true. Otherwise - return false. |
---|
| 2368 | + */ |
---|
1586 | 2369 | static bool |
---|
1587 | | -smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) |
---|
| 2370 | +smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) |
---|
1588 | 2371 | { |
---|
1589 | 2372 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; |
---|
1590 | 2373 | |
---|
1591 | 2374 | if (shdr->Status != STATUS_PENDING) |
---|
1592 | 2375 | return false; |
---|
1593 | 2376 | |
---|
1594 | | - if (!length) { |
---|
| 2377 | + if (shdr->CreditRequest) { |
---|
1595 | 2378 | spin_lock(&server->req_lock); |
---|
1596 | 2379 | server->credits += le16_to_cpu(shdr->CreditRequest); |
---|
1597 | 2380 | spin_unlock(&server->req_lock); |
---|
.. | .. |
---|
1618 | 2401 | return true; |
---|
1619 | 2402 | } |
---|
1620 | 2403 | |
---|
| 2404 | +static bool |
---|
| 2405 | +smb2_is_status_io_timeout(char *buf) |
---|
| 2406 | +{ |
---|
| 2407 | + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; |
---|
| 2408 | + |
---|
| 2409 | + if (shdr->Status == STATUS_IO_TIMEOUT) |
---|
| 2410 | + return true; |
---|
| 2411 | + else |
---|
| 2412 | + return false; |
---|
| 2413 | +} |
---|
| 2414 | + |
---|
1621 | 2415 | static int |
---|
1622 | 2416 | smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, |
---|
1623 | 2417 | struct cifsInodeInfo *cinode) |
---|
.. | .. |
---|
1631 | 2425 | CIFS_CACHE_READ(cinode) ? 1 : 0); |
---|
1632 | 2426 | } |
---|
1633 | 2427 | |
---|
1634 | | -static void |
---|
| 2428 | +void |
---|
1635 | 2429 | smb2_set_related(struct smb_rqst *rqst) |
---|
1636 | 2430 | { |
---|
1637 | 2431 | struct smb2_sync_hdr *shdr; |
---|
1638 | 2432 | |
---|
1639 | 2433 | shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); |
---|
| 2434 | + if (shdr == NULL) { |
---|
| 2435 | + cifs_dbg(FYI, "shdr NULL in smb2_set_related\n"); |
---|
| 2436 | + return; |
---|
| 2437 | + } |
---|
1640 | 2438 | shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS; |
---|
1641 | 2439 | } |
---|
1642 | 2440 | |
---|
1643 | 2441 | char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; |
---|
1644 | 2442 | |
---|
1645 | | -static void |
---|
1646 | | -smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst) |
---|
| 2443 | +void |
---|
| 2444 | +smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) |
---|
1647 | 2445 | { |
---|
1648 | 2446 | struct smb2_sync_hdr *shdr; |
---|
| 2447 | + struct cifs_ses *ses = tcon->ses; |
---|
| 2448 | + struct TCP_Server_Info *server = ses->server; |
---|
1649 | 2449 | unsigned long len = smb_rqst_len(server, rqst); |
---|
1650 | | - |
---|
1651 | | - /* SMB headers in a compound are 8 byte aligned. */ |
---|
1652 | | - if (len & 7) { |
---|
1653 | | - rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; |
---|
1654 | | - rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); |
---|
1655 | | - rqst->rq_nvec++; |
---|
1656 | | - len = smb_rqst_len(server, rqst); |
---|
1657 | | - } |
---|
| 2450 | + int i, num_padding; |
---|
1658 | 2451 | |
---|
1659 | 2452 | shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); |
---|
| 2453 | + if (shdr == NULL) { |
---|
| 2454 | + cifs_dbg(FYI, "shdr NULL in smb2_set_next_command\n"); |
---|
| 2455 | + return; |
---|
| 2456 | + } |
---|
| 2457 | + |
---|
| 2458 | + /* SMB headers in a compound are 8 byte aligned. */ |
---|
| 2459 | + |
---|
| 2460 | + /* No padding needed */ |
---|
| 2461 | + if (!(len & 7)) |
---|
| 2462 | + goto finished; |
---|
| 2463 | + |
---|
| 2464 | + num_padding = 8 - (len & 7); |
---|
| 2465 | + if (!smb3_encryption_required(tcon)) { |
---|
| 2466 | + /* |
---|
| 2467 | + * If we do not have encryption then we can just add an extra |
---|
| 2468 | + * iov for the padding. |
---|
| 2469 | + */ |
---|
| 2470 | + rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; |
---|
| 2471 | + rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding; |
---|
| 2472 | + rqst->rq_nvec++; |
---|
| 2473 | + len += num_padding; |
---|
| 2474 | + } else { |
---|
| 2475 | + /* |
---|
| 2476 | + * We can not add a small padding iov for the encryption case |
---|
| 2477 | + * because the encryption framework can not handle the padding |
---|
| 2478 | + * iovs. |
---|
| 2479 | + * We have to flatten this into a single buffer and add |
---|
| 2480 | + * the padding to it. |
---|
| 2481 | + */ |
---|
| 2482 | + for (i = 1; i < rqst->rq_nvec; i++) { |
---|
| 2483 | + memcpy(rqst->rq_iov[0].iov_base + |
---|
| 2484 | + rqst->rq_iov[0].iov_len, |
---|
| 2485 | + rqst->rq_iov[i].iov_base, |
---|
| 2486 | + rqst->rq_iov[i].iov_len); |
---|
| 2487 | + rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len; |
---|
| 2488 | + } |
---|
| 2489 | + memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len, |
---|
| 2490 | + 0, num_padding); |
---|
| 2491 | + rqst->rq_iov[0].iov_len += num_padding; |
---|
| 2492 | + len += num_padding; |
---|
| 2493 | + rqst->rq_nvec = 1; |
---|
| 2494 | + } |
---|
| 2495 | + |
---|
| 2496 | + finished: |
---|
1660 | 2497 | shdr->NextCommand = cpu_to_le32(len); |
---|
1661 | 2498 | } |
---|
1662 | 2499 | |
---|
1663 | | -static int |
---|
1664 | | -smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, |
---|
1665 | | - struct kstatfs *buf) |
---|
| 2500 | +/* |
---|
| 2501 | + * Passes the query info response back to the caller on success. |
---|
| 2502 | + * Caller need to free this with free_rsp_buf(). |
---|
| 2503 | + */ |
---|
| 2504 | +int |
---|
| 2505 | +smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 2506 | + __le16 *utf16_path, u32 desired_access, |
---|
| 2507 | + u32 class, u32 type, u32 output_len, |
---|
| 2508 | + struct kvec *rsp, int *buftype, |
---|
| 2509 | + struct cifs_sb_info *cifs_sb) |
---|
1666 | 2510 | { |
---|
1667 | | - struct smb2_query_info_rsp *rsp; |
---|
1668 | | - struct smb2_fs_full_size_info *info = NULL; |
---|
| 2511 | + struct cifs_ses *ses = tcon->ses; |
---|
| 2512 | + struct TCP_Server_Info *server = cifs_pick_channel(ses); |
---|
| 2513 | + int flags = CIFS_CP_CREATE_CLOSE_OP; |
---|
1669 | 2514 | struct smb_rqst rqst[3]; |
---|
1670 | 2515 | int resp_buftype[3]; |
---|
1671 | 2516 | struct kvec rsp_iov[3]; |
---|
1672 | 2517 | struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
1673 | 2518 | struct kvec qi_iov[1]; |
---|
1674 | 2519 | struct kvec close_iov[1]; |
---|
1675 | | - struct cifs_ses *ses = tcon->ses; |
---|
1676 | | - struct TCP_Server_Info *server = ses->server; |
---|
1677 | | - __le16 srch_path = 0; /* Null - open root of share */ |
---|
1678 | 2520 | u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
1679 | 2521 | struct cifs_open_parms oparms; |
---|
1680 | 2522 | struct cifs_fid fid; |
---|
1681 | | - int flags = 0; |
---|
1682 | 2523 | int rc; |
---|
1683 | 2524 | |
---|
1684 | 2525 | if (smb3_encryption_required(tcon)) |
---|
1685 | 2526 | flags |= CIFS_TRANSFORM_REQ; |
---|
1686 | 2527 | |
---|
1687 | 2528 | memset(rqst, 0, sizeof(rqst)); |
---|
1688 | | - memset(resp_buftype, 0, sizeof(resp_buftype)); |
---|
| 2529 | + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
---|
1689 | 2530 | memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
1690 | 2531 | |
---|
1691 | 2532 | memset(&open_iov, 0, sizeof(open_iov)); |
---|
.. | .. |
---|
1693 | 2534 | rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
1694 | 2535 | |
---|
1695 | 2536 | oparms.tcon = tcon; |
---|
1696 | | - oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
| 2537 | + oparms.desired_access = desired_access; |
---|
1697 | 2538 | oparms.disposition = FILE_OPEN; |
---|
1698 | | - oparms.create_options = 0; |
---|
| 2539 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
1699 | 2540 | oparms.fid = &fid; |
---|
1700 | 2541 | oparms.reconnect = false; |
---|
1701 | 2542 | |
---|
1702 | | - rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path); |
---|
| 2543 | + rc = SMB2_open_init(tcon, server, |
---|
| 2544 | + &rqst[0], &oplock, &oparms, utf16_path); |
---|
1703 | 2545 | if (rc) |
---|
1704 | | - goto qfs_exit; |
---|
1705 | | - smb2_set_next_command(server, &rqst[0]); |
---|
| 2546 | + goto qic_exit; |
---|
| 2547 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
1706 | 2548 | |
---|
1707 | 2549 | memset(&qi_iov, 0, sizeof(qi_iov)); |
---|
1708 | 2550 | rqst[1].rq_iov = qi_iov; |
---|
1709 | 2551 | rqst[1].rq_nvec = 1; |
---|
1710 | 2552 | |
---|
1711 | | - rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, |
---|
1712 | | - FS_FULL_SIZE_INFORMATION, |
---|
1713 | | - SMB2_O_INFO_FILESYSTEM, 0, |
---|
1714 | | - sizeof(struct smb2_fs_full_size_info)); |
---|
| 2553 | + rc = SMB2_query_info_init(tcon, server, |
---|
| 2554 | + &rqst[1], COMPOUND_FID, COMPOUND_FID, |
---|
| 2555 | + class, type, 0, |
---|
| 2556 | + output_len, 0, |
---|
| 2557 | + NULL); |
---|
1715 | 2558 | if (rc) |
---|
1716 | | - goto qfs_exit; |
---|
1717 | | - smb2_set_next_command(server, &rqst[1]); |
---|
| 2559 | + goto qic_exit; |
---|
| 2560 | + smb2_set_next_command(tcon, &rqst[1]); |
---|
1718 | 2561 | smb2_set_related(&rqst[1]); |
---|
1719 | 2562 | |
---|
1720 | 2563 | memset(&close_iov, 0, sizeof(close_iov)); |
---|
1721 | 2564 | rqst[2].rq_iov = close_iov; |
---|
1722 | 2565 | rqst[2].rq_nvec = 1; |
---|
1723 | 2566 | |
---|
1724 | | - rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); |
---|
| 2567 | + rc = SMB2_close_init(tcon, server, |
---|
| 2568 | + &rqst[2], COMPOUND_FID, COMPOUND_FID, false); |
---|
1725 | 2569 | if (rc) |
---|
1726 | | - goto qfs_exit; |
---|
| 2570 | + goto qic_exit; |
---|
1727 | 2571 | smb2_set_related(&rqst[2]); |
---|
1728 | 2572 | |
---|
1729 | | - rc = compound_send_recv(xid, ses, flags, 3, rqst, |
---|
| 2573 | + rc = compound_send_recv(xid, ses, server, |
---|
| 2574 | + flags, 3, rqst, |
---|
1730 | 2575 | resp_buftype, rsp_iov); |
---|
1731 | | - if (rc) |
---|
1732 | | - goto qfs_exit; |
---|
| 2576 | + if (rc) { |
---|
| 2577 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 2578 | + if (rc == -EREMCHG) { |
---|
| 2579 | + tcon->need_reconnect = true; |
---|
| 2580 | + pr_warn_once("server share %s deleted\n", |
---|
| 2581 | + tcon->treeName); |
---|
| 2582 | + } |
---|
| 2583 | + goto qic_exit; |
---|
| 2584 | + } |
---|
| 2585 | + *rsp = rsp_iov[1]; |
---|
| 2586 | + *buftype = resp_buftype[1]; |
---|
1733 | 2587 | |
---|
1734 | | - rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; |
---|
1735 | | - buf->f_type = SMB2_MAGIC_NUMBER; |
---|
1736 | | - info = (struct smb2_fs_full_size_info *)( |
---|
1737 | | - le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); |
---|
1738 | | - rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
---|
1739 | | - le32_to_cpu(rsp->OutputBufferLength), |
---|
1740 | | - &rsp_iov[1], |
---|
1741 | | - sizeof(struct smb2_fs_full_size_info)); |
---|
1742 | | - if (!rc) |
---|
1743 | | - smb2_copy_fs_info_to_kstatfs(info, buf); |
---|
1744 | | - |
---|
1745 | | -qfs_exit: |
---|
| 2588 | + qic_exit: |
---|
1746 | 2589 | SMB2_open_free(&rqst[0]); |
---|
1747 | 2590 | SMB2_query_info_free(&rqst[1]); |
---|
1748 | 2591 | SMB2_close_free(&rqst[2]); |
---|
1749 | 2592 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
1750 | | - free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
1751 | 2593 | free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
---|
1752 | 2594 | return rc; |
---|
1753 | 2595 | } |
---|
1754 | 2596 | |
---|
1755 | 2597 | static int |
---|
| 2598 | +smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 2599 | + struct cifs_sb_info *cifs_sb, struct kstatfs *buf) |
---|
| 2600 | +{ |
---|
| 2601 | + struct smb2_query_info_rsp *rsp; |
---|
| 2602 | + struct smb2_fs_full_size_info *info = NULL; |
---|
| 2603 | + __le16 utf16_path = 0; /* Null - open root of share */ |
---|
| 2604 | + struct kvec rsp_iov = {NULL, 0}; |
---|
| 2605 | + int buftype = CIFS_NO_BUFFER; |
---|
| 2606 | + int rc; |
---|
| 2607 | + |
---|
| 2608 | + |
---|
| 2609 | + rc = smb2_query_info_compound(xid, tcon, &utf16_path, |
---|
| 2610 | + FILE_READ_ATTRIBUTES, |
---|
| 2611 | + FS_FULL_SIZE_INFORMATION, |
---|
| 2612 | + SMB2_O_INFO_FILESYSTEM, |
---|
| 2613 | + sizeof(struct smb2_fs_full_size_info), |
---|
| 2614 | + &rsp_iov, &buftype, cifs_sb); |
---|
| 2615 | + if (rc) |
---|
| 2616 | + goto qfs_exit; |
---|
| 2617 | + |
---|
| 2618 | + rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
---|
| 2619 | + buf->f_type = SMB2_MAGIC_NUMBER; |
---|
| 2620 | + info = (struct smb2_fs_full_size_info *)( |
---|
| 2621 | + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); |
---|
| 2622 | + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
---|
| 2623 | + le32_to_cpu(rsp->OutputBufferLength), |
---|
| 2624 | + &rsp_iov, |
---|
| 2625 | + sizeof(struct smb2_fs_full_size_info)); |
---|
| 2626 | + if (!rc) |
---|
| 2627 | + smb2_copy_fs_info_to_kstatfs(info, buf); |
---|
| 2628 | + |
---|
| 2629 | +qfs_exit: |
---|
| 2630 | + free_rsp_buf(buftype, rsp_iov.iov_base); |
---|
| 2631 | + return rc; |
---|
| 2632 | +} |
---|
| 2633 | + |
---|
| 2634 | +static int |
---|
1756 | 2635 | smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, |
---|
1757 | | - struct kstatfs *buf) |
---|
| 2636 | + struct cifs_sb_info *cifs_sb, struct kstatfs *buf) |
---|
1758 | 2637 | { |
---|
1759 | 2638 | int rc; |
---|
1760 | 2639 | __le16 srch_path = 0; /* Null - open root of share */ |
---|
.. | .. |
---|
1763 | 2642 | struct cifs_fid fid; |
---|
1764 | 2643 | |
---|
1765 | 2644 | if (!tcon->posix_extensions) |
---|
1766 | | - return smb2_queryfs(xid, tcon, buf); |
---|
| 2645 | + return smb2_queryfs(xid, tcon, cifs_sb, buf); |
---|
1767 | 2646 | |
---|
1768 | 2647 | oparms.tcon = tcon; |
---|
1769 | 2648 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
1770 | 2649 | oparms.disposition = FILE_OPEN; |
---|
1771 | | - oparms.create_options = 0; |
---|
| 2650 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
1772 | 2651 | oparms.fid = &fid; |
---|
1773 | 2652 | oparms.reconnect = false; |
---|
1774 | 2653 | |
---|
1775 | | - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); |
---|
| 2654 | + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, |
---|
| 2655 | + NULL, NULL); |
---|
1776 | 2656 | if (rc) |
---|
1777 | 2657 | return rc; |
---|
1778 | 2658 | |
---|
.. | .. |
---|
1834 | 2714 | struct get_dfs_referral_rsp *dfs_rsp = NULL; |
---|
1835 | 2715 | u32 dfs_req_size = 0, dfs_rsp_size = 0; |
---|
1836 | 2716 | |
---|
1837 | | - cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name); |
---|
| 2717 | + cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name); |
---|
1838 | 2718 | |
---|
1839 | 2719 | /* |
---|
1840 | 2720 | * Try to use the IPC tcon, otherwise just use any |
---|
.. | .. |
---|
1881 | 2761 | do { |
---|
1882 | 2762 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
---|
1883 | 2763 | FSCTL_DFS_GET_REFERRALS, |
---|
1884 | | - true /* is_fsctl */, |
---|
1885 | | - (char *)dfs_req, dfs_req_size, |
---|
| 2764 | + (char *)dfs_req, dfs_req_size, CIFSMaxBufSize, |
---|
1886 | 2765 | (char **)&dfs_rsp, &dfs_rsp_size); |
---|
1887 | 2766 | } while (rc == -EAGAIN); |
---|
1888 | 2767 | |
---|
1889 | 2768 | if (rc) { |
---|
1890 | 2769 | if ((rc != -ENOENT) && (rc != -EOPNOTSUPP)) |
---|
1891 | | - cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc); |
---|
| 2770 | + cifs_tcon_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc); |
---|
1892 | 2771 | goto out; |
---|
1893 | 2772 | } |
---|
1894 | 2773 | |
---|
.. | .. |
---|
1897 | 2776 | nls_codepage, remap, search_name, |
---|
1898 | 2777 | true /* is_unicode */); |
---|
1899 | 2778 | if (rc) { |
---|
1900 | | - cifs_dbg(VFS, "parse error in smb2_get_dfs_refer rc=%d\n", rc); |
---|
| 2779 | + cifs_tcon_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc); |
---|
1901 | 2780 | goto out; |
---|
1902 | 2781 | } |
---|
1903 | 2782 | |
---|
.. | .. |
---|
1913 | 2792 | kfree(dfs_rsp); |
---|
1914 | 2793 | return rc; |
---|
1915 | 2794 | } |
---|
| 2795 | + |
---|
| 2796 | +static int |
---|
| 2797 | +parse_reparse_posix(struct reparse_posix_data *symlink_buf, |
---|
| 2798 | + u32 plen, char **target_path, |
---|
| 2799 | + struct cifs_sb_info *cifs_sb) |
---|
| 2800 | +{ |
---|
| 2801 | + unsigned int len; |
---|
| 2802 | + |
---|
| 2803 | + /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ |
---|
| 2804 | + len = le16_to_cpu(symlink_buf->ReparseDataLength); |
---|
| 2805 | + |
---|
| 2806 | + if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) { |
---|
| 2807 | + cifs_dbg(VFS, "%lld not a supported symlink type\n", |
---|
| 2808 | + le64_to_cpu(symlink_buf->InodeType)); |
---|
| 2809 | + return -EOPNOTSUPP; |
---|
| 2810 | + } |
---|
| 2811 | + |
---|
| 2812 | + *target_path = cifs_strndup_from_utf16( |
---|
| 2813 | + symlink_buf->PathBuffer, |
---|
| 2814 | + len, true, cifs_sb->local_nls); |
---|
| 2815 | + if (!(*target_path)) |
---|
| 2816 | + return -ENOMEM; |
---|
| 2817 | + |
---|
| 2818 | + convert_delimiter(*target_path, '/'); |
---|
| 2819 | + cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); |
---|
| 2820 | + |
---|
| 2821 | + return 0; |
---|
| 2822 | +} |
---|
| 2823 | + |
---|
| 2824 | +static int |
---|
| 2825 | +parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf, |
---|
| 2826 | + u32 plen, char **target_path, |
---|
| 2827 | + struct cifs_sb_info *cifs_sb) |
---|
| 2828 | +{ |
---|
| 2829 | + unsigned int sub_len; |
---|
| 2830 | + unsigned int sub_offset; |
---|
| 2831 | + |
---|
| 2832 | + /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ |
---|
| 2833 | + |
---|
| 2834 | + sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset); |
---|
| 2835 | + sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength); |
---|
| 2836 | + if (sub_offset + 20 > plen || |
---|
| 2837 | + sub_offset + sub_len + 20 > plen) { |
---|
| 2838 | + cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); |
---|
| 2839 | + return -EIO; |
---|
| 2840 | + } |
---|
| 2841 | + |
---|
| 2842 | + *target_path = cifs_strndup_from_utf16( |
---|
| 2843 | + symlink_buf->PathBuffer + sub_offset, |
---|
| 2844 | + sub_len, true, cifs_sb->local_nls); |
---|
| 2845 | + if (!(*target_path)) |
---|
| 2846 | + return -ENOMEM; |
---|
| 2847 | + |
---|
| 2848 | + convert_delimiter(*target_path, '/'); |
---|
| 2849 | + cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); |
---|
| 2850 | + |
---|
| 2851 | + return 0; |
---|
| 2852 | +} |
---|
| 2853 | + |
---|
| 2854 | +static int |
---|
| 2855 | +parse_reparse_point(struct reparse_data_buffer *buf, |
---|
| 2856 | + u32 plen, char **target_path, |
---|
| 2857 | + struct cifs_sb_info *cifs_sb) |
---|
| 2858 | +{ |
---|
| 2859 | + if (plen < sizeof(struct reparse_data_buffer)) { |
---|
| 2860 | + cifs_dbg(VFS, "reparse buffer is too small. Must be at least 8 bytes but was %d\n", |
---|
| 2861 | + plen); |
---|
| 2862 | + return -EIO; |
---|
| 2863 | + } |
---|
| 2864 | + |
---|
| 2865 | + if (plen < le16_to_cpu(buf->ReparseDataLength) + |
---|
| 2866 | + sizeof(struct reparse_data_buffer)) { |
---|
| 2867 | + cifs_dbg(VFS, "srv returned invalid reparse buf length: %d\n", |
---|
| 2868 | + plen); |
---|
| 2869 | + return -EIO; |
---|
| 2870 | + } |
---|
| 2871 | + |
---|
| 2872 | + /* See MS-FSCC 2.1.2 */ |
---|
| 2873 | + switch (le32_to_cpu(buf->ReparseTag)) { |
---|
| 2874 | + case IO_REPARSE_TAG_NFS: |
---|
| 2875 | + return parse_reparse_posix( |
---|
| 2876 | + (struct reparse_posix_data *)buf, |
---|
| 2877 | + plen, target_path, cifs_sb); |
---|
| 2878 | + case IO_REPARSE_TAG_SYMLINK: |
---|
| 2879 | + return parse_reparse_symlink( |
---|
| 2880 | + (struct reparse_symlink_data_buffer *)buf, |
---|
| 2881 | + plen, target_path, cifs_sb); |
---|
| 2882 | + default: |
---|
| 2883 | + cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n", |
---|
| 2884 | + le32_to_cpu(buf->ReparseTag)); |
---|
| 2885 | + return -EOPNOTSUPP; |
---|
| 2886 | + } |
---|
| 2887 | +} |
---|
| 2888 | + |
---|
1916 | 2889 | #define SMB2_SYMLINK_STRUCT_SIZE \ |
---|
1917 | 2890 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) |
---|
1918 | 2891 | |
---|
1919 | 2892 | static int |
---|
1920 | 2893 | smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, |
---|
1921 | | - const char *full_path, char **target_path, |
---|
1922 | | - struct cifs_sb_info *cifs_sb) |
---|
| 2894 | + struct cifs_sb_info *cifs_sb, const char *full_path, |
---|
| 2895 | + char **target_path, bool is_reparse_point) |
---|
1923 | 2896 | { |
---|
1924 | 2897 | int rc; |
---|
1925 | | - __le16 *utf16_path; |
---|
| 2898 | + __le16 *utf16_path = NULL; |
---|
1926 | 2899 | __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
1927 | 2900 | struct cifs_open_parms oparms; |
---|
1928 | 2901 | struct cifs_fid fid; |
---|
1929 | 2902 | struct kvec err_iov = {NULL, 0}; |
---|
1930 | 2903 | struct smb2_err_rsp *err_buf = NULL; |
---|
1931 | | - int resp_buftype; |
---|
1932 | 2904 | struct smb2_symlink_err_rsp *symlink; |
---|
| 2905 | + struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
---|
1933 | 2906 | unsigned int sub_len; |
---|
1934 | 2907 | unsigned int sub_offset; |
---|
1935 | 2908 | unsigned int print_len; |
---|
1936 | 2909 | unsigned int print_offset; |
---|
| 2910 | + int flags = CIFS_CP_CREATE_CLOSE_OP; |
---|
| 2911 | + struct smb_rqst rqst[3]; |
---|
| 2912 | + int resp_buftype[3]; |
---|
| 2913 | + struct kvec rsp_iov[3]; |
---|
| 2914 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 2915 | + struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; |
---|
| 2916 | + struct kvec close_iov[1]; |
---|
| 2917 | + struct smb2_create_rsp *create_rsp; |
---|
| 2918 | + struct smb2_ioctl_rsp *ioctl_rsp; |
---|
| 2919 | + struct reparse_data_buffer *reparse_buf; |
---|
| 2920 | + int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0; |
---|
| 2921 | + u32 plen; |
---|
1937 | 2922 | |
---|
1938 | 2923 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
---|
| 2924 | + |
---|
| 2925 | + *target_path = NULL; |
---|
| 2926 | + |
---|
| 2927 | + if (smb3_encryption_required(tcon)) |
---|
| 2928 | + flags |= CIFS_TRANSFORM_REQ; |
---|
| 2929 | + |
---|
| 2930 | + memset(rqst, 0, sizeof(rqst)); |
---|
| 2931 | + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
---|
| 2932 | + memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
1939 | 2933 | |
---|
1940 | 2934 | utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); |
---|
1941 | 2935 | if (!utf16_path) |
---|
1942 | 2936 | return -ENOMEM; |
---|
1943 | 2937 | |
---|
| 2938 | + /* Open */ |
---|
| 2939 | + memset(&open_iov, 0, sizeof(open_iov)); |
---|
| 2940 | + rqst[0].rq_iov = open_iov; |
---|
| 2941 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 2942 | + |
---|
| 2943 | + memset(&oparms, 0, sizeof(oparms)); |
---|
1944 | 2944 | oparms.tcon = tcon; |
---|
1945 | 2945 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
1946 | 2946 | oparms.disposition = FILE_OPEN; |
---|
1947 | | - if (backup_cred(cifs_sb)) |
---|
1948 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
1949 | | - else |
---|
1950 | | - oparms.create_options = 0; |
---|
| 2947 | + oparms.create_options = cifs_create_options(cifs_sb, create_options); |
---|
1951 | 2948 | oparms.fid = &fid; |
---|
1952 | 2949 | oparms.reconnect = false; |
---|
1953 | 2950 | |
---|
1954 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov, |
---|
1955 | | - &resp_buftype); |
---|
1956 | | - if (!rc) |
---|
1957 | | - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); |
---|
| 2951 | + rc = SMB2_open_init(tcon, server, |
---|
| 2952 | + &rqst[0], &oplock, &oparms, utf16_path); |
---|
| 2953 | + if (rc) |
---|
| 2954 | + goto querty_exit; |
---|
| 2955 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
| 2956 | + |
---|
| 2957 | + |
---|
| 2958 | + /* IOCTL */ |
---|
| 2959 | + memset(&io_iov, 0, sizeof(io_iov)); |
---|
| 2960 | + rqst[1].rq_iov = io_iov; |
---|
| 2961 | + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; |
---|
| 2962 | + |
---|
| 2963 | + rc = SMB2_ioctl_init(tcon, server, |
---|
| 2964 | + &rqst[1], fid.persistent_fid, |
---|
| 2965 | + fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0, |
---|
| 2966 | + CIFSMaxBufSize - |
---|
| 2967 | + MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 2968 | + MAX_SMB2_CLOSE_RESPONSE_SIZE); |
---|
| 2969 | + if (rc) |
---|
| 2970 | + goto querty_exit; |
---|
| 2971 | + |
---|
| 2972 | + smb2_set_next_command(tcon, &rqst[1]); |
---|
| 2973 | + smb2_set_related(&rqst[1]); |
---|
| 2974 | + |
---|
| 2975 | + |
---|
| 2976 | + /* Close */ |
---|
| 2977 | + memset(&close_iov, 0, sizeof(close_iov)); |
---|
| 2978 | + rqst[2].rq_iov = close_iov; |
---|
| 2979 | + rqst[2].rq_nvec = 1; |
---|
| 2980 | + |
---|
| 2981 | + rc = SMB2_close_init(tcon, server, |
---|
| 2982 | + &rqst[2], COMPOUND_FID, COMPOUND_FID, false); |
---|
| 2983 | + if (rc) |
---|
| 2984 | + goto querty_exit; |
---|
| 2985 | + |
---|
| 2986 | + smb2_set_related(&rqst[2]); |
---|
| 2987 | + |
---|
| 2988 | + rc = compound_send_recv(xid, tcon->ses, server, |
---|
| 2989 | + flags, 3, rqst, |
---|
| 2990 | + resp_buftype, rsp_iov); |
---|
| 2991 | + |
---|
| 2992 | + create_rsp = rsp_iov[0].iov_base; |
---|
| 2993 | + if (create_rsp && create_rsp->sync_hdr.Status) |
---|
| 2994 | + err_iov = rsp_iov[0]; |
---|
| 2995 | + ioctl_rsp = rsp_iov[1].iov_base; |
---|
| 2996 | + |
---|
| 2997 | + /* |
---|
| 2998 | + * Open was successful and we got an ioctl response. |
---|
| 2999 | + */ |
---|
| 3000 | + if ((rc == 0) && (is_reparse_point)) { |
---|
| 3001 | + /* See MS-FSCC 2.3.23 */ |
---|
| 3002 | + |
---|
| 3003 | + reparse_buf = (struct reparse_data_buffer *) |
---|
| 3004 | + ((char *)ioctl_rsp + |
---|
| 3005 | + le32_to_cpu(ioctl_rsp->OutputOffset)); |
---|
| 3006 | + plen = le32_to_cpu(ioctl_rsp->OutputCount); |
---|
| 3007 | + |
---|
| 3008 | + if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > |
---|
| 3009 | + rsp_iov[1].iov_len) { |
---|
| 3010 | + cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n", |
---|
| 3011 | + plen); |
---|
| 3012 | + rc = -EIO; |
---|
| 3013 | + goto querty_exit; |
---|
| 3014 | + } |
---|
| 3015 | + |
---|
| 3016 | + rc = parse_reparse_point(reparse_buf, plen, target_path, |
---|
| 3017 | + cifs_sb); |
---|
| 3018 | + goto querty_exit; |
---|
| 3019 | + } |
---|
| 3020 | + |
---|
1958 | 3021 | if (!rc || !err_iov.iov_base) { |
---|
1959 | 3022 | rc = -ENOENT; |
---|
1960 | | - goto free_path; |
---|
| 3023 | + goto querty_exit; |
---|
1961 | 3024 | } |
---|
1962 | 3025 | |
---|
1963 | 3026 | err_buf = err_iov.iov_base; |
---|
1964 | 3027 | if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || |
---|
1965 | 3028 | err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { |
---|
1966 | | - rc = -ENOENT; |
---|
| 3029 | + rc = -EINVAL; |
---|
| 3030 | + goto querty_exit; |
---|
| 3031 | + } |
---|
| 3032 | + |
---|
| 3033 | + symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; |
---|
| 3034 | + if (le32_to_cpu(symlink->SymLinkErrorTag) != SYMLINK_ERROR_TAG || |
---|
| 3035 | + le32_to_cpu(symlink->ReparseTag) != IO_REPARSE_TAG_SYMLINK) { |
---|
| 3036 | + rc = -EINVAL; |
---|
1967 | 3037 | goto querty_exit; |
---|
1968 | 3038 | } |
---|
1969 | 3039 | |
---|
1970 | 3040 | /* open must fail on symlink - reset rc */ |
---|
1971 | 3041 | rc = 0; |
---|
1972 | | - symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; |
---|
1973 | 3042 | sub_len = le16_to_cpu(symlink->SubstituteNameLength); |
---|
1974 | 3043 | sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); |
---|
1975 | 3044 | print_len = le16_to_cpu(symlink->PrintNameLength); |
---|
1976 | 3045 | print_offset = le16_to_cpu(symlink->PrintNameOffset); |
---|
1977 | 3046 | |
---|
1978 | 3047 | if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { |
---|
1979 | | - rc = -ENOENT; |
---|
| 3048 | + rc = -EINVAL; |
---|
1980 | 3049 | goto querty_exit; |
---|
1981 | 3050 | } |
---|
1982 | 3051 | |
---|
1983 | 3052 | if (err_iov.iov_len < |
---|
1984 | 3053 | SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { |
---|
1985 | | - rc = -ENOENT; |
---|
| 3054 | + rc = -EINVAL; |
---|
1986 | 3055 | goto querty_exit; |
---|
1987 | 3056 | } |
---|
1988 | 3057 | |
---|
.. | .. |
---|
1997 | 3066 | cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); |
---|
1998 | 3067 | |
---|
1999 | 3068 | querty_exit: |
---|
2000 | | - free_rsp_buf(resp_buftype, err_buf); |
---|
2001 | | - free_path: |
---|
| 3069 | + cifs_dbg(FYI, "query symlink rc %d\n", rc); |
---|
2002 | 3070 | kfree(utf16_path); |
---|
| 3071 | + SMB2_open_free(&rqst[0]); |
---|
| 3072 | + SMB2_ioctl_free(&rqst[1]); |
---|
| 3073 | + SMB2_close_free(&rqst[2]); |
---|
| 3074 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 3075 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 3076 | + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
---|
2003 | 3077 | return rc; |
---|
2004 | 3078 | } |
---|
2005 | 3079 | |
---|
2006 | | -#ifdef CONFIG_CIFS_ACL |
---|
| 3080 | +int |
---|
| 3081 | +smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, |
---|
| 3082 | + struct cifs_sb_info *cifs_sb, const char *full_path, |
---|
| 3083 | + __u32 *tag) |
---|
| 3084 | +{ |
---|
| 3085 | + int rc; |
---|
| 3086 | + __le16 *utf16_path = NULL; |
---|
| 3087 | + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; |
---|
| 3088 | + struct cifs_open_parms oparms; |
---|
| 3089 | + struct cifs_fid fid; |
---|
| 3090 | + struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses); |
---|
| 3091 | + int flags = CIFS_CP_CREATE_CLOSE_OP; |
---|
| 3092 | + struct smb_rqst rqst[3]; |
---|
| 3093 | + int resp_buftype[3]; |
---|
| 3094 | + struct kvec rsp_iov[3]; |
---|
| 3095 | + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; |
---|
| 3096 | + struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; |
---|
| 3097 | + struct kvec close_iov[1]; |
---|
| 3098 | + struct smb2_ioctl_rsp *ioctl_rsp; |
---|
| 3099 | + struct reparse_data_buffer *reparse_buf; |
---|
| 3100 | + u32 plen; |
---|
| 3101 | + |
---|
| 3102 | + cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
---|
| 3103 | + |
---|
| 3104 | + if (smb3_encryption_required(tcon)) |
---|
| 3105 | + flags |= CIFS_TRANSFORM_REQ; |
---|
| 3106 | + |
---|
| 3107 | + memset(rqst, 0, sizeof(rqst)); |
---|
| 3108 | + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
---|
| 3109 | + memset(rsp_iov, 0, sizeof(rsp_iov)); |
---|
| 3110 | + |
---|
| 3111 | + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); |
---|
| 3112 | + if (!utf16_path) |
---|
| 3113 | + return -ENOMEM; |
---|
| 3114 | + |
---|
| 3115 | + /* |
---|
| 3116 | + * setup smb2open - TODO add optimization to call cifs_get_readable_path |
---|
| 3117 | + * to see if there is a handle already open that we can use |
---|
| 3118 | + */ |
---|
| 3119 | + memset(&open_iov, 0, sizeof(open_iov)); |
---|
| 3120 | + rqst[0].rq_iov = open_iov; |
---|
| 3121 | + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
---|
| 3122 | + |
---|
| 3123 | + memset(&oparms, 0, sizeof(oparms)); |
---|
| 3124 | + oparms.tcon = tcon; |
---|
| 3125 | + oparms.desired_access = FILE_READ_ATTRIBUTES; |
---|
| 3126 | + oparms.disposition = FILE_OPEN; |
---|
| 3127 | + oparms.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT); |
---|
| 3128 | + oparms.fid = &fid; |
---|
| 3129 | + oparms.reconnect = false; |
---|
| 3130 | + |
---|
| 3131 | + rc = SMB2_open_init(tcon, server, |
---|
| 3132 | + &rqst[0], &oplock, &oparms, utf16_path); |
---|
| 3133 | + if (rc) |
---|
| 3134 | + goto query_rp_exit; |
---|
| 3135 | + smb2_set_next_command(tcon, &rqst[0]); |
---|
| 3136 | + |
---|
| 3137 | + |
---|
| 3138 | + /* IOCTL */ |
---|
| 3139 | + memset(&io_iov, 0, sizeof(io_iov)); |
---|
| 3140 | + rqst[1].rq_iov = io_iov; |
---|
| 3141 | + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; |
---|
| 3142 | + |
---|
| 3143 | + rc = SMB2_ioctl_init(tcon, server, |
---|
| 3144 | + &rqst[1], COMPOUND_FID, |
---|
| 3145 | + COMPOUND_FID, FSCTL_GET_REPARSE_POINT, NULL, 0, |
---|
| 3146 | + CIFSMaxBufSize - |
---|
| 3147 | + MAX_SMB2_CREATE_RESPONSE_SIZE - |
---|
| 3148 | + MAX_SMB2_CLOSE_RESPONSE_SIZE); |
---|
| 3149 | + if (rc) |
---|
| 3150 | + goto query_rp_exit; |
---|
| 3151 | + |
---|
| 3152 | + smb2_set_next_command(tcon, &rqst[1]); |
---|
| 3153 | + smb2_set_related(&rqst[1]); |
---|
| 3154 | + |
---|
| 3155 | + |
---|
| 3156 | + /* Close */ |
---|
| 3157 | + memset(&close_iov, 0, sizeof(close_iov)); |
---|
| 3158 | + rqst[2].rq_iov = close_iov; |
---|
| 3159 | + rqst[2].rq_nvec = 1; |
---|
| 3160 | + |
---|
| 3161 | + rc = SMB2_close_init(tcon, server, |
---|
| 3162 | + &rqst[2], COMPOUND_FID, COMPOUND_FID, false); |
---|
| 3163 | + if (rc) |
---|
| 3164 | + goto query_rp_exit; |
---|
| 3165 | + |
---|
| 3166 | + smb2_set_related(&rqst[2]); |
---|
| 3167 | + |
---|
| 3168 | + rc = compound_send_recv(xid, tcon->ses, server, |
---|
| 3169 | + flags, 3, rqst, |
---|
| 3170 | + resp_buftype, rsp_iov); |
---|
| 3171 | + |
---|
| 3172 | + ioctl_rsp = rsp_iov[1].iov_base; |
---|
| 3173 | + |
---|
| 3174 | + /* |
---|
| 3175 | + * Open was successful and we got an ioctl response. |
---|
| 3176 | + */ |
---|
| 3177 | + if (rc == 0) { |
---|
| 3178 | + /* See MS-FSCC 2.3.23 */ |
---|
| 3179 | + |
---|
| 3180 | + reparse_buf = (struct reparse_data_buffer *) |
---|
| 3181 | + ((char *)ioctl_rsp + |
---|
| 3182 | + le32_to_cpu(ioctl_rsp->OutputOffset)); |
---|
| 3183 | + plen = le32_to_cpu(ioctl_rsp->OutputCount); |
---|
| 3184 | + |
---|
| 3185 | + if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > |
---|
| 3186 | + rsp_iov[1].iov_len) { |
---|
| 3187 | + cifs_tcon_dbg(FYI, "srv returned invalid ioctl len: %d\n", |
---|
| 3188 | + plen); |
---|
| 3189 | + rc = -EIO; |
---|
| 3190 | + goto query_rp_exit; |
---|
| 3191 | + } |
---|
| 3192 | + *tag = le32_to_cpu(reparse_buf->ReparseTag); |
---|
| 3193 | + } |
---|
| 3194 | + |
---|
| 3195 | + query_rp_exit: |
---|
| 3196 | + kfree(utf16_path); |
---|
| 3197 | + SMB2_open_free(&rqst[0]); |
---|
| 3198 | + SMB2_ioctl_free(&rqst[1]); |
---|
| 3199 | + SMB2_close_free(&rqst[2]); |
---|
| 3200 | + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); |
---|
| 3201 | + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); |
---|
| 3202 | + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); |
---|
| 3203 | + return rc; |
---|
| 3204 | +} |
---|
| 3205 | + |
---|
2007 | 3206 | static struct cifs_ntsd * |
---|
2008 | 3207 | get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb, |
---|
2009 | 3208 | const struct cifs_fid *cifsfid, u32 *pacllen) |
---|
.. | .. |
---|
2053 | 3252 | tcon = tlink_tcon(tlink); |
---|
2054 | 3253 | xid = get_xid(); |
---|
2055 | 3254 | |
---|
2056 | | - if (backup_cred(cifs_sb)) |
---|
2057 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
2058 | | - else |
---|
2059 | | - oparms.create_options = 0; |
---|
2060 | | - |
---|
2061 | 3255 | utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); |
---|
2062 | 3256 | if (!utf16_path) { |
---|
2063 | 3257 | rc = -ENOMEM; |
---|
.. | .. |
---|
2068 | 3262 | oparms.tcon = tcon; |
---|
2069 | 3263 | oparms.desired_access = READ_CONTROL; |
---|
2070 | 3264 | oparms.disposition = FILE_OPEN; |
---|
| 3265 | + /* |
---|
| 3266 | + * When querying an ACL, even if the file is a symlink we want to open |
---|
| 3267 | + * the source not the target, and so the protocol requires that the |
---|
| 3268 | + * client specify this flag when opening a reparse point |
---|
| 3269 | + */ |
---|
| 3270 | + oparms.create_options = cifs_create_options(cifs_sb, 0) | OPEN_REPARSE_POINT; |
---|
2071 | 3271 | oparms.fid = &fid; |
---|
2072 | 3272 | oparms.reconnect = false; |
---|
2073 | 3273 | |
---|
2074 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
| 3274 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL, |
---|
| 3275 | + NULL); |
---|
2075 | 3276 | kfree(utf16_path); |
---|
2076 | 3277 | if (!rc) { |
---|
2077 | 3278 | rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid, |
---|
.. | .. |
---|
2088 | 3289 | return pntsd; |
---|
2089 | 3290 | } |
---|
2090 | 3291 | |
---|
2091 | | -#ifdef CONFIG_CIFS_ACL |
---|
2092 | 3292 | static int |
---|
2093 | 3293 | set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, |
---|
2094 | 3294 | struct inode *inode, const char *path, int aclflag) |
---|
.. | .. |
---|
2110 | 3310 | tcon = tlink_tcon(tlink); |
---|
2111 | 3311 | xid = get_xid(); |
---|
2112 | 3312 | |
---|
2113 | | - if (backup_cred(cifs_sb)) |
---|
2114 | | - oparms.create_options = CREATE_OPEN_BACKUP_INTENT; |
---|
2115 | | - else |
---|
2116 | | - oparms.create_options = 0; |
---|
2117 | | - |
---|
2118 | 3313 | if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) |
---|
2119 | 3314 | access_flags = WRITE_OWNER; |
---|
2120 | 3315 | else |
---|
.. | .. |
---|
2129 | 3324 | |
---|
2130 | 3325 | oparms.tcon = tcon; |
---|
2131 | 3326 | oparms.desired_access = access_flags; |
---|
| 3327 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
---|
2132 | 3328 | oparms.disposition = FILE_OPEN; |
---|
2133 | 3329 | oparms.path = path; |
---|
2134 | 3330 | oparms.fid = &fid; |
---|
2135 | 3331 | oparms.reconnect = false; |
---|
2136 | 3332 | |
---|
2137 | | - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); |
---|
| 3333 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, |
---|
| 3334 | + NULL, NULL); |
---|
2138 | 3335 | kfree(utf16_path); |
---|
2139 | 3336 | if (!rc) { |
---|
2140 | 3337 | rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid, |
---|
.. | .. |
---|
2146 | 3343 | free_xid(xid); |
---|
2147 | 3344 | return rc; |
---|
2148 | 3345 | } |
---|
2149 | | -#endif /* CIFS_ACL */ |
---|
2150 | 3346 | |
---|
2151 | 3347 | /* Retrieve an ACL from the server */ |
---|
2152 | 3348 | static struct cifs_ntsd * |
---|
.. | .. |
---|
2166 | 3362 | cifsFileInfo_put(open_file); |
---|
2167 | 3363 | return pntsd; |
---|
2168 | 3364 | } |
---|
2169 | | -#endif |
---|
2170 | 3365 | |
---|
2171 | 3366 | static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, |
---|
2172 | 3367 | loff_t offset, loff_t len, bool keep_size) |
---|
2173 | 3368 | { |
---|
| 3369 | + struct cifs_ses *ses = tcon->ses; |
---|
2174 | 3370 | struct inode *inode; |
---|
2175 | 3371 | struct cifsInodeInfo *cifsi; |
---|
2176 | 3372 | struct cifsFileInfo *cfile = file->private_data; |
---|
2177 | 3373 | struct file_zero_data_information fsctl_buf; |
---|
2178 | 3374 | long rc; |
---|
2179 | 3375 | unsigned int xid; |
---|
| 3376 | + __le64 eof; |
---|
2180 | 3377 | |
---|
2181 | 3378 | xid = get_xid(); |
---|
2182 | 3379 | |
---|
2183 | 3380 | inode = d_inode(cfile->dentry); |
---|
2184 | 3381 | cifsi = CIFS_I(inode); |
---|
| 3382 | + |
---|
| 3383 | + trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3384 | + ses->Suid, offset, len); |
---|
2185 | 3385 | |
---|
2186 | 3386 | /* |
---|
2187 | 3387 | * We zero the range through ioctl, so we need remove the page caches |
---|
.. | .. |
---|
2193 | 3393 | if (!CIFS_CACHE_READ(cifsi)) |
---|
2194 | 3394 | if (keep_size == false) { |
---|
2195 | 3395 | rc = -EOPNOTSUPP; |
---|
| 3396 | + trace_smb3_zero_err(xid, cfile->fid.persistent_fid, |
---|
| 3397 | + tcon->tid, ses->Suid, offset, len, rc); |
---|
2196 | 3398 | free_xid(xid); |
---|
2197 | 3399 | return rc; |
---|
2198 | 3400 | } |
---|
2199 | 3401 | |
---|
2200 | | - /* |
---|
2201 | | - * Must check if file sparse since fallocate -z (zero range) assumes |
---|
2202 | | - * non-sparse allocation |
---|
2203 | | - */ |
---|
2204 | | - if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { |
---|
2205 | | - rc = -EOPNOTSUPP; |
---|
2206 | | - free_xid(xid); |
---|
2207 | | - return rc; |
---|
2208 | | - } |
---|
2209 | | - |
---|
2210 | | - /* |
---|
2211 | | - * need to make sure we are not asked to extend the file since the SMB3 |
---|
2212 | | - * fsctl does not change the file size. In the future we could change |
---|
2213 | | - * this to zero the first part of the range then set the file size |
---|
2214 | | - * which for a non sparse file would zero the newly extended range |
---|
2215 | | - */ |
---|
2216 | | - if (keep_size == false) |
---|
2217 | | - if (i_size_read(inode) < offset + len) { |
---|
2218 | | - rc = -EOPNOTSUPP; |
---|
2219 | | - free_xid(xid); |
---|
2220 | | - return rc; |
---|
2221 | | - } |
---|
2222 | | - |
---|
2223 | | - cifs_dbg(FYI, "offset %lld len %lld", offset, len); |
---|
| 3402 | + cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len); |
---|
2224 | 3403 | |
---|
2225 | 3404 | fsctl_buf.FileOffset = cpu_to_le64(offset); |
---|
2226 | 3405 | fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); |
---|
2227 | 3406 | |
---|
2228 | 3407 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
2229 | 3408 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, |
---|
2230 | | - true /* is_fctl */, (char *)&fsctl_buf, |
---|
2231 | | - sizeof(struct file_zero_data_information), NULL, NULL); |
---|
| 3409 | + (char *)&fsctl_buf, |
---|
| 3410 | + sizeof(struct file_zero_data_information), |
---|
| 3411 | + 0, NULL, NULL); |
---|
| 3412 | + if (rc) |
---|
| 3413 | + goto zero_range_exit; |
---|
| 3414 | + |
---|
| 3415 | + /* |
---|
| 3416 | + * do we also need to change the size of the file? |
---|
| 3417 | + */ |
---|
| 3418 | + if (keep_size == false && i_size_read(inode) < offset + len) { |
---|
| 3419 | + eof = cpu_to_le64(offset + len); |
---|
| 3420 | + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, |
---|
| 3421 | + cfile->fid.volatile_fid, cfile->pid, &eof); |
---|
| 3422 | + } |
---|
| 3423 | + |
---|
| 3424 | + zero_range_exit: |
---|
2232 | 3425 | free_xid(xid); |
---|
| 3426 | + if (rc) |
---|
| 3427 | + trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3428 | + ses->Suid, offset, len, rc); |
---|
| 3429 | + else |
---|
| 3430 | + trace_smb3_zero_done(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3431 | + ses->Suid, offset, len); |
---|
2233 | 3432 | return rc; |
---|
2234 | 3433 | } |
---|
2235 | 3434 | |
---|
2236 | 3435 | static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, |
---|
2237 | 3436 | loff_t offset, loff_t len) |
---|
2238 | 3437 | { |
---|
2239 | | - struct inode *inode; |
---|
2240 | | - struct cifsInodeInfo *cifsi; |
---|
| 3438 | + struct inode *inode = file_inode(file); |
---|
2241 | 3439 | struct cifsFileInfo *cfile = file->private_data; |
---|
2242 | 3440 | struct file_zero_data_information fsctl_buf; |
---|
2243 | 3441 | long rc; |
---|
.. | .. |
---|
2246 | 3444 | |
---|
2247 | 3445 | xid = get_xid(); |
---|
2248 | 3446 | |
---|
2249 | | - inode = d_inode(cfile->dentry); |
---|
2250 | | - cifsi = CIFS_I(inode); |
---|
2251 | | - |
---|
| 3447 | + inode_lock(inode); |
---|
2252 | 3448 | /* Need to make file sparse, if not already, before freeing range. */ |
---|
2253 | 3449 | /* Consider adding equivalent for compressed since it could also work */ |
---|
2254 | 3450 | if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) { |
---|
2255 | 3451 | rc = -EOPNOTSUPP; |
---|
2256 | | - free_xid(xid); |
---|
2257 | | - return rc; |
---|
| 3452 | + goto out; |
---|
2258 | 3453 | } |
---|
2259 | 3454 | |
---|
2260 | 3455 | /* |
---|
.. | .. |
---|
2263 | 3458 | */ |
---|
2264 | 3459 | truncate_pagecache_range(inode, offset, offset + len - 1); |
---|
2265 | 3460 | |
---|
2266 | | - cifs_dbg(FYI, "offset %lld len %lld", offset, len); |
---|
| 3461 | + cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len); |
---|
2267 | 3462 | |
---|
2268 | 3463 | fsctl_buf.FileOffset = cpu_to_le64(offset); |
---|
2269 | 3464 | fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); |
---|
2270 | 3465 | |
---|
2271 | 3466 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
2272 | 3467 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, |
---|
2273 | | - true /* is_fctl */, (char *)&fsctl_buf, |
---|
2274 | | - sizeof(struct file_zero_data_information), NULL, NULL); |
---|
| 3468 | + (char *)&fsctl_buf, |
---|
| 3469 | + sizeof(struct file_zero_data_information), |
---|
| 3470 | + CIFSMaxBufSize, NULL, NULL); |
---|
| 3471 | +out: |
---|
| 3472 | + inode_unlock(inode); |
---|
2275 | 3473 | free_xid(xid); |
---|
2276 | 3474 | return rc; |
---|
2277 | 3475 | } |
---|
| 3476 | + |
---|
| 3477 | +static int smb3_simple_fallocate_write_range(unsigned int xid, |
---|
| 3478 | + struct cifs_tcon *tcon, |
---|
| 3479 | + struct cifsFileInfo *cfile, |
---|
| 3480 | + loff_t off, loff_t len, |
---|
| 3481 | + char *buf) |
---|
| 3482 | +{ |
---|
| 3483 | + struct cifs_io_parms io_parms = {0}; |
---|
| 3484 | + int nbytes; |
---|
| 3485 | + int rc = 0; |
---|
| 3486 | + struct kvec iov[2]; |
---|
| 3487 | + |
---|
| 3488 | + io_parms.netfid = cfile->fid.netfid; |
---|
| 3489 | + io_parms.pid = current->tgid; |
---|
| 3490 | + io_parms.tcon = tcon; |
---|
| 3491 | + io_parms.persistent_fid = cfile->fid.persistent_fid; |
---|
| 3492 | + io_parms.volatile_fid = cfile->fid.volatile_fid; |
---|
| 3493 | + |
---|
| 3494 | + while (len) { |
---|
| 3495 | + io_parms.offset = off; |
---|
| 3496 | + io_parms.length = len; |
---|
| 3497 | + if (io_parms.length > SMB2_MAX_BUFFER_SIZE) |
---|
| 3498 | + io_parms.length = SMB2_MAX_BUFFER_SIZE; |
---|
| 3499 | + /* iov[0] is reserved for smb header */ |
---|
| 3500 | + iov[1].iov_base = buf; |
---|
| 3501 | + iov[1].iov_len = io_parms.length; |
---|
| 3502 | + rc = SMB2_write(xid, &io_parms, &nbytes, iov, 1); |
---|
| 3503 | + if (rc) |
---|
| 3504 | + break; |
---|
| 3505 | + if (nbytes > len) |
---|
| 3506 | + return -EINVAL; |
---|
| 3507 | + buf += nbytes; |
---|
| 3508 | + off += nbytes; |
---|
| 3509 | + len -= nbytes; |
---|
| 3510 | + } |
---|
| 3511 | + return rc; |
---|
| 3512 | +} |
---|
| 3513 | + |
---|
| 3514 | +static int smb3_simple_fallocate_range(unsigned int xid, |
---|
| 3515 | + struct cifs_tcon *tcon, |
---|
| 3516 | + struct cifsFileInfo *cfile, |
---|
| 3517 | + loff_t off, loff_t len) |
---|
| 3518 | +{ |
---|
| 3519 | + struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; |
---|
| 3520 | + u32 out_data_len; |
---|
| 3521 | + char *buf = NULL; |
---|
| 3522 | + loff_t l; |
---|
| 3523 | + int rc; |
---|
| 3524 | + |
---|
| 3525 | + in_data.file_offset = cpu_to_le64(off); |
---|
| 3526 | + in_data.length = cpu_to_le64(len); |
---|
| 3527 | + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
| 3528 | + cfile->fid.volatile_fid, |
---|
| 3529 | + FSCTL_QUERY_ALLOCATED_RANGES, |
---|
| 3530 | + (char *)&in_data, sizeof(in_data), |
---|
| 3531 | + 1024 * sizeof(struct file_allocated_range_buffer), |
---|
| 3532 | + (char **)&out_data, &out_data_len); |
---|
| 3533 | + if (rc) |
---|
| 3534 | + goto out; |
---|
| 3535 | + |
---|
| 3536 | + buf = kzalloc(1024 * 1024, GFP_KERNEL); |
---|
| 3537 | + if (buf == NULL) { |
---|
| 3538 | + rc = -ENOMEM; |
---|
| 3539 | + goto out; |
---|
| 3540 | + } |
---|
| 3541 | + |
---|
| 3542 | + tmp_data = out_data; |
---|
| 3543 | + while (len) { |
---|
| 3544 | + /* |
---|
| 3545 | + * The rest of the region is unmapped so write it all. |
---|
| 3546 | + */ |
---|
| 3547 | + if (out_data_len == 0) { |
---|
| 3548 | + rc = smb3_simple_fallocate_write_range(xid, tcon, |
---|
| 3549 | + cfile, off, len, buf); |
---|
| 3550 | + goto out; |
---|
| 3551 | + } |
---|
| 3552 | + |
---|
| 3553 | + if (out_data_len < sizeof(struct file_allocated_range_buffer)) { |
---|
| 3554 | + rc = -EINVAL; |
---|
| 3555 | + goto out; |
---|
| 3556 | + } |
---|
| 3557 | + |
---|
| 3558 | + if (off < le64_to_cpu(tmp_data->file_offset)) { |
---|
| 3559 | + /* |
---|
| 3560 | + * We are at a hole. Write until the end of the region |
---|
| 3561 | + * or until the next allocated data, |
---|
| 3562 | + * whichever comes next. |
---|
| 3563 | + */ |
---|
| 3564 | + l = le64_to_cpu(tmp_data->file_offset) - off; |
---|
| 3565 | + if (len < l) |
---|
| 3566 | + l = len; |
---|
| 3567 | + rc = smb3_simple_fallocate_write_range(xid, tcon, |
---|
| 3568 | + cfile, off, l, buf); |
---|
| 3569 | + if (rc) |
---|
| 3570 | + goto out; |
---|
| 3571 | + off = off + l; |
---|
| 3572 | + len = len - l; |
---|
| 3573 | + if (len == 0) |
---|
| 3574 | + goto out; |
---|
| 3575 | + } |
---|
| 3576 | + /* |
---|
| 3577 | + * We are at a section of allocated data, just skip forward |
---|
| 3578 | + * until the end of the data or the end of the region |
---|
| 3579 | + * we are supposed to fallocate, whichever comes first. |
---|
| 3580 | + */ |
---|
| 3581 | + l = le64_to_cpu(tmp_data->length); |
---|
| 3582 | + if (len < l) |
---|
| 3583 | + l = len; |
---|
| 3584 | + off += l; |
---|
| 3585 | + len -= l; |
---|
| 3586 | + |
---|
| 3587 | + tmp_data = &tmp_data[1]; |
---|
| 3588 | + out_data_len -= sizeof(struct file_allocated_range_buffer); |
---|
| 3589 | + } |
---|
| 3590 | + |
---|
| 3591 | + out: |
---|
| 3592 | + kfree(out_data); |
---|
| 3593 | + kfree(buf); |
---|
| 3594 | + return rc; |
---|
| 3595 | +} |
---|
| 3596 | + |
---|
2278 | 3597 | |
---|
2279 | 3598 | static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, |
---|
2280 | 3599 | loff_t off, loff_t len, bool keep_size) |
---|
.. | .. |
---|
2284 | 3603 | struct cifsFileInfo *cfile = file->private_data; |
---|
2285 | 3604 | long rc = -EOPNOTSUPP; |
---|
2286 | 3605 | unsigned int xid; |
---|
| 3606 | + __le64 eof; |
---|
2287 | 3607 | |
---|
2288 | 3608 | xid = get_xid(); |
---|
2289 | 3609 | |
---|
2290 | 3610 | inode = d_inode(cfile->dentry); |
---|
2291 | 3611 | cifsi = CIFS_I(inode); |
---|
2292 | 3612 | |
---|
| 3613 | + trace_smb3_falloc_enter(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3614 | + tcon->ses->Suid, off, len); |
---|
2293 | 3615 | /* if file not oplocked can't be sure whether asking to extend size */ |
---|
2294 | 3616 | if (!CIFS_CACHE_READ(cifsi)) |
---|
2295 | 3617 | if (keep_size == false) { |
---|
| 3618 | + trace_smb3_falloc_err(xid, cfile->fid.persistent_fid, |
---|
| 3619 | + tcon->tid, tcon->ses->Suid, off, len, rc); |
---|
2296 | 3620 | free_xid(xid); |
---|
2297 | 3621 | return rc; |
---|
2298 | 3622 | } |
---|
2299 | 3623 | |
---|
2300 | 3624 | /* |
---|
| 3625 | + * Extending the file |
---|
| 3626 | + */ |
---|
| 3627 | + if ((keep_size == false) && i_size_read(inode) < off + len) { |
---|
| 3628 | + rc = inode_newsize_ok(inode, off + len); |
---|
| 3629 | + if (rc) |
---|
| 3630 | + goto out; |
---|
| 3631 | + |
---|
| 3632 | + if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) |
---|
| 3633 | + smb2_set_sparse(xid, tcon, cfile, inode, false); |
---|
| 3634 | + |
---|
| 3635 | + eof = cpu_to_le64(off + len); |
---|
| 3636 | + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, |
---|
| 3637 | + cfile->fid.volatile_fid, cfile->pid, &eof); |
---|
| 3638 | + if (rc == 0) { |
---|
| 3639 | + cifsi->server_eof = off + len; |
---|
| 3640 | + cifs_setsize(inode, off + len); |
---|
| 3641 | + cifs_truncate_page(inode->i_mapping, inode->i_size); |
---|
| 3642 | + truncate_setsize(inode, off + len); |
---|
| 3643 | + } |
---|
| 3644 | + goto out; |
---|
| 3645 | + } |
---|
| 3646 | + |
---|
| 3647 | + /* |
---|
2301 | 3648 | * Files are non-sparse by default so falloc may be a no-op |
---|
2302 | | - * Must check if file sparse. If not sparse, and not extending |
---|
2303 | | - * then no need to do anything since file already allocated |
---|
| 3649 | + * Must check if file sparse. If not sparse, and since we are not |
---|
| 3650 | + * extending then no need to do anything since file already allocated |
---|
2304 | 3651 | */ |
---|
2305 | 3652 | if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) { |
---|
2306 | | - if (keep_size == true) |
---|
| 3653 | + rc = 0; |
---|
| 3654 | + goto out; |
---|
| 3655 | + } |
---|
| 3656 | + |
---|
| 3657 | + if (keep_size == true) { |
---|
| 3658 | + /* |
---|
| 3659 | + * We can not preallocate pages beyond the end of the file |
---|
| 3660 | + * in SMB2 |
---|
| 3661 | + */ |
---|
| 3662 | + if (off >= i_size_read(inode)) { |
---|
2307 | 3663 | rc = 0; |
---|
2308 | | - /* check if extending file */ |
---|
2309 | | - else if (i_size_read(inode) >= off + len) |
---|
2310 | | - /* not extending file and already not sparse */ |
---|
2311 | | - rc = 0; |
---|
2312 | | - /* BB: in future add else clause to extend file */ |
---|
2313 | | - else |
---|
2314 | | - rc = -EOPNOTSUPP; |
---|
2315 | | - free_xid(xid); |
---|
2316 | | - return rc; |
---|
| 3664 | + goto out; |
---|
| 3665 | + } |
---|
| 3666 | + /* |
---|
| 3667 | + * For fallocates that are partially beyond the end of file, |
---|
| 3668 | + * clamp len so we only fallocate up to the end of file. |
---|
| 3669 | + */ |
---|
| 3670 | + if (off + len > i_size_read(inode)) { |
---|
| 3671 | + len = i_size_read(inode) - off; |
---|
| 3672 | + } |
---|
2317 | 3673 | } |
---|
2318 | 3674 | |
---|
2319 | 3675 | if ((keep_size == true) || (i_size_read(inode) >= off + len)) { |
---|
| 3676 | + /* |
---|
| 3677 | + * At this point, we are trying to fallocate an internal |
---|
| 3678 | + * regions of a sparse file. Since smb2 does not have a |
---|
| 3679 | + * fallocate command we have two otions on how to emulate this. |
---|
| 3680 | + * We can either turn the entire file to become non-sparse |
---|
| 3681 | + * which we only do if the fallocate is for virtually |
---|
| 3682 | + * the whole file, or we can overwrite the region with zeroes |
---|
| 3683 | + * using SMB2_write, which could be prohibitevly expensive |
---|
| 3684 | + * if len is large. |
---|
| 3685 | + */ |
---|
| 3686 | + /* |
---|
| 3687 | + * We are only trying to fallocate a small region so |
---|
| 3688 | + * just write it with zero. |
---|
| 3689 | + */ |
---|
| 3690 | + if (len <= 1024 * 1024) { |
---|
| 3691 | + rc = smb3_simple_fallocate_range(xid, tcon, cfile, |
---|
| 3692 | + off, len); |
---|
| 3693 | + goto out; |
---|
| 3694 | + } |
---|
| 3695 | + |
---|
2320 | 3696 | /* |
---|
2321 | 3697 | * Check if falloc starts within first few pages of file |
---|
2322 | 3698 | * and ends within a few pages of the end of file to |
---|
.. | .. |
---|
2327 | 3703 | */ |
---|
2328 | 3704 | if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) { |
---|
2329 | 3705 | rc = -EOPNOTSUPP; |
---|
2330 | | - free_xid(xid); |
---|
2331 | | - return rc; |
---|
| 3706 | + goto out; |
---|
2332 | 3707 | } |
---|
2333 | | - |
---|
2334 | | - rc = smb2_set_sparse(xid, tcon, cfile, inode, false); |
---|
2335 | 3708 | } |
---|
2336 | | - /* BB: else ... in future add code to extend file and set sparse */ |
---|
2337 | 3709 | |
---|
| 3710 | + smb2_set_sparse(xid, tcon, cfile, inode, false); |
---|
| 3711 | + rc = 0; |
---|
| 3712 | + |
---|
| 3713 | +out: |
---|
| 3714 | + if (rc) |
---|
| 3715 | + trace_smb3_falloc_err(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3716 | + tcon->ses->Suid, off, len, rc); |
---|
| 3717 | + else |
---|
| 3718 | + trace_smb3_falloc_done(xid, cfile->fid.persistent_fid, tcon->tid, |
---|
| 3719 | + tcon->ses->Suid, off, len); |
---|
2338 | 3720 | |
---|
2339 | 3721 | free_xid(xid); |
---|
2340 | 3722 | return rc; |
---|
2341 | 3723 | } |
---|
2342 | 3724 | |
---|
| 3725 | +static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence) |
---|
| 3726 | +{ |
---|
| 3727 | + struct cifsFileInfo *wrcfile, *cfile = file->private_data; |
---|
| 3728 | + struct cifsInodeInfo *cifsi; |
---|
| 3729 | + struct inode *inode; |
---|
| 3730 | + int rc = 0; |
---|
| 3731 | + struct file_allocated_range_buffer in_data, *out_data = NULL; |
---|
| 3732 | + u32 out_data_len; |
---|
| 3733 | + unsigned int xid; |
---|
| 3734 | + |
---|
| 3735 | + if (whence != SEEK_HOLE && whence != SEEK_DATA) |
---|
| 3736 | + return generic_file_llseek(file, offset, whence); |
---|
| 3737 | + |
---|
| 3738 | + inode = d_inode(cfile->dentry); |
---|
| 3739 | + cifsi = CIFS_I(inode); |
---|
| 3740 | + |
---|
| 3741 | + if (offset < 0 || offset >= i_size_read(inode)) |
---|
| 3742 | + return -ENXIO; |
---|
| 3743 | + |
---|
| 3744 | + xid = get_xid(); |
---|
| 3745 | + /* |
---|
| 3746 | + * We need to be sure that all dirty pages are written as they |
---|
| 3747 | + * might fill holes on the server. |
---|
| 3748 | + * Note that we also MUST flush any written pages since at least |
---|
| 3749 | + * some servers (Windows2016) will not reflect recent writes in |
---|
| 3750 | + * QUERY_ALLOCATED_RANGES until SMB2_flush is called. |
---|
| 3751 | + */ |
---|
| 3752 | + wrcfile = find_writable_file(cifsi, FIND_WR_ANY); |
---|
| 3753 | + if (wrcfile) { |
---|
| 3754 | + filemap_write_and_wait(inode->i_mapping); |
---|
| 3755 | + smb2_flush_file(xid, tcon, &wrcfile->fid); |
---|
| 3756 | + cifsFileInfo_put(wrcfile); |
---|
| 3757 | + } |
---|
| 3758 | + |
---|
| 3759 | + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { |
---|
| 3760 | + if (whence == SEEK_HOLE) |
---|
| 3761 | + offset = i_size_read(inode); |
---|
| 3762 | + goto lseek_exit; |
---|
| 3763 | + } |
---|
| 3764 | + |
---|
| 3765 | + in_data.file_offset = cpu_to_le64(offset); |
---|
| 3766 | + in_data.length = cpu_to_le64(i_size_read(inode)); |
---|
| 3767 | + |
---|
| 3768 | + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
| 3769 | + cfile->fid.volatile_fid, |
---|
| 3770 | + FSCTL_QUERY_ALLOCATED_RANGES, |
---|
| 3771 | + (char *)&in_data, sizeof(in_data), |
---|
| 3772 | + sizeof(struct file_allocated_range_buffer), |
---|
| 3773 | + (char **)&out_data, &out_data_len); |
---|
| 3774 | + if (rc == -E2BIG) |
---|
| 3775 | + rc = 0; |
---|
| 3776 | + if (rc) |
---|
| 3777 | + goto lseek_exit; |
---|
| 3778 | + |
---|
| 3779 | + if (whence == SEEK_HOLE && out_data_len == 0) |
---|
| 3780 | + goto lseek_exit; |
---|
| 3781 | + |
---|
| 3782 | + if (whence == SEEK_DATA && out_data_len == 0) { |
---|
| 3783 | + rc = -ENXIO; |
---|
| 3784 | + goto lseek_exit; |
---|
| 3785 | + } |
---|
| 3786 | + |
---|
| 3787 | + if (out_data_len < sizeof(struct file_allocated_range_buffer)) { |
---|
| 3788 | + rc = -EINVAL; |
---|
| 3789 | + goto lseek_exit; |
---|
| 3790 | + } |
---|
| 3791 | + if (whence == SEEK_DATA) { |
---|
| 3792 | + offset = le64_to_cpu(out_data->file_offset); |
---|
| 3793 | + goto lseek_exit; |
---|
| 3794 | + } |
---|
| 3795 | + if (offset < le64_to_cpu(out_data->file_offset)) |
---|
| 3796 | + goto lseek_exit; |
---|
| 3797 | + |
---|
| 3798 | + offset = le64_to_cpu(out_data->file_offset) + le64_to_cpu(out_data->length); |
---|
| 3799 | + |
---|
| 3800 | + lseek_exit: |
---|
| 3801 | + free_xid(xid); |
---|
| 3802 | + kfree(out_data); |
---|
| 3803 | + if (!rc) |
---|
| 3804 | + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); |
---|
| 3805 | + else |
---|
| 3806 | + return rc; |
---|
| 3807 | +} |
---|
| 3808 | + |
---|
| 3809 | +static int smb3_fiemap(struct cifs_tcon *tcon, |
---|
| 3810 | + struct cifsFileInfo *cfile, |
---|
| 3811 | + struct fiemap_extent_info *fei, u64 start, u64 len) |
---|
| 3812 | +{ |
---|
| 3813 | + unsigned int xid; |
---|
| 3814 | + struct file_allocated_range_buffer in_data, *out_data; |
---|
| 3815 | + u32 out_data_len; |
---|
| 3816 | + int i, num, rc, flags, last_blob; |
---|
| 3817 | + u64 next; |
---|
| 3818 | + |
---|
| 3819 | + rc = fiemap_prep(d_inode(cfile->dentry), fei, start, &len, 0); |
---|
| 3820 | + if (rc) |
---|
| 3821 | + return rc; |
---|
| 3822 | + |
---|
| 3823 | + xid = get_xid(); |
---|
| 3824 | + again: |
---|
| 3825 | + in_data.file_offset = cpu_to_le64(start); |
---|
| 3826 | + in_data.length = cpu_to_le64(len); |
---|
| 3827 | + |
---|
| 3828 | + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
---|
| 3829 | + cfile->fid.volatile_fid, |
---|
| 3830 | + FSCTL_QUERY_ALLOCATED_RANGES, |
---|
| 3831 | + (char *)&in_data, sizeof(in_data), |
---|
| 3832 | + 1024 * sizeof(struct file_allocated_range_buffer), |
---|
| 3833 | + (char **)&out_data, &out_data_len); |
---|
| 3834 | + if (rc == -E2BIG) { |
---|
| 3835 | + last_blob = 0; |
---|
| 3836 | + rc = 0; |
---|
| 3837 | + } else |
---|
| 3838 | + last_blob = 1; |
---|
| 3839 | + if (rc) |
---|
| 3840 | + goto out; |
---|
| 3841 | + |
---|
| 3842 | + if (out_data_len && out_data_len < sizeof(struct file_allocated_range_buffer)) { |
---|
| 3843 | + rc = -EINVAL; |
---|
| 3844 | + goto out; |
---|
| 3845 | + } |
---|
| 3846 | + if (out_data_len % sizeof(struct file_allocated_range_buffer)) { |
---|
| 3847 | + rc = -EINVAL; |
---|
| 3848 | + goto out; |
---|
| 3849 | + } |
---|
| 3850 | + |
---|
| 3851 | + num = out_data_len / sizeof(struct file_allocated_range_buffer); |
---|
| 3852 | + for (i = 0; i < num; i++) { |
---|
| 3853 | + flags = 0; |
---|
| 3854 | + if (i == num - 1 && last_blob) |
---|
| 3855 | + flags |= FIEMAP_EXTENT_LAST; |
---|
| 3856 | + |
---|
| 3857 | + rc = fiemap_fill_next_extent(fei, |
---|
| 3858 | + le64_to_cpu(out_data[i].file_offset), |
---|
| 3859 | + le64_to_cpu(out_data[i].file_offset), |
---|
| 3860 | + le64_to_cpu(out_data[i].length), |
---|
| 3861 | + flags); |
---|
| 3862 | + if (rc < 0) |
---|
| 3863 | + goto out; |
---|
| 3864 | + if (rc == 1) { |
---|
| 3865 | + rc = 0; |
---|
| 3866 | + goto out; |
---|
| 3867 | + } |
---|
| 3868 | + } |
---|
| 3869 | + |
---|
| 3870 | + if (!last_blob) { |
---|
| 3871 | + next = le64_to_cpu(out_data[num - 1].file_offset) + |
---|
| 3872 | + le64_to_cpu(out_data[num - 1].length); |
---|
| 3873 | + len = len - (next - start); |
---|
| 3874 | + start = next; |
---|
| 3875 | + goto again; |
---|
| 3876 | + } |
---|
| 3877 | + |
---|
| 3878 | + out: |
---|
| 3879 | + free_xid(xid); |
---|
| 3880 | + kfree(out_data); |
---|
| 3881 | + return rc; |
---|
| 3882 | +} |
---|
2343 | 3883 | |
---|
2344 | 3884 | static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, |
---|
2345 | 3885 | loff_t off, loff_t len) |
---|
.. | .. |
---|
2489 | 4029 | } |
---|
2490 | 4030 | } |
---|
2491 | 4031 | |
---|
| 4032 | +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
---|
2492 | 4033 | static bool |
---|
2493 | 4034 | smb2_is_read_op(__u32 oplock) |
---|
2494 | 4035 | { |
---|
2495 | 4036 | return oplock == SMB2_OPLOCK_LEVEL_II; |
---|
2496 | 4037 | } |
---|
| 4038 | +#endif /* CIFS_ALLOW_INSECURE_LEGACY */ |
---|
2497 | 4039 | |
---|
2498 | 4040 | static bool |
---|
2499 | 4041 | smb21_is_read_op(__u32 oplock) |
---|
.. | .. |
---|
2606 | 4148 | |
---|
2607 | 4149 | static void |
---|
2608 | 4150 | fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len, |
---|
2609 | | - struct smb_rqst *old_rq) |
---|
| 4151 | + struct smb_rqst *old_rq, __le16 cipher_type) |
---|
2610 | 4152 | { |
---|
2611 | 4153 | struct smb2_sync_hdr *shdr = |
---|
2612 | 4154 | (struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base; |
---|
.. | .. |
---|
2615 | 4157 | tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; |
---|
2616 | 4158 | tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); |
---|
2617 | 4159 | tr_hdr->Flags = cpu_to_le16(0x01); |
---|
2618 | | - get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE); |
---|
| 4160 | + if ((cipher_type == SMB2_ENCRYPTION_AES128_GCM) || |
---|
| 4161 | + (cipher_type == SMB2_ENCRYPTION_AES256_GCM)) |
---|
| 4162 | + get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE); |
---|
| 4163 | + else |
---|
| 4164 | + get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE); |
---|
2619 | 4165 | memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); |
---|
2620 | 4166 | } |
---|
2621 | 4167 | |
---|
2622 | | -/* We can not use the normal sg_set_buf() as we will sometimes pass a |
---|
2623 | | - * stack object as buf. |
---|
2624 | | - */ |
---|
2625 | | -static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, |
---|
2626 | | - unsigned int buflen) |
---|
| 4168 | +static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst, |
---|
| 4169 | + int num_rqst, const u8 *sig, u8 **iv, |
---|
| 4170 | + struct aead_request **req, struct scatterlist **sgl, |
---|
| 4171 | + unsigned int *num_sgs) |
---|
2627 | 4172 | { |
---|
2628 | | - void *addr; |
---|
2629 | | - /* |
---|
2630 | | - * VMAP_STACK (at least) puts stack into the vmalloc address space |
---|
2631 | | - */ |
---|
2632 | | - if (is_vmalloc_addr(buf)) |
---|
2633 | | - addr = vmalloc_to_page(buf); |
---|
2634 | | - else |
---|
2635 | | - addr = virt_to_page(buf); |
---|
2636 | | - sg_set_page(sg, addr, buflen, offset_in_page(buf)); |
---|
2637 | | -} |
---|
| 4173 | + unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm); |
---|
| 4174 | + unsigned int iv_size = crypto_aead_ivsize(tfm); |
---|
| 4175 | + unsigned int len; |
---|
| 4176 | + u8 *p; |
---|
2638 | 4177 | |
---|
2639 | | -/* Assumes the first rqst has a transform header as the first iov. |
---|
2640 | | - * I.e. |
---|
2641 | | - * rqst[0].rq_iov[0] is transform header |
---|
2642 | | - * rqst[0].rq_iov[1+] data to be encrypted/decrypted |
---|
2643 | | - * rqst[1+].rq_iov[0+] data to be encrypted/decrypted |
---|
2644 | | - */ |
---|
2645 | | -static struct scatterlist * |
---|
2646 | | -init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) |
---|
2647 | | -{ |
---|
2648 | | - unsigned int sg_len; |
---|
2649 | | - struct scatterlist *sg; |
---|
2650 | | - unsigned int i; |
---|
2651 | | - unsigned int j; |
---|
2652 | | - unsigned int idx = 0; |
---|
2653 | | - int skip; |
---|
| 4178 | + *num_sgs = cifs_get_num_sgs(rqst, num_rqst, sig); |
---|
2654 | 4179 | |
---|
2655 | | - sg_len = 1; |
---|
2656 | | - for (i = 0; i < num_rqst; i++) |
---|
2657 | | - sg_len += rqst[i].rq_nvec + rqst[i].rq_npages; |
---|
| 4180 | + len = iv_size; |
---|
| 4181 | + len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); |
---|
| 4182 | + len = ALIGN(len, crypto_tfm_ctx_alignment()); |
---|
| 4183 | + len += req_size; |
---|
| 4184 | + len = ALIGN(len, __alignof__(struct scatterlist)); |
---|
| 4185 | + len += *num_sgs * sizeof(**sgl); |
---|
2658 | 4186 | |
---|
2659 | | - sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); |
---|
2660 | | - if (!sg) |
---|
| 4187 | + p = kmalloc(len, GFP_ATOMIC); |
---|
| 4188 | + if (!p) |
---|
2661 | 4189 | return NULL; |
---|
2662 | 4190 | |
---|
2663 | | - sg_init_table(sg, sg_len); |
---|
| 4191 | + *iv = (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1); |
---|
| 4192 | + *req = (struct aead_request *)PTR_ALIGN(*iv + iv_size, |
---|
| 4193 | + crypto_tfm_ctx_alignment()); |
---|
| 4194 | + *sgl = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size, |
---|
| 4195 | + __alignof__(struct scatterlist)); |
---|
| 4196 | + return p; |
---|
| 4197 | +} |
---|
| 4198 | + |
---|
| 4199 | +static void *smb2_get_aead_req(struct crypto_aead *tfm, const struct smb_rqst *rqst, |
---|
| 4200 | + int num_rqst, const u8 *sig, u8 **iv, |
---|
| 4201 | + struct aead_request **req, struct scatterlist **sgl) |
---|
| 4202 | +{ |
---|
| 4203 | + unsigned int off, len, skip; |
---|
| 4204 | + struct scatterlist *sg; |
---|
| 4205 | + unsigned int num_sgs; |
---|
| 4206 | + unsigned long addr; |
---|
| 4207 | + int i, j; |
---|
| 4208 | + void *p; |
---|
| 4209 | + |
---|
| 4210 | + p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, sgl, &num_sgs); |
---|
| 4211 | + if (!p) |
---|
| 4212 | + return NULL; |
---|
| 4213 | + |
---|
| 4214 | + sg_init_table(*sgl, num_sgs); |
---|
| 4215 | + sg = *sgl; |
---|
| 4216 | + |
---|
| 4217 | + /* Assumes the first rqst has a transform header as the first iov. |
---|
| 4218 | + * I.e. |
---|
| 4219 | + * rqst[0].rq_iov[0] is transform header |
---|
| 4220 | + * rqst[0].rq_iov[1+] data to be encrypted/decrypted |
---|
| 4221 | + * rqst[1+].rq_iov[0+] data to be encrypted/decrypted |
---|
| 4222 | + */ |
---|
2664 | 4223 | for (i = 0; i < num_rqst; i++) { |
---|
| 4224 | + /* |
---|
| 4225 | + * The first rqst has a transform header where the |
---|
| 4226 | + * first 20 bytes are not part of the encrypted blob. |
---|
| 4227 | + */ |
---|
2665 | 4228 | for (j = 0; j < rqst[i].rq_nvec; j++) { |
---|
2666 | | - /* |
---|
2667 | | - * The first rqst has a transform header where the |
---|
2668 | | - * first 20 bytes are not part of the encrypted blob |
---|
2669 | | - */ |
---|
| 4229 | + struct kvec *iov = &rqst[i].rq_iov[j]; |
---|
| 4230 | + |
---|
2670 | 4231 | skip = (i == 0) && (j == 0) ? 20 : 0; |
---|
2671 | | - smb2_sg_set_buf(&sg[idx++], |
---|
2672 | | - rqst[i].rq_iov[j].iov_base + skip, |
---|
2673 | | - rqst[i].rq_iov[j].iov_len - skip); |
---|
| 4232 | + addr = (unsigned long)iov->iov_base + skip; |
---|
| 4233 | + len = iov->iov_len - skip; |
---|
| 4234 | + sg = cifs_sg_set_buf(sg, (void *)addr, len); |
---|
2674 | 4235 | } |
---|
2675 | | - |
---|
2676 | 4236 | for (j = 0; j < rqst[i].rq_npages; j++) { |
---|
2677 | | - unsigned int len, offset; |
---|
2678 | | - |
---|
2679 | | - rqst_page_get_length(&rqst[i], j, &len, &offset); |
---|
2680 | | - sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset); |
---|
| 4237 | + rqst_page_get_length(&rqst[i], j, &len, &off); |
---|
| 4238 | + sg_set_page(sg++, rqst[i].rq_pages[j], len, off); |
---|
2681 | 4239 | } |
---|
2682 | 4240 | } |
---|
2683 | | - smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE); |
---|
2684 | | - return sg; |
---|
| 4241 | + cifs_sg_set_buf(sg, sig, SMB2_SIGNATURE_SIZE); |
---|
| 4242 | + |
---|
| 4243 | + return p; |
---|
2685 | 4244 | } |
---|
2686 | 4245 | |
---|
2687 | 4246 | static int |
---|
.. | .. |
---|
2691 | 4250 | u8 *ses_enc_key; |
---|
2692 | 4251 | |
---|
2693 | 4252 | spin_lock(&cifs_tcp_ses_lock); |
---|
2694 | | - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
---|
2695 | | - if (ses->Suid != ses_id) |
---|
2696 | | - continue; |
---|
2697 | | - ses_enc_key = enc ? ses->smb3encryptionkey : |
---|
2698 | | - ses->smb3decryptionkey; |
---|
2699 | | - memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE); |
---|
2700 | | - spin_unlock(&cifs_tcp_ses_lock); |
---|
2701 | | - return 0; |
---|
| 4253 | + list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
---|
| 4254 | + list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
---|
| 4255 | + if (ses->Suid == ses_id) { |
---|
| 4256 | + ses_enc_key = enc ? ses->smb3encryptionkey : |
---|
| 4257 | + ses->smb3decryptionkey; |
---|
| 4258 | + memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); |
---|
| 4259 | + spin_unlock(&cifs_tcp_ses_lock); |
---|
| 4260 | + return 0; |
---|
| 4261 | + } |
---|
| 4262 | + } |
---|
2702 | 4263 | } |
---|
2703 | 4264 | spin_unlock(&cifs_tcp_ses_lock); |
---|
2704 | 4265 | |
---|
.. | .. |
---|
2721 | 4282 | int rc = 0; |
---|
2722 | 4283 | struct scatterlist *sg; |
---|
2723 | 4284 | u8 sign[SMB2_SIGNATURE_SIZE] = {}; |
---|
2724 | | - u8 key[SMB3_SIGN_KEY_SIZE]; |
---|
| 4285 | + u8 key[SMB3_ENC_DEC_KEY_SIZE]; |
---|
2725 | 4286 | struct aead_request *req; |
---|
2726 | | - char *iv; |
---|
2727 | | - unsigned int iv_len; |
---|
| 4287 | + u8 *iv; |
---|
2728 | 4288 | DECLARE_CRYPTO_WAIT(wait); |
---|
2729 | 4289 | struct crypto_aead *tfm; |
---|
2730 | 4290 | unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); |
---|
| 4291 | + void *creq; |
---|
2731 | 4292 | |
---|
2732 | 4293 | rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key); |
---|
2733 | 4294 | if (rc) { |
---|
2734 | | - cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__, |
---|
| 4295 | + cifs_server_dbg(VFS, "%s: Could not get %scryption key\n", __func__, |
---|
2735 | 4296 | enc ? "en" : "de"); |
---|
2736 | 4297 | return rc; |
---|
2737 | 4298 | } |
---|
2738 | 4299 | |
---|
2739 | 4300 | rc = smb3_crypto_aead_allocate(server); |
---|
2740 | 4301 | if (rc) { |
---|
2741 | | - cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); |
---|
| 4302 | + cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); |
---|
2742 | 4303 | return rc; |
---|
2743 | 4304 | } |
---|
2744 | 4305 | |
---|
2745 | 4306 | tfm = enc ? server->secmech.ccmaesencrypt : |
---|
2746 | 4307 | server->secmech.ccmaesdecrypt; |
---|
2747 | | - rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE); |
---|
| 4308 | + |
---|
| 4309 | + if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || |
---|
| 4310 | + (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) |
---|
| 4311 | + rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); |
---|
| 4312 | + else |
---|
| 4313 | + rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); |
---|
| 4314 | + |
---|
2748 | 4315 | if (rc) { |
---|
2749 | | - cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); |
---|
| 4316 | + cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); |
---|
2750 | 4317 | return rc; |
---|
2751 | 4318 | } |
---|
2752 | 4319 | |
---|
2753 | 4320 | rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); |
---|
2754 | 4321 | if (rc) { |
---|
2755 | | - cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); |
---|
| 4322 | + cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); |
---|
2756 | 4323 | return rc; |
---|
2757 | 4324 | } |
---|
2758 | 4325 | |
---|
2759 | | - req = aead_request_alloc(tfm, GFP_KERNEL); |
---|
2760 | | - if (!req) { |
---|
2761 | | - cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__); |
---|
| 4326 | + creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg); |
---|
| 4327 | + if (unlikely(!creq)) |
---|
2762 | 4328 | return -ENOMEM; |
---|
2763 | | - } |
---|
2764 | 4329 | |
---|
2765 | 4330 | if (!enc) { |
---|
2766 | 4331 | memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); |
---|
2767 | 4332 | crypt_len += SMB2_SIGNATURE_SIZE; |
---|
2768 | 4333 | } |
---|
2769 | 4334 | |
---|
2770 | | - sg = init_sg(num_rqst, rqst, sign); |
---|
2771 | | - if (!sg) { |
---|
2772 | | - cifs_dbg(VFS, "%s: Failed to init sg", __func__); |
---|
2773 | | - rc = -ENOMEM; |
---|
2774 | | - goto free_req; |
---|
| 4335 | + if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || |
---|
| 4336 | + (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) |
---|
| 4337 | + memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); |
---|
| 4338 | + else { |
---|
| 4339 | + iv[0] = 3; |
---|
| 4340 | + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); |
---|
2775 | 4341 | } |
---|
2776 | 4342 | |
---|
2777 | | - iv_len = crypto_aead_ivsize(tfm); |
---|
2778 | | - iv = kzalloc(iv_len, GFP_KERNEL); |
---|
2779 | | - if (!iv) { |
---|
2780 | | - cifs_dbg(VFS, "%s: Failed to alloc IV", __func__); |
---|
2781 | | - rc = -ENOMEM; |
---|
2782 | | - goto free_sg; |
---|
2783 | | - } |
---|
2784 | | - iv[0] = 3; |
---|
2785 | | - memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE); |
---|
2786 | | - |
---|
| 4343 | + aead_request_set_tfm(req, tfm); |
---|
2787 | 4344 | aead_request_set_crypt(req, sg, sg, crypt_len, iv); |
---|
2788 | 4345 | aead_request_set_ad(req, assoc_data_len); |
---|
2789 | 4346 | |
---|
.. | .. |
---|
2796 | 4353 | if (!rc && enc) |
---|
2797 | 4354 | memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); |
---|
2798 | 4355 | |
---|
2799 | | - kfree(iv); |
---|
2800 | | -free_sg: |
---|
2801 | | - kfree(sg); |
---|
2802 | | -free_req: |
---|
2803 | | - kfree(req); |
---|
| 4356 | + kfree_sensitive(creq); |
---|
2804 | 4357 | return rc; |
---|
2805 | 4358 | } |
---|
2806 | 4359 | |
---|
.. | .. |
---|
2882 | 4435 | } |
---|
2883 | 4436 | |
---|
2884 | 4437 | /* fill the 1st iov with a transform header */ |
---|
2885 | | - fill_transform_hdr(tr_hdr, orig_len, old_rq); |
---|
| 4438 | + fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type); |
---|
2886 | 4439 | |
---|
2887 | 4440 | rc = crypt_message(server, num_rqst, new_rq, 1); |
---|
2888 | | - cifs_dbg(FYI, "encrypt message returned %d", rc); |
---|
| 4441 | + cifs_dbg(FYI, "Encrypt message returned %d\n", rc); |
---|
2889 | 4442 | if (rc) |
---|
2890 | 4443 | goto err_free; |
---|
2891 | 4444 | |
---|
.. | .. |
---|
2907 | 4460 | static int |
---|
2908 | 4461 | decrypt_raw_data(struct TCP_Server_Info *server, char *buf, |
---|
2909 | 4462 | unsigned int buf_data_size, struct page **pages, |
---|
2910 | | - unsigned int npages, unsigned int page_data_size) |
---|
| 4463 | + unsigned int npages, unsigned int page_data_size, |
---|
| 4464 | + bool is_offloaded) |
---|
2911 | 4465 | { |
---|
2912 | 4466 | struct kvec iov[2]; |
---|
2913 | 4467 | struct smb_rqst rqst = {NULL}; |
---|
.. | .. |
---|
2926 | 4480 | rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE; |
---|
2927 | 4481 | |
---|
2928 | 4482 | rc = crypt_message(server, 1, &rqst, 0); |
---|
2929 | | - cifs_dbg(FYI, "decrypt message returned %d\n", rc); |
---|
| 4483 | + cifs_dbg(FYI, "Decrypt message returned %d\n", rc); |
---|
2930 | 4484 | |
---|
2931 | 4485 | if (rc) |
---|
2932 | 4486 | return rc; |
---|
2933 | 4487 | |
---|
2934 | 4488 | memmove(buf, iov[1].iov_base, buf_data_size); |
---|
2935 | 4489 | |
---|
2936 | | - server->total_read = buf_data_size + page_data_size; |
---|
| 4490 | + if (!is_offloaded) |
---|
| 4491 | + server->total_read = buf_data_size + page_data_size; |
---|
2937 | 4492 | |
---|
2938 | 4493 | return rc; |
---|
2939 | 4494 | } |
---|
.. | .. |
---|
2998 | 4553 | static int |
---|
2999 | 4554 | handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, |
---|
3000 | 4555 | char *buf, unsigned int buf_len, struct page **pages, |
---|
3001 | | - unsigned int npages, unsigned int page_data_size) |
---|
| 4556 | + unsigned int npages, unsigned int page_data_size, |
---|
| 4557 | + bool is_offloaded) |
---|
3002 | 4558 | { |
---|
3003 | 4559 | unsigned int data_offset; |
---|
3004 | 4560 | unsigned int data_len; |
---|
.. | .. |
---|
3014 | 4570 | bool use_rdma_mr = false; |
---|
3015 | 4571 | |
---|
3016 | 4572 | if (shdr->Command != SMB2_READ) { |
---|
3017 | | - cifs_dbg(VFS, "only big read responses are supported\n"); |
---|
| 4573 | + cifs_server_dbg(VFS, "only big read responses are supported\n"); |
---|
3018 | 4574 | return -ENOTSUPP; |
---|
3019 | 4575 | } |
---|
3020 | 4576 | |
---|
3021 | 4577 | if (server->ops->is_session_expired && |
---|
3022 | 4578 | server->ops->is_session_expired(buf)) { |
---|
3023 | | - cifs_reconnect(server); |
---|
3024 | | - wake_up(&server->response_q); |
---|
| 4579 | + if (!is_offloaded) |
---|
| 4580 | + cifs_reconnect(server); |
---|
3025 | 4581 | return -1; |
---|
3026 | 4582 | } |
---|
3027 | 4583 | |
---|
3028 | 4584 | if (server->ops->is_status_pending && |
---|
3029 | | - server->ops->is_status_pending(buf, server, 0)) |
---|
| 4585 | + server->ops->is_status_pending(buf, server)) |
---|
3030 | 4586 | return -1; |
---|
3031 | 4587 | |
---|
3032 | 4588 | /* set up first two iov to get credits */ |
---|
.. | .. |
---|
3045 | 4601 | cifs_dbg(FYI, "%s: server returned error %d\n", |
---|
3046 | 4602 | __func__, rdata->result); |
---|
3047 | 4603 | /* normal error on read response */ |
---|
3048 | | - dequeue_mid(mid, false); |
---|
| 4604 | + if (is_offloaded) |
---|
| 4605 | + mid->mid_state = MID_RESPONSE_RECEIVED; |
---|
| 4606 | + else |
---|
| 4607 | + dequeue_mid(mid, false); |
---|
3049 | 4608 | return 0; |
---|
3050 | 4609 | } |
---|
3051 | 4610 | |
---|
.. | .. |
---|
3069 | 4628 | cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", |
---|
3070 | 4629 | __func__, data_offset); |
---|
3071 | 4630 | rdata->result = -EIO; |
---|
3072 | | - dequeue_mid(mid, rdata->result); |
---|
| 4631 | + if (is_offloaded) |
---|
| 4632 | + mid->mid_state = MID_RESPONSE_MALFORMED; |
---|
| 4633 | + else |
---|
| 4634 | + dequeue_mid(mid, rdata->result); |
---|
3073 | 4635 | return 0; |
---|
3074 | 4636 | } |
---|
3075 | 4637 | |
---|
.. | .. |
---|
3085 | 4647 | cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n", |
---|
3086 | 4648 | __func__, data_offset); |
---|
3087 | 4649 | rdata->result = -EIO; |
---|
3088 | | - dequeue_mid(mid, rdata->result); |
---|
| 4650 | + if (is_offloaded) |
---|
| 4651 | + mid->mid_state = MID_RESPONSE_MALFORMED; |
---|
| 4652 | + else |
---|
| 4653 | + dequeue_mid(mid, rdata->result); |
---|
3089 | 4654 | return 0; |
---|
3090 | 4655 | } |
---|
3091 | 4656 | |
---|
3092 | 4657 | if (data_len > page_data_size - pad_len) { |
---|
3093 | 4658 | /* data_len is corrupt -- discard frame */ |
---|
3094 | 4659 | rdata->result = -EIO; |
---|
3095 | | - dequeue_mid(mid, rdata->result); |
---|
| 4660 | + if (is_offloaded) |
---|
| 4661 | + mid->mid_state = MID_RESPONSE_MALFORMED; |
---|
| 4662 | + else |
---|
| 4663 | + dequeue_mid(mid, rdata->result); |
---|
3096 | 4664 | return 0; |
---|
3097 | 4665 | } |
---|
3098 | 4666 | |
---|
3099 | 4667 | rdata->result = init_read_bvec(pages, npages, page_data_size, |
---|
3100 | 4668 | cur_off, &bvec); |
---|
3101 | 4669 | if (rdata->result != 0) { |
---|
3102 | | - dequeue_mid(mid, rdata->result); |
---|
| 4670 | + if (is_offloaded) |
---|
| 4671 | + mid->mid_state = MID_RESPONSE_MALFORMED; |
---|
| 4672 | + else |
---|
| 4673 | + dequeue_mid(mid, rdata->result); |
---|
3103 | 4674 | return 0; |
---|
3104 | 4675 | } |
---|
3105 | 4676 | |
---|
3106 | | - iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len); |
---|
| 4677 | + iov_iter_bvec(&iter, WRITE, bvec, npages, data_len); |
---|
3107 | 4678 | } else if (buf_len >= data_offset + data_len) { |
---|
3108 | 4679 | /* read response payload is in buf */ |
---|
3109 | 4680 | WARN_ONCE(npages > 0, "read data can be either in buf or in pages"); |
---|
3110 | 4681 | iov.iov_base = buf + data_offset; |
---|
3111 | 4682 | iov.iov_len = data_len; |
---|
3112 | | - iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len); |
---|
| 4683 | + iov_iter_kvec(&iter, WRITE, &iov, 1, data_len); |
---|
3113 | 4684 | } else { |
---|
3114 | 4685 | /* read response payload cannot be in both buf and pages */ |
---|
3115 | 4686 | WARN_ONCE(1, "buf can not contain only a part of read data"); |
---|
3116 | 4687 | rdata->result = -EIO; |
---|
3117 | | - dequeue_mid(mid, rdata->result); |
---|
| 4688 | + if (is_offloaded) |
---|
| 4689 | + mid->mid_state = MID_RESPONSE_MALFORMED; |
---|
| 4690 | + else |
---|
| 4691 | + dequeue_mid(mid, rdata->result); |
---|
3118 | 4692 | return 0; |
---|
3119 | 4693 | } |
---|
3120 | 4694 | |
---|
.. | .. |
---|
3125 | 4699 | if (length < 0) |
---|
3126 | 4700 | return length; |
---|
3127 | 4701 | |
---|
3128 | | - dequeue_mid(mid, false); |
---|
| 4702 | + if (is_offloaded) |
---|
| 4703 | + mid->mid_state = MID_RESPONSE_RECEIVED; |
---|
| 4704 | + else |
---|
| 4705 | + dequeue_mid(mid, false); |
---|
3129 | 4706 | return length; |
---|
3130 | 4707 | } |
---|
3131 | 4708 | |
---|
| 4709 | +struct smb2_decrypt_work { |
---|
| 4710 | + struct work_struct decrypt; |
---|
| 4711 | + struct TCP_Server_Info *server; |
---|
| 4712 | + struct page **ppages; |
---|
| 4713 | + char *buf; |
---|
| 4714 | + unsigned int npages; |
---|
| 4715 | + unsigned int len; |
---|
| 4716 | +}; |
---|
| 4717 | + |
---|
| 4718 | + |
---|
| 4719 | +static void smb2_decrypt_offload(struct work_struct *work) |
---|
| 4720 | +{ |
---|
| 4721 | + struct smb2_decrypt_work *dw = container_of(work, |
---|
| 4722 | + struct smb2_decrypt_work, decrypt); |
---|
| 4723 | + int i, rc; |
---|
| 4724 | + struct mid_q_entry *mid; |
---|
| 4725 | + |
---|
| 4726 | + rc = decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_size, |
---|
| 4727 | + dw->ppages, dw->npages, dw->len, true); |
---|
| 4728 | + if (rc) { |
---|
| 4729 | + cifs_dbg(VFS, "error decrypting rc=%d\n", rc); |
---|
| 4730 | + goto free_pages; |
---|
| 4731 | + } |
---|
| 4732 | + |
---|
| 4733 | + dw->server->lstrp = jiffies; |
---|
| 4734 | + mid = smb2_find_dequeue_mid(dw->server, dw->buf); |
---|
| 4735 | + if (mid == NULL) |
---|
| 4736 | + cifs_dbg(FYI, "mid not found\n"); |
---|
| 4737 | + else { |
---|
| 4738 | + mid->decrypted = true; |
---|
| 4739 | + rc = handle_read_data(dw->server, mid, dw->buf, |
---|
| 4740 | + dw->server->vals->read_rsp_size, |
---|
| 4741 | + dw->ppages, dw->npages, dw->len, |
---|
| 4742 | + true); |
---|
| 4743 | + if (rc >= 0) { |
---|
| 4744 | +#ifdef CONFIG_CIFS_STATS2 |
---|
| 4745 | + mid->when_received = jiffies; |
---|
| 4746 | +#endif |
---|
| 4747 | + mid->callback(mid); |
---|
| 4748 | + } else { |
---|
| 4749 | + spin_lock(&GlobalMid_Lock); |
---|
| 4750 | + if (dw->server->tcpStatus == CifsNeedReconnect) { |
---|
| 4751 | + mid->mid_state = MID_RETRY_NEEDED; |
---|
| 4752 | + spin_unlock(&GlobalMid_Lock); |
---|
| 4753 | + mid->callback(mid); |
---|
| 4754 | + } else { |
---|
| 4755 | + mid->mid_state = MID_REQUEST_SUBMITTED; |
---|
| 4756 | + mid->mid_flags &= ~(MID_DELETED); |
---|
| 4757 | + list_add_tail(&mid->qhead, |
---|
| 4758 | + &dw->server->pending_mid_q); |
---|
| 4759 | + spin_unlock(&GlobalMid_Lock); |
---|
| 4760 | + } |
---|
| 4761 | + } |
---|
| 4762 | + cifs_mid_q_entry_release(mid); |
---|
| 4763 | + } |
---|
| 4764 | + |
---|
| 4765 | +free_pages: |
---|
| 4766 | + for (i = dw->npages-1; i >= 0; i--) |
---|
| 4767 | + put_page(dw->ppages[i]); |
---|
| 4768 | + |
---|
| 4769 | + kfree(dw->ppages); |
---|
| 4770 | + cifs_small_buf_release(dw->buf); |
---|
| 4771 | + kfree(dw); |
---|
| 4772 | +} |
---|
| 4773 | + |
---|
| 4774 | + |
---|
3132 | 4775 | static int |
---|
3133 | | -receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) |
---|
| 4776 | +receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, |
---|
| 4777 | + int *num_mids) |
---|
3134 | 4778 | { |
---|
3135 | 4779 | char *buf = server->smallbuf; |
---|
3136 | 4780 | struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf; |
---|
.. | .. |
---|
3140 | 4784 | unsigned int buflen = server->pdu_size; |
---|
3141 | 4785 | int rc; |
---|
3142 | 4786 | int i = 0; |
---|
| 4787 | + struct smb2_decrypt_work *dw; |
---|
3143 | 4788 | |
---|
| 4789 | + *num_mids = 1; |
---|
3144 | 4790 | len = min_t(unsigned int, buflen, server->vals->read_rsp_size + |
---|
3145 | 4791 | sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1; |
---|
3146 | 4792 | |
---|
.. | .. |
---|
3176 | 4822 | if (rc) |
---|
3177 | 4823 | goto free_pages; |
---|
3178 | 4824 | |
---|
| 4825 | + /* |
---|
| 4826 | + * For large reads, offload to different thread for better performance, |
---|
| 4827 | + * use more cores decrypting which can be expensive |
---|
| 4828 | + */ |
---|
| 4829 | + |
---|
| 4830 | + if ((server->min_offload) && (server->in_flight > 1) && |
---|
| 4831 | + (server->pdu_size >= server->min_offload)) { |
---|
| 4832 | + dw = kmalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL); |
---|
| 4833 | + if (dw == NULL) |
---|
| 4834 | + goto non_offloaded_decrypt; |
---|
| 4835 | + |
---|
| 4836 | + dw->buf = server->smallbuf; |
---|
| 4837 | + server->smallbuf = (char *)cifs_small_buf_get(); |
---|
| 4838 | + |
---|
| 4839 | + INIT_WORK(&dw->decrypt, smb2_decrypt_offload); |
---|
| 4840 | + |
---|
| 4841 | + dw->npages = npages; |
---|
| 4842 | + dw->server = server; |
---|
| 4843 | + dw->ppages = pages; |
---|
| 4844 | + dw->len = len; |
---|
| 4845 | + queue_work(decrypt_wq, &dw->decrypt); |
---|
| 4846 | + *num_mids = 0; /* worker thread takes care of finding mid */ |
---|
| 4847 | + return -1; |
---|
| 4848 | + } |
---|
| 4849 | + |
---|
| 4850 | +non_offloaded_decrypt: |
---|
3179 | 4851 | rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size, |
---|
3180 | | - pages, npages, len); |
---|
| 4852 | + pages, npages, len, false); |
---|
3181 | 4853 | if (rc) |
---|
3182 | 4854 | goto free_pages; |
---|
3183 | 4855 | |
---|
.. | .. |
---|
3189 | 4861 | (*mid)->decrypted = true; |
---|
3190 | 4862 | rc = handle_read_data(server, *mid, buf, |
---|
3191 | 4863 | server->vals->read_rsp_size, |
---|
3192 | | - pages, npages, len); |
---|
| 4864 | + pages, npages, len, false); |
---|
3193 | 4865 | } |
---|
3194 | 4866 | |
---|
3195 | 4867 | free_pages: |
---|
.. | .. |
---|
3233 | 4905 | server->total_read += length; |
---|
3234 | 4906 | |
---|
3235 | 4907 | buf_size = pdu_length - sizeof(struct smb2_transform_hdr); |
---|
3236 | | - length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0); |
---|
| 4908 | + length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0, false); |
---|
3237 | 4909 | if (length) |
---|
3238 | 4910 | return length; |
---|
3239 | 4911 | |
---|
.. | .. |
---|
3260 | 4932 | } |
---|
3261 | 4933 | |
---|
3262 | 4934 | if (*num_mids >= MAX_COMPOUND) { |
---|
3263 | | - cifs_dbg(VFS, "too many PDUs in compound\n"); |
---|
| 4935 | + cifs_server_dbg(VFS, "too many PDUs in compound\n"); |
---|
3264 | 4936 | return -1; |
---|
3265 | 4937 | } |
---|
3266 | 4938 | bufs[*num_mids] = buf; |
---|
.. | .. |
---|
3306 | 4978 | |
---|
3307 | 4979 | if (pdu_length < sizeof(struct smb2_transform_hdr) + |
---|
3308 | 4980 | sizeof(struct smb2_sync_hdr)) { |
---|
3309 | | - cifs_dbg(VFS, "Transform message is too small (%u)\n", |
---|
| 4981 | + cifs_server_dbg(VFS, "Transform message is too small (%u)\n", |
---|
3310 | 4982 | pdu_length); |
---|
3311 | 4983 | cifs_reconnect(server); |
---|
3312 | | - wake_up(&server->response_q); |
---|
3313 | 4984 | return -ECONNABORTED; |
---|
3314 | 4985 | } |
---|
3315 | 4986 | |
---|
3316 | 4987 | if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) { |
---|
3317 | | - cifs_dbg(VFS, "Transform message is broken\n"); |
---|
| 4988 | + cifs_server_dbg(VFS, "Transform message is broken\n"); |
---|
3318 | 4989 | cifs_reconnect(server); |
---|
3319 | | - wake_up(&server->response_q); |
---|
3320 | 4990 | return -ECONNABORTED; |
---|
3321 | 4991 | } |
---|
3322 | 4992 | |
---|
3323 | 4993 | /* TODO: add support for compounds containing READ. */ |
---|
3324 | 4994 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { |
---|
3325 | | - *num_mids = 1; |
---|
3326 | | - return receive_encrypted_read(server, &mids[0]); |
---|
| 4995 | + return receive_encrypted_read(server, &mids[0], num_mids); |
---|
3327 | 4996 | } |
---|
3328 | 4997 | |
---|
3329 | 4998 | return receive_encrypted_standard(server, mids, bufs, num_mids); |
---|
.. | .. |
---|
3335 | 5004 | char *buf = server->large_buf ? server->bigbuf : server->smallbuf; |
---|
3336 | 5005 | |
---|
3337 | 5006 | return handle_read_data(server, mid, buf, server->pdu_size, |
---|
3338 | | - NULL, 0, 0); |
---|
| 5007 | + NULL, 0, 0, false); |
---|
3339 | 5008 | } |
---|
3340 | 5009 | |
---|
3341 | 5010 | static int |
---|
.. | .. |
---|
3351 | 5020 | return le32_to_cpu(hdr->NextCommand); |
---|
3352 | 5021 | } |
---|
3353 | 5022 | |
---|
| 5023 | +static int |
---|
| 5024 | +smb2_make_node(unsigned int xid, struct inode *inode, |
---|
| 5025 | + struct dentry *dentry, struct cifs_tcon *tcon, |
---|
| 5026 | + char *full_path, umode_t mode, dev_t dev) |
---|
| 5027 | +{ |
---|
| 5028 | + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
---|
| 5029 | + int rc = -EPERM; |
---|
| 5030 | + FILE_ALL_INFO *buf = NULL; |
---|
| 5031 | + struct cifs_io_parms io_parms = {0}; |
---|
| 5032 | + __u32 oplock = 0; |
---|
| 5033 | + struct cifs_fid fid; |
---|
| 5034 | + struct cifs_open_parms oparms; |
---|
| 5035 | + unsigned int bytes_written; |
---|
| 5036 | + struct win_dev *pdev; |
---|
| 5037 | + struct kvec iov[2]; |
---|
| 5038 | + |
---|
| 5039 | + /* |
---|
| 5040 | + * Check if mounted with mount parm 'sfu' mount parm. |
---|
| 5041 | + * SFU emulation should work with all servers, but only |
---|
| 5042 | + * supports block and char device (no socket & fifo), |
---|
| 5043 | + * and was used by default in earlier versions of Windows |
---|
| 5044 | + */ |
---|
| 5045 | + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) |
---|
| 5046 | + goto out; |
---|
| 5047 | + |
---|
| 5048 | + /* |
---|
| 5049 | + * TODO: Add ability to create instead via reparse point. Windows (e.g. |
---|
| 5050 | + * their current NFS server) uses this approach to expose special files |
---|
| 5051 | + * over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions |
---|
| 5052 | + */ |
---|
| 5053 | + |
---|
| 5054 | + if (!S_ISCHR(mode) && !S_ISBLK(mode)) |
---|
| 5055 | + goto out; |
---|
| 5056 | + |
---|
| 5057 | + cifs_dbg(FYI, "sfu compat create special file\n"); |
---|
| 5058 | + |
---|
| 5059 | + buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
---|
| 5060 | + if (buf == NULL) { |
---|
| 5061 | + rc = -ENOMEM; |
---|
| 5062 | + goto out; |
---|
| 5063 | + } |
---|
| 5064 | + |
---|
| 5065 | + oparms.tcon = tcon; |
---|
| 5066 | + oparms.cifs_sb = cifs_sb; |
---|
| 5067 | + oparms.desired_access = GENERIC_WRITE; |
---|
| 5068 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR | |
---|
| 5069 | + CREATE_OPTION_SPECIAL); |
---|
| 5070 | + oparms.disposition = FILE_CREATE; |
---|
| 5071 | + oparms.path = full_path; |
---|
| 5072 | + oparms.fid = &fid; |
---|
| 5073 | + oparms.reconnect = false; |
---|
| 5074 | + |
---|
| 5075 | + if (tcon->ses->server->oplocks) |
---|
| 5076 | + oplock = REQ_OPLOCK; |
---|
| 5077 | + else |
---|
| 5078 | + oplock = 0; |
---|
| 5079 | + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf); |
---|
| 5080 | + if (rc) |
---|
| 5081 | + goto out; |
---|
| 5082 | + |
---|
| 5083 | + /* |
---|
| 5084 | + * BB Do not bother to decode buf since no local inode yet to put |
---|
| 5085 | + * timestamps in, but we can reuse it safely. |
---|
| 5086 | + */ |
---|
| 5087 | + |
---|
| 5088 | + pdev = (struct win_dev *)buf; |
---|
| 5089 | + io_parms.pid = current->tgid; |
---|
| 5090 | + io_parms.tcon = tcon; |
---|
| 5091 | + io_parms.offset = 0; |
---|
| 5092 | + io_parms.length = sizeof(struct win_dev); |
---|
| 5093 | + iov[1].iov_base = buf; |
---|
| 5094 | + iov[1].iov_len = sizeof(struct win_dev); |
---|
| 5095 | + if (S_ISCHR(mode)) { |
---|
| 5096 | + memcpy(pdev->type, "IntxCHR", 8); |
---|
| 5097 | + pdev->major = cpu_to_le64(MAJOR(dev)); |
---|
| 5098 | + pdev->minor = cpu_to_le64(MINOR(dev)); |
---|
| 5099 | + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, |
---|
| 5100 | + &bytes_written, iov, 1); |
---|
| 5101 | + } else if (S_ISBLK(mode)) { |
---|
| 5102 | + memcpy(pdev->type, "IntxBLK", 8); |
---|
| 5103 | + pdev->major = cpu_to_le64(MAJOR(dev)); |
---|
| 5104 | + pdev->minor = cpu_to_le64(MINOR(dev)); |
---|
| 5105 | + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, |
---|
| 5106 | + &bytes_written, iov, 1); |
---|
| 5107 | + } |
---|
| 5108 | + tcon->ses->server->ops->close(xid, tcon, &fid); |
---|
| 5109 | + d_drop(dentry); |
---|
| 5110 | + |
---|
| 5111 | + /* FIXME: add code here to set EAs */ |
---|
| 5112 | +out: |
---|
| 5113 | + kfree(buf); |
---|
| 5114 | + return rc; |
---|
| 5115 | +} |
---|
| 5116 | + |
---|
| 5117 | +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
---|
3354 | 5118 | struct smb_version_operations smb20_operations = { |
---|
3355 | 5119 | .compare_fids = smb2_compare_fids, |
---|
3356 | 5120 | .setup_request = smb2_setup_request, |
---|
.. | .. |
---|
3438 | 5202 | .query_all_EAs = smb2_query_eas, |
---|
3439 | 5203 | .set_EA = smb2_set_ea, |
---|
3440 | 5204 | #endif /* CIFS_XATTR */ |
---|
3441 | | -#ifdef CONFIG_CIFS_ACL |
---|
3442 | 5205 | .get_acl = get_smb2_acl, |
---|
3443 | 5206 | .get_acl_by_fid = get_smb2_acl_by_fid, |
---|
3444 | 5207 | .set_acl = set_smb2_acl, |
---|
3445 | | -#endif /* CIFS_ACL */ |
---|
3446 | 5208 | .next_header = smb2_next_header, |
---|
| 5209 | + .ioctl_query_info = smb2_ioctl_query_info, |
---|
| 5210 | + .make_node = smb2_make_node, |
---|
| 5211 | + .fiemap = smb3_fiemap, |
---|
| 5212 | + .llseek = smb3_llseek, |
---|
| 5213 | + .is_status_io_timeout = smb2_is_status_io_timeout, |
---|
3447 | 5214 | }; |
---|
| 5215 | +#endif /* CIFS_ALLOW_INSECURE_LEGACY */ |
---|
3448 | 5216 | |
---|
3449 | 5217 | struct smb_version_operations smb21_operations = { |
---|
3450 | 5218 | .compare_fids = smb2_compare_fids, |
---|
.. | .. |
---|
3456 | 5224 | .get_credits_field = smb2_get_credits_field, |
---|
3457 | 5225 | .get_credits = smb2_get_credits, |
---|
3458 | 5226 | .wait_mtu_credits = smb2_wait_mtu_credits, |
---|
| 5227 | + .adjust_credits = smb2_adjust_credits, |
---|
3459 | 5228 | .get_next_mid = smb2_get_next_mid, |
---|
3460 | 5229 | .revert_current_mid = smb2_revert_current_mid, |
---|
3461 | 5230 | .read_data_offset = smb2_read_data_offset, |
---|
.. | .. |
---|
3528 | 5297 | .wp_retry_size = smb2_wp_retry_size, |
---|
3529 | 5298 | .dir_needs_close = smb2_dir_needs_close, |
---|
3530 | 5299 | .enum_snapshots = smb3_enum_snapshots, |
---|
| 5300 | + .notify = smb3_notify, |
---|
3531 | 5301 | .get_dfs_refer = smb2_get_dfs_refer, |
---|
3532 | 5302 | .select_sectype = smb2_select_sectype, |
---|
3533 | 5303 | #ifdef CONFIG_CIFS_XATTR |
---|
3534 | 5304 | .query_all_EAs = smb2_query_eas, |
---|
3535 | 5305 | .set_EA = smb2_set_ea, |
---|
3536 | 5306 | #endif /* CIFS_XATTR */ |
---|
3537 | | -#ifdef CONFIG_CIFS_ACL |
---|
3538 | 5307 | .get_acl = get_smb2_acl, |
---|
3539 | 5308 | .get_acl_by_fid = get_smb2_acl_by_fid, |
---|
3540 | 5309 | .set_acl = set_smb2_acl, |
---|
3541 | | -#endif /* CIFS_ACL */ |
---|
3542 | 5310 | .next_header = smb2_next_header, |
---|
| 5311 | + .ioctl_query_info = smb2_ioctl_query_info, |
---|
| 5312 | + .make_node = smb2_make_node, |
---|
| 5313 | + .fiemap = smb3_fiemap, |
---|
| 5314 | + .llseek = smb3_llseek, |
---|
| 5315 | + .is_status_io_timeout = smb2_is_status_io_timeout, |
---|
3543 | 5316 | }; |
---|
3544 | 5317 | |
---|
3545 | 5318 | struct smb_version_operations smb30_operations = { |
---|
.. | .. |
---|
3552 | 5325 | .get_credits_field = smb2_get_credits_field, |
---|
3553 | 5326 | .get_credits = smb2_get_credits, |
---|
3554 | 5327 | .wait_mtu_credits = smb2_wait_mtu_credits, |
---|
| 5328 | + .adjust_credits = smb2_adjust_credits, |
---|
3555 | 5329 | .get_next_mid = smb2_get_next_mid, |
---|
3556 | 5330 | .revert_current_mid = smb2_revert_current_mid, |
---|
3557 | 5331 | .read_data_offset = smb2_read_data_offset, |
---|
.. | .. |
---|
3568 | 5342 | .downgrade_oplock = smb3_downgrade_oplock, |
---|
3569 | 5343 | .need_neg = smb2_need_neg, |
---|
3570 | 5344 | .negotiate = smb2_negotiate, |
---|
3571 | | - .negotiate_wsize = smb2_negotiate_wsize, |
---|
3572 | | - .negotiate_rsize = smb2_negotiate_rsize, |
---|
| 5345 | + .negotiate_wsize = smb3_negotiate_wsize, |
---|
| 5346 | + .negotiate_rsize = smb3_negotiate_rsize, |
---|
3573 | 5347 | .sess_setup = SMB2_sess_setup, |
---|
3574 | 5348 | .logoff = SMB2_logoff, |
---|
3575 | 5349 | .tree_connect = SMB2_tcon, |
---|
.. | .. |
---|
3579 | 5353 | .can_echo = smb2_can_echo, |
---|
3580 | 5354 | .echo = SMB2_echo, |
---|
3581 | 5355 | .query_path_info = smb2_query_path_info, |
---|
| 5356 | + /* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */ |
---|
| 5357 | + .query_reparse_tag = smb2_query_reparse_tag, |
---|
3582 | 5358 | .get_srv_inum = smb2_get_srv_inum, |
---|
3583 | 5359 | .query_file_info = smb2_query_file_info, |
---|
3584 | 5360 | .set_path_size = smb2_set_path_size, |
---|
.. | .. |
---|
3597 | 5373 | .open = smb2_open_file, |
---|
3598 | 5374 | .set_fid = smb2_set_fid, |
---|
3599 | 5375 | .close = smb2_close_file, |
---|
| 5376 | + .close_getattr = smb2_close_getattr, |
---|
3600 | 5377 | .flush = smb2_flush_file, |
---|
3601 | 5378 | .async_readv = smb2_async_readv, |
---|
3602 | 5379 | .async_writev = smb2_async_writev, |
---|
.. | .. |
---|
3630 | 5407 | .dir_needs_close = smb2_dir_needs_close, |
---|
3631 | 5408 | .fallocate = smb3_fallocate, |
---|
3632 | 5409 | .enum_snapshots = smb3_enum_snapshots, |
---|
| 5410 | + .notify = smb3_notify, |
---|
3633 | 5411 | .init_transform_rq = smb3_init_transform_rq, |
---|
3634 | 5412 | .is_transform_hdr = smb3_is_transform_hdr, |
---|
3635 | 5413 | .receive_transform = smb3_receive_transform, |
---|
.. | .. |
---|
3639 | 5417 | .query_all_EAs = smb2_query_eas, |
---|
3640 | 5418 | .set_EA = smb2_set_ea, |
---|
3641 | 5419 | #endif /* CIFS_XATTR */ |
---|
3642 | | -#ifdef CONFIG_CIFS_ACL |
---|
3643 | 5420 | .get_acl = get_smb2_acl, |
---|
3644 | 5421 | .get_acl_by_fid = get_smb2_acl_by_fid, |
---|
3645 | 5422 | .set_acl = set_smb2_acl, |
---|
3646 | | -#endif /* CIFS_ACL */ |
---|
3647 | 5423 | .next_header = smb2_next_header, |
---|
| 5424 | + .ioctl_query_info = smb2_ioctl_query_info, |
---|
| 5425 | + .make_node = smb2_make_node, |
---|
| 5426 | + .fiemap = smb3_fiemap, |
---|
| 5427 | + .llseek = smb3_llseek, |
---|
| 5428 | + .is_status_io_timeout = smb2_is_status_io_timeout, |
---|
3648 | 5429 | }; |
---|
3649 | 5430 | |
---|
3650 | 5431 | struct smb_version_operations smb311_operations = { |
---|
.. | .. |
---|
3657 | 5438 | .get_credits_field = smb2_get_credits_field, |
---|
3658 | 5439 | .get_credits = smb2_get_credits, |
---|
3659 | 5440 | .wait_mtu_credits = smb2_wait_mtu_credits, |
---|
| 5441 | + .adjust_credits = smb2_adjust_credits, |
---|
3660 | 5442 | .get_next_mid = smb2_get_next_mid, |
---|
3661 | 5443 | .revert_current_mid = smb2_revert_current_mid, |
---|
3662 | 5444 | .read_data_offset = smb2_read_data_offset, |
---|
.. | .. |
---|
3673 | 5455 | .downgrade_oplock = smb3_downgrade_oplock, |
---|
3674 | 5456 | .need_neg = smb2_need_neg, |
---|
3675 | 5457 | .negotiate = smb2_negotiate, |
---|
3676 | | - .negotiate_wsize = smb2_negotiate_wsize, |
---|
3677 | | - .negotiate_rsize = smb2_negotiate_rsize, |
---|
| 5458 | + .negotiate_wsize = smb3_negotiate_wsize, |
---|
| 5459 | + .negotiate_rsize = smb3_negotiate_rsize, |
---|
3678 | 5460 | .sess_setup = SMB2_sess_setup, |
---|
3679 | 5461 | .logoff = SMB2_logoff, |
---|
3680 | 5462 | .tree_connect = SMB2_tcon, |
---|
.. | .. |
---|
3684 | 5466 | .can_echo = smb2_can_echo, |
---|
3685 | 5467 | .echo = SMB2_echo, |
---|
3686 | 5468 | .query_path_info = smb2_query_path_info, |
---|
| 5469 | + .query_reparse_tag = smb2_query_reparse_tag, |
---|
3687 | 5470 | .get_srv_inum = smb2_get_srv_inum, |
---|
3688 | 5471 | .query_file_info = smb2_query_file_info, |
---|
3689 | 5472 | .set_path_size = smb2_set_path_size, |
---|
.. | .. |
---|
3703 | 5486 | .open = smb2_open_file, |
---|
3704 | 5487 | .set_fid = smb2_set_fid, |
---|
3705 | 5488 | .close = smb2_close_file, |
---|
| 5489 | + .close_getattr = smb2_close_getattr, |
---|
3706 | 5490 | .flush = smb2_flush_file, |
---|
3707 | 5491 | .async_readv = smb2_async_readv, |
---|
3708 | 5492 | .async_writev = smb2_async_writev, |
---|
.. | .. |
---|
3736 | 5520 | .dir_needs_close = smb2_dir_needs_close, |
---|
3737 | 5521 | .fallocate = smb3_fallocate, |
---|
3738 | 5522 | .enum_snapshots = smb3_enum_snapshots, |
---|
| 5523 | + .notify = smb3_notify, |
---|
3739 | 5524 | .init_transform_rq = smb3_init_transform_rq, |
---|
3740 | 5525 | .is_transform_hdr = smb3_is_transform_hdr, |
---|
3741 | 5526 | .receive_transform = smb3_receive_transform, |
---|
.. | .. |
---|
3745 | 5530 | .query_all_EAs = smb2_query_eas, |
---|
3746 | 5531 | .set_EA = smb2_set_ea, |
---|
3747 | 5532 | #endif /* CIFS_XATTR */ |
---|
3748 | | -#ifdef CONFIG_CIFS_ACL |
---|
3749 | 5533 | .get_acl = get_smb2_acl, |
---|
3750 | 5534 | .get_acl_by_fid = get_smb2_acl_by_fid, |
---|
3751 | 5535 | .set_acl = set_smb2_acl, |
---|
3752 | | -#endif /* CIFS_ACL */ |
---|
3753 | 5536 | .next_header = smb2_next_header, |
---|
| 5537 | + .ioctl_query_info = smb2_ioctl_query_info, |
---|
| 5538 | + .make_node = smb2_make_node, |
---|
| 5539 | + .fiemap = smb3_fiemap, |
---|
| 5540 | + .llseek = smb3_llseek, |
---|
| 5541 | + .is_status_io_timeout = smb2_is_status_io_timeout, |
---|
3754 | 5542 | }; |
---|
3755 | 5543 | |
---|
| 5544 | +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
---|
3756 | 5545 | struct smb_version_values smb20_values = { |
---|
3757 | 5546 | .version_string = SMB20_VERSION_STRING, |
---|
3758 | 5547 | .protocol_id = SMB20_PROT_ID, |
---|
.. | .. |
---|
3773 | 5562 | .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, |
---|
3774 | 5563 | .create_lease_size = sizeof(struct create_lease), |
---|
3775 | 5564 | }; |
---|
| 5565 | +#endif /* ALLOW_INSECURE_LEGACY */ |
---|
3776 | 5566 | |
---|
3777 | 5567 | struct smb_version_values smb21_values = { |
---|
3778 | 5568 | .version_string = SMB21_VERSION_STRING, |
---|