diff options
author | Steve French <sfrench@us.ibm.com> | 2008-03-14 18:37:16 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-03-14 18:37:16 -0400 |
commit | 8b1327f6ed957030a64ccdb17131955bfea2d3fe (patch) | |
tree | 075ff00b4c333ef333aff5927eac45bde16d8d53 | |
parent | ebe8912be214662c8289977fb416c1f015df4a0b (diff) |
[CIFS] file create with acl support enabled is slow
Shirish Pargaonkar noted:
With cifsacl mount option, when a file is created on the Windows server,
exclusive oplock is broken right away because the get cifs acl code
again opens the file to obtain security descriptor.
The client does not have the newly created file handle or inode in any
of its lists yet so it does not respond to oplock break and server waits for
its duration and then responds to the second open. This slows down file
creation signficantly. The fix is to pass the file descriptor to the get
cifsacl code wherever available so that get cifs acl code does not send
second open (NT Create ANDX) and oplock is not broken.
CC: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifsacl.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/dir.c | 5 | ||||
-rw-r--r-- | fs/cifs/file.c | 4 | ||||
-rw-r--r-- | fs/cifs/inode.c | 11 | ||||
-rw-r--r-- | fs/cifs/link.c | 2 |
6 files changed, 30 insertions, 22 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index f93932c21772..1f5a4289b848 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifsacl.c | 2 | * fs/cifs/cifsacl.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2007 | 4 | * Copyright (C) International Business Machines Corp., 2007,2008 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * Contains the routines for mapping CIFS/NTFS ACLs | 7 | * Contains the routines for mapping CIFS/NTFS ACLs |
@@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
556 | 556 | ||
557 | /* Retrieve an ACL from the server */ | 557 | /* Retrieve an ACL from the server */ |
558 | static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, | 558 | static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, |
559 | const char *path) | 559 | const char *path, const __u16 *pfid) |
560 | { | 560 | { |
561 | struct cifsFileInfo *open_file; | 561 | struct cifsFileInfo *open_file = NULL; |
562 | int unlock_file = FALSE; | 562 | int unlock_file = FALSE; |
563 | int xid; | 563 | int xid; |
564 | int rc = -EIO; | 564 | int rc = -EIO; |
@@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, | |||
573 | return NULL; | 573 | return NULL; |
574 | 574 | ||
575 | xid = GetXid(); | 575 | xid = GetXid(); |
576 | open_file = find_readable_file(CIFS_I(inode)); | 576 | if (pfid == NULL) |
577 | open_file = find_readable_file(CIFS_I(inode)); | ||
578 | else | ||
579 | fid = *pfid; | ||
580 | |||
577 | sb = inode->i_sb; | 581 | sb = inode->i_sb; |
578 | if (sb == NULL) { | 582 | if (sb == NULL) { |
579 | FreeXid(xid); | 583 | FreeXid(xid); |
@@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, | |||
584 | if (open_file) { | 588 | if (open_file) { |
585 | unlock_file = TRUE; | 589 | unlock_file = TRUE; |
586 | fid = open_file->netfid; | 590 | fid = open_file->netfid; |
587 | } else { | 591 | } else if (pfid == NULL) { |
588 | int oplock = FALSE; | 592 | int oplock = FALSE; |
589 | /* open file */ | 593 | /* open file */ |
590 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, | 594 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, |
@@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, | |||
600 | 604 | ||
601 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); | 605 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); |
602 | cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); | 606 | cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); |
603 | if (unlock_file == TRUE) | 607 | if (unlock_file == TRUE) /* find_readable_file increments ref count */ |
604 | atomic_dec(&open_file->wrtPending); | 608 | atomic_dec(&open_file->wrtPending); |
605 | else | 609 | else if (pfid == NULL) /* if opened above we have to close the handle */ |
606 | CIFSSMBClose(xid, cifs_sb->tcon, fid); | 610 | CIFSSMBClose(xid, cifs_sb->tcon, fid); |
611 | /* else handle was passed in by caller */ | ||
607 | 612 | ||
608 | FreeXid(xid); | 613 | FreeXid(xid); |
609 | return pntsd; | 614 | return pntsd; |
@@ -664,14 +669,14 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
664 | } | 669 | } |
665 | 670 | ||
666 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 671 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
667 | void acl_to_uid_mode(struct inode *inode, const char *path) | 672 | void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid) |
668 | { | 673 | { |
669 | struct cifs_ntsd *pntsd = NULL; | 674 | struct cifs_ntsd *pntsd = NULL; |
670 | u32 acllen = 0; | 675 | u32 acllen = 0; |
671 | int rc = 0; | 676 | int rc = 0; |
672 | 677 | ||
673 | cFYI(DBG2, ("converting ACL to mode for %s", path)); | 678 | cFYI(DBG2, ("converting ACL to mode for %s", path)); |
674 | pntsd = get_cifs_acl(&acllen, inode, path); | 679 | pntsd = get_cifs_acl(&acllen, inode, path, pfid); |
675 | 680 | ||
676 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 681 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
677 | if (pntsd) | 682 | if (pntsd) |
@@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
694 | cFYI(DBG2, ("set ACL from mode for %s", path)); | 699 | cFYI(DBG2, ("set ACL from mode for %s", path)); |
695 | 700 | ||
696 | /* Get the security descriptor */ | 701 | /* Get the security descriptor */ |
697 | pntsd = get_cifs_acl(&acllen, inode, path); | 702 | pntsd = get_cifs_acl(&acllen, inode, path, NULL); |
698 | 703 | ||
699 | /* Add three ACEs for owner, group, everyone getting rid of | 704 | /* Add three ACEs for owner, group, everyone getting rid of |
700 | other ACEs as chmod disables ACEs and set the security descriptor */ | 705 | other ACEs as chmod disables ACEs and set the security descriptor */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index a0414bda587c..7e5e0e78cd72 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -92,11 +92,12 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); | |||
92 | extern int cifs_get_inode_info(struct inode **pinode, | 92 | extern int cifs_get_inode_info(struct inode **pinode, |
93 | const unsigned char *search_path, | 93 | const unsigned char *search_path, |
94 | FILE_ALL_INFO * pfile_info, | 94 | FILE_ALL_INFO * pfile_info, |
95 | struct super_block *sb, int xid); | 95 | struct super_block *sb, int xid, const __u16 *pfid); |
96 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 96 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
97 | const unsigned char *search_path, | 97 | const unsigned char *search_path, |
98 | struct super_block *sb, int xid); | 98 | struct super_block *sb, int xid); |
99 | extern void acl_to_uid_mode(struct inode *inode, const char *search_path); | 99 | extern void acl_to_uid_mode(struct inode *inode, const char *path, |
100 | const __u16 *pfid); | ||
100 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); | 101 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); |
101 | 102 | ||
102 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 103 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4e83b47c4b34..0f5c62ba4038 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
229 | inode->i_sb, xid); | 229 | inode->i_sb, xid); |
230 | else { | 230 | else { |
231 | rc = cifs_get_inode_info(&newinode, full_path, | 231 | rc = cifs_get_inode_info(&newinode, full_path, |
232 | buf, inode->i_sb, xid); | 232 | buf, inode->i_sb, xid, |
233 | &fileHandle); | ||
233 | if (newinode) { | 234 | if (newinode) { |
234 | newinode->i_mode = mode; | 235 | newinode->i_mode = mode; |
235 | if ((oplock & CIFS_CREATE_ACTION) && | 236 | if ((oplock & CIFS_CREATE_ACTION) && |
@@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
483 | parent_dir_inode->i_sb, xid); | 484 | parent_dir_inode->i_sb, xid); |
484 | else | 485 | else |
485 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | 486 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
486 | parent_dir_inode->i_sb, xid); | 487 | parent_dir_inode->i_sb, xid, NULL); |
487 | 488 | ||
488 | if ((rc == 0) && (newInode != NULL)) { | 489 | if ((rc == 0) && (newInode != NULL)) { |
489 | if (pTcon->nocase) | 490 | if (pTcon->nocase) |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index fa849c91d323..40b690073fc1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -145,7 +145,7 @@ client_can_cache: | |||
145 | full_path, inode->i_sb, xid); | 145 | full_path, inode->i_sb, xid); |
146 | else | 146 | else |
147 | rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, | 147 | rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, |
148 | full_path, buf, inode->i_sb, xid); | 148 | full_path, buf, inode->i_sb, xid, NULL); |
149 | 149 | ||
150 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 150 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { |
151 | pCifsInode->clientCanCacheAll = TRUE; | 151 | pCifsInode->clientCanCacheAll = TRUE; |
@@ -440,7 +440,7 @@ reopen_error_exit: | |||
440 | else | 440 | else |
441 | rc = cifs_get_inode_info(&inode, | 441 | rc = cifs_get_inode_info(&inode, |
442 | full_path, NULL, inode->i_sb, | 442 | full_path, NULL, inode->i_sb, |
443 | xid); | 443 | xid, NULL); |
444 | } /* else we are writing out data to server already | 444 | } /* else we are writing out data to server already |
445 | and could deadlock if we tried to flush data, and | 445 | and could deadlock if we tried to flush data, and |
446 | since we do not know if we have data that would | 446 | since we do not know if we have data that would |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index e57e5c46ad48..7e4c24491729 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -371,7 +371,7 @@ static int get_sfu_mode(struct inode *inode, | |||
371 | 371 | ||
372 | int cifs_get_inode_info(struct inode **pinode, | 372 | int cifs_get_inode_info(struct inode **pinode, |
373 | const unsigned char *search_path, FILE_ALL_INFO *pfindData, | 373 | const unsigned char *search_path, FILE_ALL_INFO *pfindData, |
374 | struct super_block *sb, int xid) | 374 | struct super_block *sb, int xid, const __u16 *pfid) |
375 | { | 375 | { |
376 | int rc = 0; | 376 | int rc = 0; |
377 | struct cifsTconInfo *pTcon; | 377 | struct cifsTconInfo *pTcon; |
@@ -569,7 +569,7 @@ try_again_CIFSSMBQPathInfo: | |||
569 | /* fill in 0777 bits from ACL */ | 569 | /* fill in 0777 bits from ACL */ |
570 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 570 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
571 | cFYI(1, ("Getting mode bits from ACL")); | 571 | cFYI(1, ("Getting mode bits from ACL")); |
572 | acl_to_uid_mode(inode, search_path); | 572 | acl_to_uid_mode(inode, search_path, pfid); |
573 | } | 573 | } |
574 | #endif | 574 | #endif |
575 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | 575 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
@@ -616,7 +616,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
616 | if (cifs_sb->tcon->unix_ext) | 616 | if (cifs_sb->tcon->unix_ext) |
617 | rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); | 617 | rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); |
618 | else | 618 | else |
619 | rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); | 619 | rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid, |
620 | NULL); | ||
620 | if (rc && cifs_sb->tcon->ipc) { | 621 | if (rc && cifs_sb->tcon->ipc) { |
621 | cFYI(1, ("ipc connection - fake read inode")); | 622 | cFYI(1, ("ipc connection - fake read inode")); |
622 | inode->i_mode |= S_IFDIR; | 623 | inode->i_mode |= S_IFDIR; |
@@ -949,7 +950,7 @@ mkdir_get_info: | |||
949 | inode->i_sb, xid); | 950 | inode->i_sb, xid); |
950 | else | 951 | else |
951 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 952 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
952 | inode->i_sb, xid); | 953 | inode->i_sb, xid, NULL); |
953 | 954 | ||
954 | if (pTcon->nocase) | 955 | if (pTcon->nocase) |
955 | direntry->d_op = &cifs_ci_dentry_ops; | 956 | direntry->d_op = &cifs_ci_dentry_ops; |
@@ -1231,7 +1232,7 @@ int cifs_revalidate(struct dentry *direntry) | |||
1231 | } | 1232 | } |
1232 | } else { | 1233 | } else { |
1233 | rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, | 1234 | rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, |
1234 | direntry->d_sb, xid); | 1235 | direntry->d_sb, xid, NULL); |
1235 | if (rc) { | 1236 | if (rc) { |
1236 | cFYI(1, ("error on getting revalidate info %d", rc)); | 1237 | cFYI(1, ("error on getting revalidate info %d", rc)); |
1237 | /* if (rc != -ENOENT) | 1238 | /* if (rc != -ENOENT) |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1d6fb01b8e6d..d4e7ec93285f 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -205,7 +205,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
205 | inode->i_sb, xid); | 205 | inode->i_sb, xid); |
206 | else | 206 | else |
207 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 207 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
208 | inode->i_sb, xid); | 208 | inode->i_sb, xid, NULL); |
209 | 209 | ||
210 | if (rc != 0) { | 210 | if (rc != 0) { |
211 | cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", | 211 | cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", |