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