Merge tag 'qcom-drivers-for-6.9-2' of https://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / fs / smb / client / smb2inode.c
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002, 2011
5  *                 Etersoft, 2012
6  *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
7  *              Steve French (sfrench@us.ibm.com)
8  *
9  */
10 #include <linux/fs.h>
11 #include <linux/stat.h>
12 #include <linux/slab.h>
13 #include <linux/pagemap.h>
14 #include <asm/div64.h>
15 #include "cifsfs.h"
16 #include "cifspdu.h"
17 #include "cifsglob.h"
18 #include "cifsproto.h"
19 #include "cifs_debug.h"
20 #include "cifs_fs_sb.h"
21 #include "cifs_unicode.h"
22 #include "fscache.h"
23 #include "smb2glob.h"
24 #include "smb2pdu.h"
25 #include "smb2proto.h"
26 #include "cached_dir.h"
27 #include "smb2status.h"
28
29 static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
30 {
31         struct reparse_data_buffer *buf;
32         struct smb2_ioctl_rsp *io = iov->iov_base;
33         u32 off, count, len;
34
35         count = le32_to_cpu(io->OutputCount);
36         off = le32_to_cpu(io->OutputOffset);
37         if (check_add_overflow(off, count, &len) || len > iov->iov_len)
38                 return ERR_PTR(-EIO);
39
40         buf = (struct reparse_data_buffer *)((u8 *)io + off);
41         len = sizeof(*buf);
42         if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
43                 return ERR_PTR(-EIO);
44         return buf;
45 }
46
47 static inline __u32 file_create_options(struct dentry *dentry)
48 {
49         struct cifsInodeInfo *ci;
50
51         if (dentry) {
52                 ci = CIFS_I(d_inode(dentry));
53                 if (ci->cifsAttrs & ATTR_REPARSE)
54                         return OPEN_REPARSE_POINT;
55         }
56         return 0;
57 }
58
59 /* Parse owner and group from SMB3.1.1 POSIX query info */
60 static int parse_posix_sids(struct cifs_open_info_data *data,
61                             struct kvec *rsp_iov)
62 {
63         struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
64         unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
65         unsigned int qi_len = sizeof(data->posix_fi);
66         int owner_len, group_len;
67         u8 *sidsbuf, *sidsbuf_end;
68
69         if (out_len <= qi_len)
70                 return -EINVAL;
71
72         sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
73         sidsbuf_end = sidsbuf + out_len - qi_len;
74
75         owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
76         if (owner_len == -1)
77                 return -EINVAL;
78
79         memcpy(&data->posix_owner, sidsbuf, owner_len);
80         group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
81         if (group_len == -1)
82                 return -EINVAL;
83
84         memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
85         return 0;
86 }
87
88 /*
89  * note: If cfile is passed, the reference to it is dropped here.
90  * So make sure that you do not reuse cfile after return from this func.
91  *
92  * If passing @out_iov and @out_buftype, ensure to make them both large enough
93  * (>= 3) to hold all compounded responses.  Caller is also responsible for
94  * freeing them up with free_rsp_buf().
95  */
96 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
97                             struct cifs_sb_info *cifs_sb, const char *full_path,
98                             __u32 desired_access, __u32 create_disposition,
99                             __u32 create_options, umode_t mode, struct kvec *in_iov,
100                             int *cmds, int num_cmds, struct cifsFileInfo *cfile,
101                             struct kvec *out_iov, int *out_buftype)
102 {
103
104         struct reparse_data_buffer *rbuf;
105         struct smb2_compound_vars *vars = NULL;
106         struct kvec *rsp_iov, *iov;
107         struct smb_rqst *rqst;
108         int rc;
109         __le16 *utf16_path = NULL;
110         __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
111         struct cifs_fid fid;
112         struct cifs_ses *ses = tcon->ses;
113         struct TCP_Server_Info *server;
114         int num_rqst = 0, i;
115         int resp_buftype[MAX_COMPOUND];
116         struct smb2_query_info_rsp *qi_rsp = NULL;
117         struct cifs_open_info_data *idata;
118         int flags = 0;
119         __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
120         unsigned int size[2];
121         void *data[2];
122         int len;
123
124         vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
125         if (vars == NULL)
126                 return -ENOMEM;
127         rqst = &vars->rqst[0];
128         rsp_iov = &vars->rsp_iov[0];
129
130         server = cifs_pick_channel(ses);
131
132         if (smb3_encryption_required(tcon))
133                 flags |= CIFS_TRANSFORM_REQ;
134
135         for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
136                 resp_buftype[i] = CIFS_NO_BUFFER;
137
138         /* We already have a handle so we can skip the open */
139         if (cfile)
140                 goto after_open;
141
142         /* Open */
143         utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
144         if (!utf16_path) {
145                 rc = -ENOMEM;
146                 goto finished;
147         }
148
149         vars->oparms = (struct cifs_open_parms) {
150                 .tcon = tcon,
151                 .path = full_path,
152                 .desired_access = desired_access,
153                 .disposition = create_disposition,
154                 .create_options = cifs_create_options(cifs_sb, create_options),
155                 .fid = &fid,
156                 .mode = mode,
157                 .cifs_sb = cifs_sb,
158         };
159
160         rqst[num_rqst].rq_iov = &vars->open_iov[0];
161         rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
162         rc = SMB2_open_init(tcon, server,
163                             &rqst[num_rqst], &oplock, &vars->oparms,
164                             utf16_path);
165         kfree(utf16_path);
166         if (rc)
167                 goto finished;
168
169         smb2_set_next_command(tcon, &rqst[num_rqst]);
170  after_open:
171         num_rqst++;
172         rc = 0;
173
174         for (i = 0; i < num_cmds; i++) {
175                 /* Operation */
176                 switch (cmds[i]) {
177                 case SMB2_OP_QUERY_INFO:
178                         rqst[num_rqst].rq_iov = &vars->qi_iov;
179                         rqst[num_rqst].rq_nvec = 1;
180
181                         if (cfile) {
182                                 rc = SMB2_query_info_init(tcon, server,
183                                                           &rqst[num_rqst],
184                                                           cfile->fid.persistent_fid,
185                                                           cfile->fid.volatile_fid,
186                                                           FILE_ALL_INFORMATION,
187                                                           SMB2_O_INFO_FILE, 0,
188                                                           sizeof(struct smb2_file_all_info) +
189                                                           PATH_MAX * 2, 0, NULL);
190                         } else {
191                                 rc = SMB2_query_info_init(tcon, server,
192                                                           &rqst[num_rqst],
193                                                           COMPOUND_FID,
194                                                           COMPOUND_FID,
195                                                           FILE_ALL_INFORMATION,
196                                                           SMB2_O_INFO_FILE, 0,
197                                                           sizeof(struct smb2_file_all_info) +
198                                                           PATH_MAX * 2, 0, NULL);
199                                 if (!rc) {
200                                         smb2_set_next_command(tcon, &rqst[num_rqst]);
201                                         smb2_set_related(&rqst[num_rqst]);
202                                 }
203                         }
204
205                         if (rc)
206                                 goto finished;
207                         num_rqst++;
208                         trace_smb3_query_info_compound_enter(xid, ses->Suid,
209                                                              tcon->tid, full_path);
210                         break;
211                 case SMB2_OP_POSIX_QUERY_INFO:
212                         rqst[num_rqst].rq_iov = &vars->qi_iov;
213                         rqst[num_rqst].rq_nvec = 1;
214
215                         if (cfile) {
216                                 /* TBD: fix following to allow for longer SIDs */
217                                 rc = SMB2_query_info_init(tcon, server,
218                                                           &rqst[num_rqst],
219                                                           cfile->fid.persistent_fid,
220                                                           cfile->fid.volatile_fid,
221                                                           SMB_FIND_FILE_POSIX_INFO,
222                                                           SMB2_O_INFO_FILE, 0,
223                                                           sizeof(struct smb311_posix_qinfo *) +
224                                                           (PATH_MAX * 2) +
225                                                           (sizeof(struct cifs_sid) * 2), 0, NULL);
226                         } else {
227                                 rc = SMB2_query_info_init(tcon, server,
228                                                           &rqst[num_rqst],
229                                                           COMPOUND_FID,
230                                                           COMPOUND_FID,
231                                                           SMB_FIND_FILE_POSIX_INFO,
232                                                           SMB2_O_INFO_FILE, 0,
233                                                           sizeof(struct smb311_posix_qinfo *) +
234                                                           (PATH_MAX * 2) +
235                                                           (sizeof(struct cifs_sid) * 2), 0, NULL);
236                                 if (!rc) {
237                                         smb2_set_next_command(tcon, &rqst[num_rqst]);
238                                         smb2_set_related(&rqst[num_rqst]);
239                                 }
240                         }
241
242                         if (rc)
243                                 goto finished;
244                         num_rqst++;
245                         trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
246                                                                    tcon->tid, full_path);
247                         break;
248                 case SMB2_OP_DELETE:
249                         trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
250                         break;
251                 case SMB2_OP_MKDIR:
252                         /*
253                          * Directories are created through parameters in the
254                          * SMB2_open() call.
255                          */
256                         trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
257                         break;
258                 case SMB2_OP_RMDIR:
259                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
260                         rqst[num_rqst].rq_nvec = 1;
261
262                         size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
263                         data[0] = &delete_pending[0];
264
265                         rc = SMB2_set_info_init(tcon, server,
266                                                 &rqst[num_rqst], COMPOUND_FID,
267                                                 COMPOUND_FID, current->tgid,
268                                                 FILE_DISPOSITION_INFORMATION,
269                                                 SMB2_O_INFO_FILE, 0, data, size);
270                         if (rc)
271                                 goto finished;
272                         smb2_set_next_command(tcon, &rqst[num_rqst]);
273                         smb2_set_related(&rqst[num_rqst++]);
274                         trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
275                         break;
276                 case SMB2_OP_SET_EOF:
277                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
278                         rqst[num_rqst].rq_nvec = 1;
279
280                         size[0] = in_iov[i].iov_len;
281                         data[0] = in_iov[i].iov_base;
282
283                         if (cfile) {
284                                 rc = SMB2_set_info_init(tcon, server,
285                                                         &rqst[num_rqst],
286                                                         cfile->fid.persistent_fid,
287                                                         cfile->fid.volatile_fid,
288                                                         current->tgid,
289                                                         FILE_END_OF_FILE_INFORMATION,
290                                                         SMB2_O_INFO_FILE, 0,
291                                                         data, size);
292                         } else {
293                                 rc = SMB2_set_info_init(tcon, server,
294                                                         &rqst[num_rqst],
295                                                         COMPOUND_FID,
296                                                         COMPOUND_FID,
297                                                         current->tgid,
298                                                         FILE_END_OF_FILE_INFORMATION,
299                                                         SMB2_O_INFO_FILE, 0,
300                                                         data, size);
301                                 if (!rc) {
302                                         smb2_set_next_command(tcon, &rqst[num_rqst]);
303                                         smb2_set_related(&rqst[num_rqst]);
304                                 }
305                         }
306                         if (rc)
307                                 goto finished;
308                         num_rqst++;
309                         trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
310                         break;
311                 case SMB2_OP_SET_INFO:
312                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
313                         rqst[num_rqst].rq_nvec = 1;
314
315                         size[0] = in_iov[i].iov_len;
316                         data[0] = in_iov[i].iov_base;
317
318                         if (cfile) {
319                                 rc = SMB2_set_info_init(tcon, server,
320                                                         &rqst[num_rqst],
321                                                         cfile->fid.persistent_fid,
322                                                         cfile->fid.volatile_fid, current->tgid,
323                                                         FILE_BASIC_INFORMATION,
324                                                         SMB2_O_INFO_FILE, 0, data, size);
325                         } else {
326                                 rc = SMB2_set_info_init(tcon, server,
327                                                         &rqst[num_rqst],
328                                                         COMPOUND_FID,
329                                                         COMPOUND_FID, current->tgid,
330                                                         FILE_BASIC_INFORMATION,
331                                                         SMB2_O_INFO_FILE, 0, data, size);
332                                 if (!rc) {
333                                         smb2_set_next_command(tcon, &rqst[num_rqst]);
334                                         smb2_set_related(&rqst[num_rqst]);
335                                 }
336                         }
337
338                         if (rc)
339                                 goto finished;
340                         num_rqst++;
341                         trace_smb3_set_info_compound_enter(xid, ses->Suid,
342                                                            tcon->tid, full_path);
343                         break;
344                 case SMB2_OP_RENAME:
345                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
346                         rqst[num_rqst].rq_nvec = 2;
347
348                         len = in_iov[i].iov_len;
349
350                         vars->rename_info.ReplaceIfExists = 1;
351                         vars->rename_info.RootDirectory = 0;
352                         vars->rename_info.FileNameLength = cpu_to_le32(len);
353
354                         size[0] = sizeof(struct smb2_file_rename_info);
355                         data[0] = &vars->rename_info;
356
357                         size[1] = len + 2 /* null */;
358                         data[1] = in_iov[i].iov_base;
359
360                         if (cfile) {
361                                 rc = SMB2_set_info_init(tcon, server,
362                                                         &rqst[num_rqst],
363                                                         cfile->fid.persistent_fid,
364                                                         cfile->fid.volatile_fid,
365                                                         current->tgid, FILE_RENAME_INFORMATION,
366                                                         SMB2_O_INFO_FILE, 0, data, size);
367                         } else {
368                                 rc = SMB2_set_info_init(tcon, server,
369                                                         &rqst[num_rqst],
370                                                         COMPOUND_FID, COMPOUND_FID,
371                                                         current->tgid, FILE_RENAME_INFORMATION,
372                                                         SMB2_O_INFO_FILE, 0, data, size);
373                                 if (!rc) {
374                                         smb2_set_next_command(tcon, &rqst[num_rqst]);
375                                         smb2_set_related(&rqst[num_rqst]);
376                                 }
377                         }
378                         if (rc)
379                                 goto finished;
380                         num_rqst++;
381                         trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
382                         break;
383                 case SMB2_OP_HARDLINK:
384                         rqst[num_rqst].rq_iov = &vars->si_iov[0];
385                         rqst[num_rqst].rq_nvec = 2;
386
387                         len = in_iov[i].iov_len;
388
389                         vars->link_info.ReplaceIfExists = 0;
390                         vars->link_info.RootDirectory = 0;
391                         vars->link_info.FileNameLength = cpu_to_le32(len);
392
393                         size[0] = sizeof(struct smb2_file_link_info);
394                         data[0] = &vars->link_info;
395
396                         size[1] = len + 2 /* null */;
397                         data[1] = in_iov[i].iov_base;
398
399                         rc = SMB2_set_info_init(tcon, server,
400                                                 &rqst[num_rqst], COMPOUND_FID,
401                                                 COMPOUND_FID, current->tgid,
402                                                 FILE_LINK_INFORMATION,
403                                                 SMB2_O_INFO_FILE, 0, data, size);
404                         if (rc)
405                                 goto finished;
406                         smb2_set_next_command(tcon, &rqst[num_rqst]);
407                         smb2_set_related(&rqst[num_rqst++]);
408                         trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
409                         break;
410                 case SMB2_OP_SET_REPARSE:
411                         rqst[num_rqst].rq_iov = vars->io_iov;
412                         rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
413
414                         rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
415                                              COMPOUND_FID, COMPOUND_FID,
416                                              FSCTL_SET_REPARSE_POINT,
417                                              in_iov[i].iov_base,
418                                              in_iov[i].iov_len, 0);
419                         if (rc)
420                                 goto finished;
421                         smb2_set_next_command(tcon, &rqst[num_rqst]);
422                         smb2_set_related(&rqst[num_rqst++]);
423                         trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
424                                                               tcon->tid, full_path);
425                         break;
426                 case SMB2_OP_GET_REPARSE:
427                         rqst[num_rqst].rq_iov = vars->io_iov;
428                         rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
429
430                         rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
431                                              COMPOUND_FID, COMPOUND_FID,
432                                              FSCTL_GET_REPARSE_POINT,
433                                              NULL, 0, CIFSMaxBufSize);
434                         if (rc)
435                                 goto finished;
436                         smb2_set_next_command(tcon, &rqst[num_rqst]);
437                         smb2_set_related(&rqst[num_rqst++]);
438                         trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
439                                                               tcon->tid, full_path);
440                         break;
441                 default:
442                         cifs_dbg(VFS, "Invalid command\n");
443                         rc = -EINVAL;
444                 }
445         }
446         if (rc)
447                 goto finished;
448
449         /* We already have a handle so we can skip the close */
450         if (cfile)
451                 goto after_close;
452         /* Close */
453         flags |= CIFS_CP_CREATE_CLOSE_OP;
454         rqst[num_rqst].rq_iov = &vars->close_iov;
455         rqst[num_rqst].rq_nvec = 1;
456         rc = SMB2_close_init(tcon, server,
457                              &rqst[num_rqst], COMPOUND_FID,
458                              COMPOUND_FID, false);
459         smb2_set_related(&rqst[num_rqst]);
460         if (rc)
461                 goto finished;
462  after_close:
463         num_rqst++;
464
465         if (cfile) {
466                 rc = compound_send_recv(xid, ses, server,
467                                         flags, num_rqst - 2,
468                                         &rqst[1], &resp_buftype[1],
469                                         &rsp_iov[1]);
470         } else
471                 rc = compound_send_recv(xid, ses, server,
472                                         flags, num_rqst,
473                                         rqst, resp_buftype,
474                                         rsp_iov);
475
476 finished:
477         num_rqst = 0;
478         SMB2_open_free(&rqst[num_rqst++]);
479         if (rc == -EREMCHG) {
480                 pr_warn_once("server share %s deleted\n", tcon->tree_name);
481                 tcon->need_reconnect = true;
482         }
483
484         for (i = 0; i < num_cmds; i++) {
485                 switch (cmds[i]) {
486                 case SMB2_OP_QUERY_INFO:
487                         idata = in_iov[i].iov_base;
488                         if (rc == 0 && cfile && cfile->symlink_target) {
489                                 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
490                                 if (!idata->symlink_target)
491                                         rc = -ENOMEM;
492                         }
493                         if (rc == 0) {
494                                 qi_rsp = (struct smb2_query_info_rsp *)
495                                         rsp_iov[i + 1].iov_base;
496                                 rc = smb2_validate_and_copy_iov(
497                                         le16_to_cpu(qi_rsp->OutputBufferOffset),
498                                         le32_to_cpu(qi_rsp->OutputBufferLength),
499                                         &rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
500                         }
501                         SMB2_query_info_free(&rqst[num_rqst++]);
502                         if (rc)
503                                 trace_smb3_query_info_compound_err(xid,  ses->Suid,
504                                                                    tcon->tid, rc);
505                         else
506                                 trace_smb3_query_info_compound_done(xid, ses->Suid,
507                                                                     tcon->tid);
508                         break;
509                 case SMB2_OP_POSIX_QUERY_INFO:
510                         idata = in_iov[i].iov_base;
511                         if (rc == 0 && cfile && cfile->symlink_target) {
512                                 idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
513                                 if (!idata->symlink_target)
514                                         rc = -ENOMEM;
515                         }
516                         if (rc == 0) {
517                                 qi_rsp = (struct smb2_query_info_rsp *)
518                                         rsp_iov[i + 1].iov_base;
519                                 rc = smb2_validate_and_copy_iov(
520                                         le16_to_cpu(qi_rsp->OutputBufferOffset),
521                                         le32_to_cpu(qi_rsp->OutputBufferLength),
522                                         &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
523                                         (char *)&idata->posix_fi);
524                         }
525                         if (rc == 0)
526                                 rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
527
528                         SMB2_query_info_free(&rqst[num_rqst++]);
529                         if (rc)
530                                 trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,
531                                                                          tcon->tid, rc);
532                         else
533                                 trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
534                                                                           tcon->tid);
535                         break;
536                 case SMB2_OP_DELETE:
537                         if (rc)
538                                 trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
539                         else
540                                 trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
541                         break;
542                 case SMB2_OP_MKDIR:
543                         if (rc)
544                                 trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
545                         else
546                                 trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
547                         break;
548                 case SMB2_OP_HARDLINK:
549                         if (rc)
550                                 trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
551                         else
552                                 trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
553                         SMB2_set_info_free(&rqst[num_rqst++]);
554                         break;
555                 case SMB2_OP_RENAME:
556                         if (rc)
557                                 trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
558                         else
559                                 trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
560                         SMB2_set_info_free(&rqst[num_rqst++]);
561                         break;
562                 case SMB2_OP_RMDIR:
563                         if (rc)
564                                 trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
565                         else
566                                 trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
567                         SMB2_set_info_free(&rqst[num_rqst++]);
568                         break;
569                 case SMB2_OP_SET_EOF:
570                         if (rc)
571                                 trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
572                         else
573                                 trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
574                         SMB2_set_info_free(&rqst[num_rqst++]);
575                         break;
576                 case SMB2_OP_SET_INFO:
577                         if (rc)
578                                 trace_smb3_set_info_compound_err(xid,  ses->Suid,
579                                                                  tcon->tid, rc);
580                         else
581                                 trace_smb3_set_info_compound_done(xid, ses->Suid,
582                                                                   tcon->tid);
583                         SMB2_set_info_free(&rqst[num_rqst++]);
584                         break;
585                 case SMB2_OP_SET_REPARSE:
586                         if (rc) {
587                                 trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
588                                                                     tcon->tid, rc);
589                         } else {
590                                 trace_smb3_set_reparse_compound_done(xid, ses->Suid,
591                                                                      tcon->tid);
592                         }
593                         SMB2_ioctl_free(&rqst[num_rqst++]);
594                         break;
595                 case SMB2_OP_GET_REPARSE:
596                         if (!rc) {
597                                 iov = &rsp_iov[i + 1];
598                                 idata = in_iov[i].iov_base;
599                                 idata->reparse.io.iov = *iov;
600                                 idata->reparse.io.buftype = resp_buftype[i + 1];
601                                 rbuf = reparse_buf_ptr(iov);
602                                 if (IS_ERR(rbuf)) {
603                                         rc = PTR_ERR(rbuf);
604                                         trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
605                                                                             tcon->tid, rc);
606                                 } else {
607                                         idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
608                                         trace_smb3_set_reparse_compound_done(xid, ses->Suid,
609                                                                              tcon->tid);
610                                 }
611                                 memset(iov, 0, sizeof(*iov));
612                                 resp_buftype[i + 1] = CIFS_NO_BUFFER;
613                         } else {
614                                 trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
615                                                                     tcon->tid, rc);
616                         }
617                         SMB2_ioctl_free(&rqst[num_rqst++]);
618                         break;
619                 }
620         }
621         SMB2_close_free(&rqst[num_rqst]);
622
623         if (cfile)
624                 cifsFileInfo_put(cfile);
625
626         num_cmds += 2;
627         if (out_iov && out_buftype) {
628                 memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
629                 memcpy(out_buftype, resp_buftype,
630                        num_cmds * sizeof(*out_buftype));
631         } else {
632                 for (i = 0; i < num_cmds; i++)
633                         free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
634         }
635         kfree(vars);
636         return rc;
637 }
638
639 static int parse_create_response(struct cifs_open_info_data *data,
640                                  struct cifs_sb_info *cifs_sb,
641                                  const struct kvec *iov)
642 {
643         struct smb2_create_rsp *rsp = iov->iov_base;
644         bool reparse_point = false;
645         u32 tag = 0;
646         int rc = 0;
647
648         switch (rsp->hdr.Status) {
649         case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
650                 reparse_point = true;
651                 break;
652         case STATUS_STOPPED_ON_SYMLINK:
653                 rc = smb2_parse_symlink_response(cifs_sb, iov,
654                                                  &data->symlink_target);
655                 if (rc)
656                         return rc;
657                 tag = IO_REPARSE_TAG_SYMLINK;
658                 reparse_point = true;
659                 break;
660         case STATUS_SUCCESS:
661                 reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
662                 break;
663         }
664         data->reparse_point = reparse_point;
665         data->reparse.tag = tag;
666         return rc;
667 }
668
669 int smb2_query_path_info(const unsigned int xid,
670                          struct cifs_tcon *tcon,
671                          struct cifs_sb_info *cifs_sb,
672                          const char *full_path,
673                          struct cifs_open_info_data *data)
674 {
675         __u32 create_options = 0;
676         struct cifsFileInfo *cfile;
677         struct cached_fid *cfid = NULL;
678         struct smb2_hdr *hdr;
679         struct kvec in_iov[2], out_iov[3] = {};
680         int out_buftype[3] = {};
681         int cmds[2];
682         bool islink;
683         int i, num_cmds;
684         int rc, rc2;
685
686         data->adjust_tz = false;
687         data->reparse_point = false;
688
689         /*
690          * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
691          * Create SMB2_query_posix_info worker function to do non-compounded
692          * query when we already have an open file handle for this. For now this
693          * is fast enough (always using the compounded version).
694          */
695         if (!tcon->posix_extensions) {
696                 if (*full_path) {
697                         rc = -ENOENT;
698                 } else {
699                         rc = open_cached_dir(xid, tcon, full_path,
700                                              cifs_sb, false, &cfid);
701                 }
702                 /* If it is a root and its handle is cached then use it */
703                 if (!rc) {
704                         if (cfid->file_all_info_is_valid) {
705                                 memcpy(&data->fi, &cfid->file_all_info,
706                                        sizeof(data->fi));
707                         } else {
708                                 rc = SMB2_query_info(xid, tcon,
709                                                      cfid->fid.persistent_fid,
710                                                      cfid->fid.volatile_fid,
711                                                      &data->fi);
712                         }
713                         close_cached_dir(cfid);
714                         return rc;
715                 }
716                 cmds[0] = SMB2_OP_QUERY_INFO;
717         } else {
718                 cmds[0] = SMB2_OP_POSIX_QUERY_INFO;
719         }
720
721         in_iov[0].iov_base = data;
722         in_iov[0].iov_len = sizeof(*data);
723         in_iov[1] = in_iov[0];
724
725         cifs_get_readable_path(tcon, full_path, &cfile);
726         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
727                               FILE_READ_ATTRIBUTES, FILE_OPEN,
728                               create_options, ACL_NO_MODE, in_iov,
729                               cmds, 1, cfile, out_iov, out_buftype);
730         hdr = out_iov[0].iov_base;
731         /*
732          * If first iov is unset, then SMB session was dropped or we've got a
733          * cached open file (@cfile).
734          */
735         if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
736                 goto out;
737
738         switch (rc) {
739         case 0:
740         case -EOPNOTSUPP:
741                 /*
742                  * BB TODO: When support for special files added to Samba
743                  * re-verify this path.
744                  */
745                 rc = parse_create_response(data, cifs_sb, &out_iov[0]);
746                 if (rc || !data->reparse_point)
747                         goto out;
748
749                 if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
750                         /* symlink already parsed in create response */
751                         num_cmds = 1;
752                 } else {
753                         cmds[1] = SMB2_OP_GET_REPARSE;
754                         num_cmds = 2;
755                 }
756                 create_options |= OPEN_REPARSE_POINT;
757                 cifs_get_readable_path(tcon, full_path, &cfile);
758                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
759                                       FILE_READ_ATTRIBUTES, FILE_OPEN,
760                                       create_options, ACL_NO_MODE, in_iov,
761                                       cmds, num_cmds, cfile, NULL, NULL);
762                 break;
763         case -EREMOTE:
764                 break;
765         default:
766                 if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
767                         break;
768                 rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
769                                                      full_path, &islink);
770                 if (rc2) {
771                         rc = rc2;
772                         goto out;
773                 }
774                 if (islink)
775                         rc = -EREMOTE;
776         }
777
778 out:
779         for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
780                 free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
781         return rc;
782 }
783
784 int
785 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
786            struct cifs_tcon *tcon, const char *name,
787            struct cifs_sb_info *cifs_sb)
788 {
789         return smb2_compound_op(xid, tcon, cifs_sb, name,
790                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
791                                 CREATE_NOT_FILE, mode,
792                                 NULL, &(int){SMB2_OP_MKDIR}, 1,
793                                 NULL, NULL, NULL);
794 }
795
796 void
797 smb2_mkdir_setinfo(struct inode *inode, const char *name,
798                    struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
799                    const unsigned int xid)
800 {
801         FILE_BASIC_INFO data = {};
802         struct cifsInodeInfo *cifs_i;
803         struct cifsFileInfo *cfile;
804         struct kvec in_iov;
805         u32 dosattrs;
806         int tmprc;
807
808         in_iov.iov_base = &data;
809         in_iov.iov_len = sizeof(data);
810         cifs_i = CIFS_I(inode);
811         dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
812         data.Attributes = cpu_to_le32(dosattrs);
813         cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
814         tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
815                                  FILE_WRITE_ATTRIBUTES, FILE_CREATE,
816                                  CREATE_NOT_FILE, ACL_NO_MODE, &in_iov,
817                                  &(int){SMB2_OP_SET_INFO}, 1,
818                                  cfile, NULL, NULL);
819         if (tmprc == 0)
820                 cifs_i->cifsAttrs = dosattrs;
821 }
822
823 int
824 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
825            struct cifs_sb_info *cifs_sb)
826 {
827         drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
828         return smb2_compound_op(xid, tcon, cifs_sb, name,
829                                 DELETE, FILE_OPEN, CREATE_NOT_FILE,
830                                 ACL_NO_MODE, NULL,
831                                 &(int){SMB2_OP_RMDIR}, 1,
832                                 NULL, NULL, NULL);
833 }
834
835 int
836 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
837             struct cifs_sb_info *cifs_sb)
838 {
839         return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
840                                 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
841                                 ACL_NO_MODE, NULL,
842                                 &(int){SMB2_OP_DELETE}, 1,
843                                 NULL, NULL, NULL);
844 }
845
846 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
847                               const char *from_name, const char *to_name,
848                               struct cifs_sb_info *cifs_sb,
849                               __u32 create_options, __u32 access,
850                               int command, struct cifsFileInfo *cfile)
851 {
852         struct kvec in_iov;
853         __le16 *smb2_to_name = NULL;
854         int rc;
855
856         smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
857         if (smb2_to_name == NULL) {
858                 rc = -ENOMEM;
859                 goto smb2_rename_path;
860         }
861         in_iov.iov_base = smb2_to_name;
862         in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
863         rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
864                               FILE_OPEN, create_options, ACL_NO_MODE,
865                               &in_iov, &command, 1, cfile, NULL, NULL);
866 smb2_rename_path:
867         kfree(smb2_to_name);
868         return rc;
869 }
870
871 int smb2_rename_path(const unsigned int xid,
872                      struct cifs_tcon *tcon,
873                      struct dentry *source_dentry,
874                      const char *from_name, const char *to_name,
875                      struct cifs_sb_info *cifs_sb)
876 {
877         struct cifsFileInfo *cfile;
878         __u32 co = file_create_options(source_dentry);
879
880         drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
881         cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
882
883         return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
884                                   co, DELETE, SMB2_OP_RENAME, cfile);
885 }
886
887 int smb2_create_hardlink(const unsigned int xid,
888                          struct cifs_tcon *tcon,
889                          struct dentry *source_dentry,
890                          const char *from_name, const char *to_name,
891                          struct cifs_sb_info *cifs_sb)
892 {
893         __u32 co = file_create_options(source_dentry);
894
895         return smb2_set_path_attr(xid, tcon, from_name, to_name,
896                                   cifs_sb, co, FILE_READ_ATTRIBUTES,
897                                   SMB2_OP_HARDLINK, NULL);
898 }
899
900 int
901 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
902                    const char *full_path, __u64 size,
903                    struct cifs_sb_info *cifs_sb, bool set_alloc)
904 {
905         struct cifsFileInfo *cfile;
906         struct kvec in_iov;
907         __le64 eof = cpu_to_le64(size);
908
909         in_iov.iov_base = &eof;
910         in_iov.iov_len = sizeof(eof);
911         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
912         return smb2_compound_op(xid, tcon, cifs_sb, full_path,
913                                 FILE_WRITE_DATA, FILE_OPEN,
914                                 0, ACL_NO_MODE, &in_iov,
915                                 &(int){SMB2_OP_SET_EOF}, 1,
916                                 cfile, NULL, NULL);
917 }
918
919 int
920 smb2_set_file_info(struct inode *inode, const char *full_path,
921                    FILE_BASIC_INFO *buf, const unsigned int xid)
922 {
923         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
924         struct tcon_link *tlink;
925         struct cifs_tcon *tcon;
926         struct cifsFileInfo *cfile;
927         struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
928         int rc;
929
930         if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
931             (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
932             (buf->Attributes == 0))
933                 return 0; /* would be a no op, no sense sending this */
934
935         tlink = cifs_sb_tlink(cifs_sb);
936         if (IS_ERR(tlink))
937                 return PTR_ERR(tlink);
938         tcon = tlink_tcon(tlink);
939
940         cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
941         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
942                               FILE_WRITE_ATTRIBUTES, FILE_OPEN,
943                               0, ACL_NO_MODE, &in_iov,
944                               &(int){SMB2_OP_SET_INFO}, 1,
945                               cfile, NULL, NULL);
946         cifs_put_tlink(tlink);
947         return rc;
948 }
949
950 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
951                                      struct super_block *sb,
952                                      const unsigned int xid,
953                                      struct cifs_tcon *tcon,
954                                      const char *full_path,
955                                      struct kvec *iov)
956 {
957         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
958         struct cifsFileInfo *cfile;
959         struct inode *new = NULL;
960         struct kvec in_iov[2];
961         int cmds[2];
962         int da, co, cd;
963         int rc;
964
965         da = SYNCHRONIZE | DELETE |
966                 FILE_READ_ATTRIBUTES |
967                 FILE_WRITE_ATTRIBUTES;
968         co = CREATE_NOT_DIR | OPEN_REPARSE_POINT;
969         cd = FILE_CREATE;
970         cmds[0] = SMB2_OP_SET_REPARSE;
971         in_iov[0] = *iov;
972         in_iov[1].iov_base = data;
973         in_iov[1].iov_len = sizeof(*data);
974
975         if (tcon->posix_extensions) {
976                 cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
977                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
978                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
979                                       da, cd, co, ACL_NO_MODE, in_iov,
980                                       cmds, 2, cfile, NULL, NULL);
981                 if (!rc) {
982                         rc = smb311_posix_get_inode_info(&new, full_path,
983                                                          data, sb, xid);
984                 }
985         } else {
986                 cmds[1] = SMB2_OP_QUERY_INFO;
987                 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
988                 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
989                                       da, cd, co, ACL_NO_MODE, in_iov,
990                                       cmds, 2, cfile, NULL, NULL);
991                 if (!rc) {
992                         rc = cifs_get_inode_info(&new, full_path,
993                                                  data, sb, xid, NULL);
994                 }
995         }
996         return rc ? ERR_PTR(rc) : new;
997 }
998
999 int smb2_query_reparse_point(const unsigned int xid,
1000                              struct cifs_tcon *tcon,
1001                              struct cifs_sb_info *cifs_sb,
1002                              const char *full_path,
1003                              u32 *tag, struct kvec *rsp,
1004                              int *rsp_buftype)
1005 {
1006         struct cifs_open_info_data data = {};
1007         struct cifsFileInfo *cfile;
1008         struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1009         int rc;
1010
1011         cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1012
1013         cifs_get_readable_path(tcon, full_path, &cfile);
1014         rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1015                               FILE_READ_ATTRIBUTES, FILE_OPEN,
1016                               OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
1017                               &(int){SMB2_OP_GET_REPARSE}, 1,
1018                               cfile, NULL, NULL);
1019         if (rc)
1020                 goto out;
1021
1022         *tag = data.reparse.tag;
1023         *rsp = data.reparse.io.iov;
1024         *rsp_buftype = data.reparse.io.buftype;
1025         memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1026         data.reparse.io.buftype = CIFS_NO_BUFFER;
1027 out:
1028         cifs_free_open_info(&data);
1029         return rc;
1030 }