aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-03-14 18:37:16 -0400
committerSteve French <sfrench@us.ibm.com>2008-03-14 18:37:16 -0400
commit8b1327f6ed957030a64ccdb17131955bfea2d3fe (patch)
tree075ff00b4c333ef333aff5927eac45bde16d8d53
parentebe8912be214662c8289977fb416c1f015df4a0b (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.c25
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/dir.c5
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/cifs/inode.c11
-rw-r--r--fs/cifs/link.c2
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 */
558static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, 558static 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 */
667void acl_to_uid_mode(struct inode *inode, const char *path) 672void 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);
92extern int cifs_get_inode_info(struct inode **pinode, 92extern 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);
96extern int cifs_get_inode_info_unix(struct inode **pinode, 96extern 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);
99extern void acl_to_uid_mode(struct inode *inode, const char *search_path); 99extern void acl_to_uid_mode(struct inode *inode, const char *path,
100 const __u16 *pfid);
100extern int mode_to_acl(struct inode *inode, const char *path, __u64); 101extern int mode_to_acl(struct inode *inode, const char *path, __u64);
101 102
102extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 103extern 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
372int cifs_get_inode_info(struct inode **pinode, 372int 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",