aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorRonnie Sahlberg <lsahlber@redhat.com>2019-08-29 18:25:46 -0400
committerSteve French <stfrench@microsoft.com>2019-09-16 12:43:37 -0400
commit8de9e86c67baa71c661b9ba59a4e23210d98bc79 (patch)
treebbcca0ff9e4b61fbedbdfec6d28f04580506adf7 /fs/cifs
parent31ebdc11340abfdb02b7cdbfcc5531b7f479d58d (diff)
cifs: create a helper to find a writeable handle by path name
rename() takes a path for old_file and in SMB2 we used to just create a compound for create(old_path)/rename/close(). If we already have a writable handle we can avoid the create() and close() altogether and just use the existing handle. For this situation, as we avoid doing the create() we also avoid triggering an oplock break for the existing handle. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c35
-rw-r--r--fs/cifs/smb2inode.c94
4 files changed, 106 insertions, 27 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index dd75746e60cd..7b69037bed24 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -137,6 +137,8 @@ extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
137extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, 137extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
138 bool fsuid_only, 138 bool fsuid_only,
139 struct cifsFileInfo **ret_file); 139 struct cifsFileInfo **ret_file);
140extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
141 struct cifsFileInfo **ret_file);
140extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); 142extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
141extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server); 143extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
142extern int decode_negTokenInit(unsigned char *security_blob, int length, 144extern int decode_negTokenInit(unsigned char *security_blob, int length,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index be424e81e3ad..dd5ac841aefa 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -125,7 +125,7 @@ cifs_bp_rename_retry:
125 } 125 }
126 rcu_read_unlock(); 126 rcu_read_unlock();
127 127
128 full_path = kmalloc(namelen+1, GFP_KERNEL); 128 full_path = kmalloc(namelen+1, GFP_ATOMIC);
129 if (full_path == NULL) 129 if (full_path == NULL)
130 return full_path; 130 return full_path;
131 full_path[namelen] = 0; /* trailing null */ 131 full_path[namelen] = 0; /* trailing null */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f16f6d2b5217..6124b1d1ab05 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1973,6 +1973,41 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
1973 return cfile; 1973 return cfile;
1974} 1974}
1975 1975
1976int
1977cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
1978 struct cifsFileInfo **ret_file)
1979{
1980 struct list_head *tmp;
1981 struct cifsFileInfo *cfile;
1982 struct cifsInodeInfo *cinode;
1983 char *full_path;
1984
1985 *ret_file = NULL;
1986
1987 spin_lock(&tcon->open_file_lock);
1988 list_for_each(tmp, &tcon->openFileList) {
1989 cfile = list_entry(tmp, struct cifsFileInfo,
1990 tlist);
1991 full_path = build_path_from_dentry(cfile->dentry);
1992 if (full_path == NULL) {
1993 spin_unlock(&tcon->open_file_lock);
1994 return -ENOMEM;
1995 }
1996 if (strcmp(full_path, name)) {
1997 kfree(full_path);
1998 continue;
1999 }
2000
2001 kfree(full_path);
2002 cinode = CIFS_I(d_inode(cfile->dentry));
2003 spin_unlock(&tcon->open_file_lock);
2004 return cifs_get_writable_file(cinode, 0, ret_file);
2005 }
2006
2007 spin_unlock(&tcon->open_file_lock);
2008 return -ENOENT;
2009}
2010
1976static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) 2011static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1977{ 2012{
1978 struct address_space *mapping = page->mapping; 2013 struct address_space *mapping = page->mapping;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index d8d9cdfa30b6..939fc7b2234c 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -51,7 +51,8 @@ static int
51smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, 51smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
52 struct cifs_sb_info *cifs_sb, const char *full_path, 52 struct cifs_sb_info *cifs_sb, const char *full_path,
53 __u32 desired_access, __u32 create_disposition, 53 __u32 desired_access, __u32 create_disposition,
54 __u32 create_options, void *ptr, int command) 54 __u32 create_options, void *ptr, int command,
55 struct cifsFileInfo *cfile)
55{ 56{
56 int rc; 57 int rc;
57 __le16 *utf16_path = NULL; 58 __le16 *utf16_path = NULL;
@@ -83,10 +84,16 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
83 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; 84 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
84 memset(rsp_iov, 0, sizeof(rsp_iov)); 85 memset(rsp_iov, 0, sizeof(rsp_iov));
85 86
87 /* We already have a handle so we can skip the open */
88 if (cfile)
89 goto after_open;
90
86 /* Open */ 91 /* Open */
87 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 92 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
88 if (!utf16_path) 93 if (!utf16_path) {
89 return -ENOMEM; 94 rc = -ENOMEM;
95 goto finished;
96 }
90 97
91 oparms.tcon = tcon; 98 oparms.tcon = tcon;
92 oparms.desired_access = desired_access; 99 oparms.desired_access = desired_access;
@@ -106,7 +113,10 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
106 if (rc) 113 if (rc)
107 goto finished; 114 goto finished;
108 115
109 smb2_set_next_command(tcon, &rqst[num_rqst++]); 116 smb2_set_next_command(tcon, &rqst[num_rqst]);
117 after_open:
118 num_rqst++;
119 rc = 0;
110 120
111 /* Operation */ 121 /* Operation */
112 switch (command) { 122 switch (command) {
@@ -210,14 +220,23 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
210 size[1] = len + 2 /* null */; 220 size[1] = len + 2 /* null */;
211 data[1] = (__le16 *)ptr; 221 data[1] = (__le16 *)ptr;
212 222
213 rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID, 223 if (cfile)
214 COMPOUND_FID, current->tgid, 224 rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
215 FILE_RENAME_INFORMATION, 225 cfile->fid.persistent_fid,
226 cfile->fid.volatile_fid,
227 current->tgid, FILE_RENAME_INFORMATION,
228 SMB2_O_INFO_FILE, 0, data, size);
229 else {
230 rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
231 COMPOUND_FID, COMPOUND_FID,
232 current->tgid, FILE_RENAME_INFORMATION,
216 SMB2_O_INFO_FILE, 0, data, size); 233 SMB2_O_INFO_FILE, 0, data, size);
234 smb2_set_next_command(tcon, &rqst[num_rqst]);
235 smb2_set_related(&rqst[num_rqst]);
236 }
217 if (rc) 237 if (rc)
218 goto finished; 238 goto finished;
219 smb2_set_next_command(tcon, &rqst[num_rqst]); 239 num_rqst++;
220 smb2_set_related(&rqst[num_rqst++]);
221 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 240 trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
222 break; 241 break;
223 case SMB2_OP_HARDLINK: 242 case SMB2_OP_HARDLINK:
@@ -254,20 +273,36 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
254 if (rc) 273 if (rc)
255 goto finished; 274 goto finished;
256 275
276 /* We already have a handle so we can skip the close */
277 if (cfile)
278 goto after_close;
257 /* Close */ 279 /* Close */
258 memset(&close_iov, 0, sizeof(close_iov)); 280 memset(&close_iov, 0, sizeof(close_iov));
259 rqst[num_rqst].rq_iov = close_iov; 281 rqst[num_rqst].rq_iov = close_iov;
260 rqst[num_rqst].rq_nvec = 1; 282 rqst[num_rqst].rq_nvec = 1;
261 rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID, 283 rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
262 COMPOUND_FID); 284 COMPOUND_FID);
263 smb2_set_related(&rqst[num_rqst++]); 285 smb2_set_related(&rqst[num_rqst]);
264 if (rc) 286 if (rc)
265 goto finished; 287 goto finished;
266 288 after_close:
267 rc = compound_send_recv(xid, ses, flags, num_rqst, rqst, 289 num_rqst++;
268 resp_buftype, rsp_iov); 290
291 if (cfile) {
292 cifsFileInfo_put(cfile);
293 cfile = NULL;
294 rc = compound_send_recv(xid, ses, flags, num_rqst - 2,
295 &rqst[1], &resp_buftype[1],
296 &rsp_iov[1]);
297 } else
298 rc = compound_send_recv(xid, ses, flags, num_rqst,
299 rqst, resp_buftype,
300 rsp_iov);
269 301
270 finished: 302 finished:
303 if (cfile)
304 cifsFileInfo_put(cfile);
305
271 SMB2_open_free(&rqst[0]); 306 SMB2_open_free(&rqst[0]);
272 switch (command) { 307 switch (command) {
273 case SMB2_OP_QUERY_INFO: 308 case SMB2_OP_QUERY_INFO:
@@ -404,7 +439,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
404 439
405 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 440 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
406 FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, 441 FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
407 smb2_data, SMB2_OP_QUERY_INFO); 442 smb2_data, SMB2_OP_QUERY_INFO, NULL);
408 if (rc == -EOPNOTSUPP) { 443 if (rc == -EOPNOTSUPP) {
409 *symlink = true; 444 *symlink = true;
410 create_options |= OPEN_REPARSE_POINT; 445 create_options |= OPEN_REPARSE_POINT;
@@ -413,7 +448,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
413 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 448 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
414 FILE_READ_ATTRIBUTES, FILE_OPEN, 449 FILE_READ_ATTRIBUTES, FILE_OPEN,
415 create_options, smb2_data, 450 create_options, smb2_data,
416 SMB2_OP_QUERY_INFO); 451 SMB2_OP_QUERY_INFO, NULL);
417 } 452 }
418 if (rc) 453 if (rc)
419 goto out; 454 goto out;
@@ -430,7 +465,7 @@ smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
430{ 465{
431 return smb2_compound_op(xid, tcon, cifs_sb, name, 466 return smb2_compound_op(xid, tcon, cifs_sb, name,
432 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 467 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
433 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); 468 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR, NULL);
434} 469}
435 470
436void 471void
@@ -449,7 +484,8 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
449 data.Attributes = cpu_to_le32(dosattrs); 484 data.Attributes = cpu_to_le32(dosattrs);
450 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, 485 tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
451 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 486 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
452 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); 487 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO,
488 NULL);
453 if (tmprc == 0) 489 if (tmprc == 0)
454 cifs_i->cifsAttrs = dosattrs; 490 cifs_i->cifsAttrs = dosattrs;
455} 491}
@@ -460,7 +496,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
460{ 496{
461 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 497 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
462 CREATE_NOT_FILE, 498 CREATE_NOT_FILE,
463 NULL, SMB2_OP_RMDIR); 499 NULL, SMB2_OP_RMDIR, NULL);
464} 500}
465 501
466int 502int
@@ -469,13 +505,14 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
469{ 505{
470 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 506 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
471 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 507 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
472 NULL, SMB2_OP_DELETE); 508 NULL, SMB2_OP_DELETE, NULL);
473} 509}
474 510
475static int 511static int
476smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, 512smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
477 const char *from_name, const char *to_name, 513 const char *from_name, const char *to_name,
478 struct cifs_sb_info *cifs_sb, __u32 access, int command) 514 struct cifs_sb_info *cifs_sb, __u32 access, int command,
515 struct cifsFileInfo *cfile)
479{ 516{
480 __le16 *smb2_to_name = NULL; 517 __le16 *smb2_to_name = NULL;
481 int rc; 518 int rc;
@@ -486,7 +523,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
486 goto smb2_rename_path; 523 goto smb2_rename_path;
487 } 524 }
488 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 525 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
489 FILE_OPEN, 0, smb2_to_name, command); 526 FILE_OPEN, 0, smb2_to_name, command, cfile);
490smb2_rename_path: 527smb2_rename_path:
491 kfree(smb2_to_name); 528 kfree(smb2_to_name);
492 return rc; 529 return rc;
@@ -497,8 +534,12 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
497 const char *from_name, const char *to_name, 534 const char *from_name, const char *to_name,
498 struct cifs_sb_info *cifs_sb) 535 struct cifs_sb_info *cifs_sb)
499{ 536{
500 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 537 struct cifsFileInfo *cfile;
501 DELETE, SMB2_OP_RENAME); 538
539 cifs_get_writable_path(tcon, from_name, &cfile);
540
541 return smb2_set_path_attr(xid, tcon, from_name, to_name,
542 cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
502} 543}
503 544
504int 545int
@@ -507,7 +548,8 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
507 struct cifs_sb_info *cifs_sb) 548 struct cifs_sb_info *cifs_sb)
508{ 549{
509 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, 550 return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
510 FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK); 551 FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
552 NULL);
511} 553}
512 554
513int 555int
@@ -519,7 +561,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
519 561
520 return smb2_compound_op(xid, tcon, cifs_sb, full_path, 562 return smb2_compound_op(xid, tcon, cifs_sb, full_path,
521 FILE_WRITE_DATA, FILE_OPEN, 0, &eof, 563 FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
522 SMB2_OP_SET_EOF); 564 SMB2_OP_SET_EOF, NULL);
523} 565}
524 566
525int 567int
@@ -541,7 +583,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
541 583
542 rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path, 584 rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
543 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf, 585 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
544 SMB2_OP_SET_INFO); 586 SMB2_OP_SET_INFO, NULL);
545 cifs_put_tlink(tlink); 587 cifs_put_tlink(tlink);
546 return rc; 588 return rc;
547} 589}