diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 57 |
1 files changed, 51 insertions, 6 deletions
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 | ||
83 | static 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 | ||
85 | static inline int cifs_get_disposition(unsigned int flags) | 113 | static 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 { |
474 | reopen_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; |