diff options
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 461750e01364..3758965d73d5 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -225,6 +225,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
225 | if (!(oflags & FMODE_READ)) | 225 | if (!(oflags & FMODE_READ)) |
226 | write_only = true; | 226 | write_only = true; |
227 | 227 | ||
228 | mode &= ~current_umask(); | ||
228 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, | 229 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, |
229 | pnetfid, presp_data, &oplock, full_path, | 230 | pnetfid, presp_data, &oplock, full_path, |
230 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 231 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
@@ -281,6 +282,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
281 | int create_options = CREATE_NOT_DIR; | 282 | int create_options = CREATE_NOT_DIR; |
282 | int oplock = 0; | 283 | int oplock = 0; |
283 | int oflags; | 284 | int oflags; |
285 | bool posix_create = false; | ||
284 | /* | 286 | /* |
285 | * BB below access is probably too much for mknod to request | 287 | * BB below access is probably too much for mknod to request |
286 | * but we have to do query and setpathinfo so requesting | 288 | * but we have to do query and setpathinfo so requesting |
@@ -309,7 +311,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
309 | return -ENOMEM; | 311 | return -ENOMEM; |
310 | } | 312 | } |
311 | 313 | ||
312 | mode &= ~current_umask(); | ||
313 | if (oplockEnabled) | 314 | if (oplockEnabled) |
314 | oplock = REQ_OPLOCK; | 315 | oplock = REQ_OPLOCK; |
315 | 316 | ||
@@ -328,12 +329,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
328 | negotation. EREMOTE indicates DFS junction, which is not | 329 | negotation. EREMOTE indicates DFS junction, which is not |
329 | handled in posix open */ | 330 | handled in posix open */ |
330 | 331 | ||
331 | if ((rc == 0) && (newinode == NULL)) | 332 | if (rc == 0) { |
332 | goto cifs_create_get_file_info; /* query inode info */ | 333 | posix_create = true; |
333 | else if (rc == 0) /* success, no need to query */ | 334 | if (newinode == NULL) /* query inode info */ |
334 | goto cifs_create_set_dentry; | 335 | goto cifs_create_get_file_info; |
335 | else if ((rc != -EIO) && (rc != -EREMOTE) && | 336 | else /* success, no need to query */ |
336 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | 337 | goto cifs_create_set_dentry; |
338 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
339 | (rc != -EOPNOTSUPP) && (rc != -EINVAL)) | ||
337 | goto cifs_create_out; | 340 | goto cifs_create_out; |
338 | /* else fallthrough to retry, using older open call, this is | 341 | /* else fallthrough to retry, using older open call, this is |
339 | case where server does not support this SMB level, and | 342 | case where server does not support this SMB level, and |
@@ -464,7 +467,7 @@ cifs_create_set_dentry: | |||
464 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { | 467 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { |
465 | /* mknod case - do not leave file open */ | 468 | /* mknod case - do not leave file open */ |
466 | CIFSSMBClose(xid, tcon, fileHandle); | 469 | CIFSSMBClose(xid, tcon, fileHandle); |
467 | } else if (newinode) { | 470 | } else if (!(posix_create) && (newinode)) { |
468 | cifs_fill_fileinfo(newinode, fileHandle, | 471 | cifs_fill_fileinfo(newinode, fileHandle, |
469 | cifs_sb->tcon, write_only); | 472 | cifs_sb->tcon, write_only); |
470 | } | 473 | } |
@@ -606,7 +609,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
606 | int xid; | 609 | int xid; |
607 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 610 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
608 | int oplock = 0; | 611 | int oplock = 0; |
609 | int mode; | ||
610 | __u16 fileHandle = 0; | 612 | __u16 fileHandle = 0; |
611 | bool posix_open = false; | 613 | bool posix_open = false; |
612 | struct cifs_sb_info *cifs_sb; | 614 | struct cifs_sb_info *cifs_sb; |
@@ -655,30 +657,36 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
655 | } | 657 | } |
656 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); | 658 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); |
657 | 659 | ||
660 | /* Posix open is only called (at lookup time) for file create now. | ||
661 | * For opens (rather than creates), because we do not know if it | ||
662 | * is a file or directory yet, and current Samba no longer allows | ||
663 | * us to do posix open on dirs, we could end up wasting an open call | ||
664 | * on what turns out to be a dir. For file opens, we wait to call posix | ||
665 | * open till cifs_open. It could be added here (lookup) in the future | ||
666 | * but the performance tradeoff of the extra network request when EISDIR | ||
667 | * or EACCES is returned would have to be weighed against the 50% | ||
668 | * reduction in network traffic in the other paths. | ||
669 | */ | ||
658 | if (pTcon->unix_ext) { | 670 | if (pTcon->unix_ext) { |
659 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 671 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
660 | (nd->flags & LOOKUP_OPEN)) { | 672 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
661 | if (!((nd->intent.open.flags & O_CREAT) && | 673 | (nd->intent.open.flags & O_CREAT)) { |
662 | (nd->intent.open.flags & O_EXCL))) { | 674 | rc = cifs_posix_open(full_path, &newInode, |
663 | mode = nd->intent.open.create_mode & | 675 | parent_dir_inode->i_sb, |
664 | ~current_umask(); | 676 | nd->intent.open.create_mode, |
665 | rc = cifs_posix_open(full_path, &newInode, | ||
666 | parent_dir_inode->i_sb, mode, | ||
667 | nd->intent.open.flags, &oplock, | 677 | nd->intent.open.flags, &oplock, |
668 | &fileHandle, xid); | 678 | &fileHandle, xid); |
669 | /* | 679 | /* |
670 | * This code works around a bug in | 680 | * The check below works around a bug in POSIX |
671 | * samba posix open in samba versions 3.3.1 | 681 | * open in samba versions 3.3.1 and earlier where |
672 | * and earlier where create works | 682 | * open could incorrectly fail with invalid parameter. |
673 | * but open fails with invalid parameter. | 683 | * If either that or op not supported returned, follow |
674 | * If either of these error codes are | 684 | * the normal lookup. |
675 | * returned, follow the normal lookup. | 685 | */ |
676 | * Otherwise, the error during posix open | 686 | if ((rc == 0) || (rc == -ENOENT)) |
677 | * is handled. | 687 | posix_open = true; |
678 | */ | 688 | else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP)) |
679 | if ((rc != -EINVAL) && (rc != -EOPNOTSUPP)) | 689 | pTcon->broken_posix_open = true; |
680 | posix_open = true; | ||
681 | } | ||
682 | } | 690 | } |
683 | if (!posix_open) | 691 | if (!posix_open) |
684 | rc = cifs_get_inode_info_unix(&newInode, full_path, | 692 | rc = cifs_get_inode_info_unix(&newInode, full_path, |