[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>

+30 -22
+15 -10
fs/cifs/cifsacl.c
··· 1 1 /* 2 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 5 * Author(s): Steve French (sfrench@us.ibm.com) 6 6 * 7 7 * Contains the routines for mapping CIFS/NTFS ACLs ··· 556 556 557 557 /* Retrieve an ACL from the server */ 558 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 562 int unlock_file = FALSE; 563 563 int xid; 564 564 int rc = -EIO; ··· 573 573 return NULL; 574 574 575 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 581 sb = inode->i_sb; 578 582 if (sb == NULL) { 579 583 FreeXid(xid); ··· 588 584 if (open_file) { 589 585 unlock_file = TRUE; 590 586 fid = open_file->netfid; 591 - } else { 587 + } else if (pfid == NULL) { 592 588 int oplock = FALSE; 593 589 /* open file */ 594 590 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, ··· 604 600 605 601 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); 606 602 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); 607 - if (unlock_file == TRUE) 603 + if (unlock_file == TRUE) /* find_readable_file increments ref count */ 608 604 atomic_dec(&open_file->wrtPending); 609 - else 605 + else if (pfid == NULL) /* if opened above we have to close the handle */ 610 606 CIFSSMBClose(xid, cifs_sb->tcon, fid); 607 + /* else handle was passed in by caller */ 611 608 612 609 FreeXid(xid); 613 610 return pntsd; ··· 669 664 } 670 665 671 666 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ 672 - void acl_to_uid_mode(struct inode *inode, const char *path) 667 + void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid) 673 668 { 674 669 struct cifs_ntsd *pntsd = NULL; 675 670 u32 acllen = 0; 676 671 int rc = 0; 677 672 678 673 cFYI(DBG2, ("converting ACL to mode for %s", path)); 679 - pntsd = get_cifs_acl(&acllen, inode, path); 674 + pntsd = get_cifs_acl(&acllen, inode, path, pfid); 680 675 681 676 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ 682 677 if (pntsd) ··· 699 694 cFYI(DBG2, ("set ACL from mode for %s", path)); 700 695 701 696 /* Get the security descriptor */ 702 - pntsd = get_cifs_acl(&acllen, inode, path); 697 + pntsd = get_cifs_acl(&acllen, inode, path, NULL); 703 698 704 699 /* Add three ACEs for owner, group, everyone getting rid of 705 700 other ACEs as chmod disables ACEs and set the security descriptor */
+3 -2
fs/cifs/cifsproto.h
··· 92 92 extern int cifs_get_inode_info(struct inode **pinode, 93 93 const unsigned char *search_path, 94 94 FILE_ALL_INFO * pfile_info, 95 - struct super_block *sb, int xid); 95 + struct super_block *sb, int xid, const __u16 *pfid); 96 96 extern int cifs_get_inode_info_unix(struct inode **pinode, 97 97 const unsigned char *search_path, 98 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 101 extern int mode_to_acl(struct inode *inode, const char *path, __u64); 101 102 102 103 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
+3 -2
fs/cifs/dir.c
··· 229 229 inode->i_sb, xid); 230 230 else { 231 231 rc = cifs_get_inode_info(&newinode, full_path, 232 - buf, inode->i_sb, xid); 232 + buf, inode->i_sb, xid, 233 + &fileHandle); 233 234 if (newinode) { 234 235 newinode->i_mode = mode; 235 236 if ((oplock & CIFS_CREATE_ACTION) && ··· 484 483 parent_dir_inode->i_sb, xid); 485 484 else 486 485 rc = cifs_get_inode_info(&newInode, full_path, NULL, 487 - parent_dir_inode->i_sb, xid); 486 + parent_dir_inode->i_sb, xid, NULL); 488 487 489 488 if ((rc == 0) && (newInode != NULL)) { 490 489 if (pTcon->nocase)
+2 -2
fs/cifs/file.c
··· 145 145 full_path, inode->i_sb, xid); 146 146 else 147 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 150 if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { 151 151 pCifsInode->clientCanCacheAll = TRUE; ··· 440 440 else 441 441 rc = cifs_get_inode_info(&inode, 442 442 full_path, NULL, inode->i_sb, 443 - xid); 443 + xid, NULL); 444 444 } /* else we are writing out data to server already 445 445 and could deadlock if we tried to flush data, and 446 446 since we do not know if we have data that would
+6 -5
fs/cifs/inode.c
··· 371 371 372 372 int cifs_get_inode_info(struct inode **pinode, 373 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 376 int rc = 0; 377 377 struct cifsTconInfo *pTcon; ··· 569 569 /* fill in 0777 bits from ACL */ 570 570 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 571 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 574 #endif 575 575 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { ··· 616 616 if (cifs_sb->tcon->unix_ext) 617 617 rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); 618 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 621 if (rc && cifs_sb->tcon->ipc) { 621 622 cFYI(1, ("ipc connection - fake read inode")); 622 623 inode->i_mode |= S_IFDIR; ··· 950 949 inode->i_sb, xid); 951 950 else 952 951 rc = cifs_get_inode_info(&newinode, full_path, NULL, 953 - inode->i_sb, xid); 952 + inode->i_sb, xid, NULL); 954 953 955 954 if (pTcon->nocase) 956 955 direntry->d_op = &cifs_ci_dentry_ops; ··· 1232 1231 } 1233 1232 } else { 1234 1233 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, 1235 - direntry->d_sb, xid); 1234 + direntry->d_sb, xid, NULL); 1236 1235 if (rc) { 1237 1236 cFYI(1, ("error on getting revalidate info %d", rc)); 1238 1237 /* if (rc != -ENOENT)
+1 -1
fs/cifs/link.c
··· 205 205 inode->i_sb, xid); 206 206 else 207 207 rc = cifs_get_inode_info(&newinode, full_path, NULL, 208 - inode->i_sb, xid); 208 + inode->i_sb, xid, NULL); 209 209 210 210 if (rc != 0) { 211 211 cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",