diff options
author | Steve French <sfrench@us.ibm.com> | 2009-02-23 15:43:11 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-03-11 21:36:20 -0400 |
commit | 7fc8f4e95bf9564045985bb206af8e28a5e4e28f (patch) | |
tree | e2a7229e18132fe86c66bb3e06436e537dd28535 /fs/cifs/file.c | |
parent | be652445fdccb8e5d4391928c3b45324ea37f9e1 (diff) |
[CIFS] reopen file via newer posix open protocol operation if available
If the network connection crashes, and we have to reopen files, preferentially
use the newer cifs posix open protocol operation if the server supports it.
Signed-off-by: Steve French <sfrench@us.ibm.com>
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; |