aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsproto.h3
-rw-r--r--fs/cifs/dir.c6
-rw-r--r--fs/cifs/file.c57
3 files changed, 58 insertions, 8 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 596fc8689371..a069e7bfd2d0 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -92,6 +92,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
92extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); 92extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
93extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); 93extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
94 94
95extern int cifs_posix_open(char *full_path, struct inode **pinode,
96 struct super_block *sb, int mode, int oflags,
97 int *poplock, __u16 *pnetfid, int xid);
95extern void posix_fill_in_inode(struct inode *tmp_inode, 98extern void posix_fill_in_inode(struct inode *tmp_inode,
96 FILE_UNIX_BASIC_INFO *pData, int isNewInode); 99 FILE_UNIX_BASIC_INFO *pData, int isNewInode);
97extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); 100extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 89fb72832652..f9b6f68be976 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -129,7 +129,7 @@ cifs_bp_rename_retry:
129 return full_path; 129 return full_path;
130} 130}
131 131
132static int cifs_posix_open(char *full_path, struct inode **pinode, 132int cifs_posix_open(char *full_path, struct inode **pinode,
133 struct super_block *sb, int mode, int oflags, 133 struct super_block *sb, int mode, int oflags,
134 int *poplock, __u16 *pnetfid, int xid) 134 int *poplock, __u16 *pnetfid, int xid)
135{ 135{
@@ -187,7 +187,9 @@ static int cifs_posix_open(char *full_path, struct inode **pinode,
187 if (!pinode) 187 if (!pinode)
188 goto posix_open_ret; /* caller does not need info */ 188 goto posix_open_ret; /* caller does not need info */
189 189
190 *pinode = cifs_new_inode(sb, &presp_data->UniqueId); 190 if (*pinode == NULL)
191 *pinode = cifs_new_inode(sb, &presp_data->UniqueId);
192 /* else an inode was passed in. Update its info, don't create one */
191 193
192 /* We do not need to close the file if new_inode fails since 194 /* We do not need to close the file if new_inode fails since
193 the caller will retry qpathinfo as long as inode is null */ 195 the caller will retry qpathinfo as long as inode is null */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6411f5f65d72..6603cb4024fb 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -78,8 +78,36 @@ static inline int cifs_convert_flags(unsigned int flags)
78 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | 78 return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | 79 FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
80 FILE_READ_DATA); 80 FILE_READ_DATA);
81}
81 82
83static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
84{
85 fmode_t posix_flags = 0;
82 86
87 if ((flags & O_ACCMODE) == O_RDONLY)
88 posix_flags = FMODE_READ;
89 else if ((flags & O_ACCMODE) == O_WRONLY)
90 posix_flags = FMODE_WRITE;
91 else if ((flags & O_ACCMODE) == O_RDWR) {
92 /* GENERIC_ALL is too much permission to request
93 can cause unnecessary access denied on create */
94 /* return GENERIC_ALL; */
95 posix_flags = FMODE_READ | FMODE_WRITE;
96 }
97 /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
98 reopening a file. They had their effect on the original open */
99 if (flags & O_APPEND)
100 posix_flags |= (fmode_t)O_APPEND;
101 if (flags & O_SYNC)
102 posix_flags |= (fmode_t)O_SYNC;
103 if (flags & O_DIRECTORY)
104 posix_flags |= (fmode_t)O_DIRECTORY;
105 if (flags & O_NOFOLLOW)
106 posix_flags |= (fmode_t)O_NOFOLLOW;
107 if (flags & O_DIRECT)
108 posix_flags |= (fmode_t)O_DIRECT;
109
110 return posix_flags;
83} 111}
84 112
85static inline int cifs_get_disposition(unsigned int flags) 113static inline int cifs_get_disposition(unsigned int flags)
@@ -349,7 +377,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
349 int rc = -EACCES; 377 int rc = -EACCES;
350 int xid, oplock; 378 int xid, oplock;
351 struct cifs_sb_info *cifs_sb; 379 struct cifs_sb_info *cifs_sb;
352 struct cifsTconInfo *pTcon; 380 struct cifsTconInfo *tcon;
353 struct cifsFileInfo *pCifsFile; 381 struct cifsFileInfo *pCifsFile;
354 struct cifsInodeInfo *pCifsInode; 382 struct cifsInodeInfo *pCifsInode;
355 struct inode *inode; 383 struct inode *inode;
@@ -387,7 +415,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
387 } 415 }
388 416
389 cifs_sb = CIFS_SB(inode->i_sb); 417 cifs_sb = CIFS_SB(inode->i_sb);
390 pTcon = cifs_sb->tcon; 418 tcon = cifs_sb->tcon;
391 419
392/* can not grab rename sem here because various ops, including 420/* can not grab rename sem here because various ops, including
393 those that already have the rename sem can end up causing writepage 421 those that already have the rename sem can end up causing writepage
@@ -404,20 +432,37 @@ reopen_error_exit:
404 432
405 cFYI(1, ("inode = 0x%p file flags 0x%x for %s", 433 cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
406 inode, file->f_flags, full_path)); 434 inode, file->f_flags, full_path));
407 desiredAccess = cifs_convert_flags(file->f_flags);
408 435
409 if (oplockEnabled) 436 if (oplockEnabled)
410 oplock = REQ_OPLOCK; 437 oplock = REQ_OPLOCK;
411 else 438 else
412 oplock = 0; 439 oplock = 0;
413 440
441 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
442 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
443 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
444 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
445 /* can not refresh inode info since size could be stale */
446 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
447 cifs_sb->mnt_file_mode /* ignored */,
448 oflags, &oplock, &netfid, xid);
449 if (rc == 0) {
450 cFYI(1, ("posix reopen succeeded"));
451 goto reopen_success;
452 }
453 /* fallthrough to retry open the old way on errors, especially
454 in the reconnect path it is important to retry hard */
455 }
456
457 desiredAccess = cifs_convert_flags(file->f_flags);
458
414 /* Can not refresh inode by passing in file_info buf to be returned 459 /* Can not refresh inode by passing in file_info buf to be returned
415 by SMBOpen and then calling get_inode_info with returned buf 460 by SMBOpen and then calling get_inode_info with returned buf
416 since file might have write behind data that needs to be flushed 461 since file might have write behind data that needs to be flushed
417 and server version of file size can be stale. If we knew for sure 462 and server version of file size can be stale. If we knew for sure
418 that inode was not dirty locally we could do this */ 463 that inode was not dirty locally we could do this */
419 464
420 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, 465 rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
421 CREATE_NOT_DIR, &netfid, &oplock, NULL, 466 CREATE_NOT_DIR, &netfid, &oplock, NULL,
422 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 467 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
423 CIFS_MOUNT_MAP_SPECIAL_CHR); 468 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -426,6 +471,7 @@ reopen_error_exit:
426 cFYI(1, ("cifs_open returned 0x%x", rc)); 471 cFYI(1, ("cifs_open returned 0x%x", rc));
427 cFYI(1, ("oplock: %d", oplock)); 472 cFYI(1, ("oplock: %d", oplock));
428 } else { 473 } else {
474reopen_success:
429 pCifsFile->netfid = netfid; 475 pCifsFile->netfid = netfid;
430 pCifsFile->invalidHandle = false; 476 pCifsFile->invalidHandle = false;
431 up(&pCifsFile->fh_sem); 477 up(&pCifsFile->fh_sem);
@@ -439,7 +485,7 @@ reopen_error_exit:
439 go to server to get inode info */ 485 go to server to get inode info */
440 pCifsInode->clientCanCacheAll = false; 486 pCifsInode->clientCanCacheAll = false;
441 pCifsInode->clientCanCacheRead = false; 487 pCifsInode->clientCanCacheRead = false;
442 if (pTcon->unix_ext) 488 if (tcon->unix_ext)
443 rc = cifs_get_inode_info_unix(&inode, 489 rc = cifs_get_inode_info_unix(&inode,
444 full_path, inode->i_sb, xid); 490 full_path, inode->i_sb, xid);
445 else 491 else
@@ -467,7 +513,6 @@ reopen_error_exit:
467 cifs_relock_file(pCifsFile); 513 cifs_relock_file(pCifsFile);
468 } 514 }
469 } 515 }
470
471 kfree(full_path); 516 kfree(full_path);
472 FreeXid(xid); 517 FreeXid(xid);
473 return rc; 518 return rc;