[CIFS] Add support for posix open during lookup

This patch by utilizing lookup intents, and thus removing a network
roundtrip in the open path, improves performance dramatically on
open (30% or more) to Samba and other servers which support the
cifs posix extensions

Signed-off-by: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

+116 -78
+1 -1
fs/cifs/cifsglob.h
··· 350 bool invalidHandle:1; /* file closed via session abend */ 351 bool messageMode:1; /* for pipes: message vs byte mode */ 352 atomic_t wrtPending; /* handle in use - defer close */ 353 - struct semaphore fh_sem; /* prevents reopen race after dead ses*/ 354 struct cifs_search_info srch_inf; 355 }; 356
··· 350 bool invalidHandle:1; /* file closed via session abend */ 351 bool messageMode:1; /* for pipes: message vs byte mode */ 352 atomic_t wrtPending; /* handle in use - defer close */ 353 + struct mutex fh_mutex; /* prevents reopen race after dead ses*/ 354 struct cifs_search_info srch_inf; 355 }; 356
+85 -46
fs/cifs/dir.c
··· 129 return full_path; 130 } 131 132 int cifs_posix_open(char *full_path, struct inode **pinode, 133 struct super_block *sb, int mode, int oflags, 134 int *poplock, __u16 *pnetfid, int xid) 135 { 136 int rc; 137 __u32 oplock; 138 FILE_UNIX_BASIC_INFO *presp_data; 139 __u32 posix_flags = 0; 140 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 224 if (oflags & O_DIRECT) 225 posix_flags |= SMB_O_DIRECT; 226 227 228 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, 229 pnetfid, presp_data, &oplock, full_path, ··· 253 goto posix_open_ret; 254 255 posix_fill_in_inode(*pinode, presp_data, 1); 256 257 posix_open_ret: 258 kfree(presp_data); ··· 297 char *full_path = NULL; 298 FILE_ALL_INFO *buf = NULL; 299 struct inode *newinode = NULL; 300 - struct cifsInodeInfo *pCifsInode; 301 int disposition = FILE_OVERWRITE_IF; 302 bool write_only = false; 303 ··· 467 /* mknod case - do not leave file open */ 468 CIFSSMBClose(xid, tcon, fileHandle); 469 } else if (newinode) { 470 - struct cifsFileInfo *pCifsFile = 471 - kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 472 - 473 - if (pCifsFile == NULL) 474 - goto cifs_create_out; 475 - pCifsFile->netfid = fileHandle; 476 - pCifsFile->pid = current->tgid; 477 - pCifsFile->pInode = newinode; 478 - pCifsFile->invalidHandle = false; 479 - pCifsFile->closePend = false; 480 - init_MUTEX(&pCifsFile->fh_sem); 481 - mutex_init(&pCifsFile->lock_mutex); 482 - INIT_LIST_HEAD(&pCifsFile->llist); 483 - atomic_set(&pCifsFile->wrtPending, 0); 484 - 485 - /* set the following in open now 486 - pCifsFile->pfile = file; */ 487 - write_lock(&GlobalSMBSeslock); 488 - list_add(&pCifsFile->tlist, &tcon->openFileList); 489 - pCifsInode = CIFS_I(newinode); 490 - if (pCifsInode) { 491 - /* if readable file instance put first in list*/ 492 - if (write_only) { 493 - list_add_tail(&pCifsFile->flist, 494 - &pCifsInode->openFileList); 495 - } else { 496 - list_add(&pCifsFile->flist, 497 - &pCifsInode->openFileList); 498 - } 499 - if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { 500 - pCifsInode->clientCanCacheAll = true; 501 - pCifsInode->clientCanCacheRead = true; 502 - cFYI(1, ("Exclusive Oplock inode %p", 503 - newinode)); 504 - } else if ((oplock & 0xF) == OPLOCK_READ) 505 - pCifsInode->clientCanCacheRead = true; 506 - } 507 - write_unlock(&GlobalSMBSeslock); 508 } 509 cifs_create_out: 510 kfree(buf); ··· 601 return rc; 602 } 603 604 - 605 struct dentry * 606 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, 607 struct nameidata *nd) 608 { 609 int xid; 610 int rc = 0; /* to get around spurious gcc warning, set to zero here */ 611 struct cifs_sb_info *cifs_sb; 612 struct cifsTconInfo *pTcon; 613 struct inode *newInode = NULL; 614 char *full_path = NULL; 615 616 xid = GetXid(); 617 ··· 657 } 658 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); 659 660 - if (pTcon->unix_ext) 661 - rc = cifs_get_inode_info_unix(&newInode, full_path, 662 - parent_dir_inode->i_sb, xid); 663 - else 664 rc = cifs_get_inode_info(&newInode, full_path, NULL, 665 - parent_dir_inode->i_sb, xid, NULL); 666 667 if ((rc == 0) && (newInode != NULL)) { 668 if (pTcon->nocase) ··· 685 else 686 direntry->d_op = &cifs_dentry_ops; 687 d_add(direntry, newInode); 688 - 689 /* since paths are not looked up by component - the parent 690 directories are presumed to be good here */ 691 renew_parental_timestamps(direntry);
··· 129 return full_path; 130 } 131 132 + static void 133 + cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, 134 + struct cifsTconInfo *tcon, bool write_only) 135 + { 136 + int oplock = 0; 137 + struct cifsFileInfo *pCifsFile; 138 + struct cifsInodeInfo *pCifsInode; 139 + 140 + pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 141 + 142 + if (pCifsFile == NULL) 143 + return; 144 + 145 + if (oplockEnabled) 146 + oplock = REQ_OPLOCK; 147 + 148 + pCifsFile->netfid = fileHandle; 149 + pCifsFile->pid = current->tgid; 150 + pCifsFile->pInode = newinode; 151 + pCifsFile->invalidHandle = false; 152 + pCifsFile->closePend = false; 153 + mutex_init(&pCifsFile->fh_mutex); 154 + mutex_init(&pCifsFile->lock_mutex); 155 + INIT_LIST_HEAD(&pCifsFile->llist); 156 + atomic_set(&pCifsFile->wrtPending, 0); 157 + 158 + /* set the following in open now 159 + pCifsFile->pfile = file; */ 160 + write_lock(&GlobalSMBSeslock); 161 + list_add(&pCifsFile->tlist, &tcon->openFileList); 162 + pCifsInode = CIFS_I(newinode); 163 + if (pCifsInode) { 164 + /* if readable file instance put first in list*/ 165 + if (write_only) { 166 + list_add_tail(&pCifsFile->flist, 167 + &pCifsInode->openFileList); 168 + } else { 169 + list_add(&pCifsFile->flist, 170 + &pCifsInode->openFileList); 171 + } 172 + if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { 173 + pCifsInode->clientCanCacheAll = true; 174 + pCifsInode->clientCanCacheRead = true; 175 + cFYI(1, ("Exclusive Oplock inode %p", 176 + newinode)); 177 + } else if ((oplock & 0xF) == OPLOCK_READ) 178 + pCifsInode->clientCanCacheRead = true; 179 + } 180 + write_unlock(&GlobalSMBSeslock); 181 + } 182 + 183 int cifs_posix_open(char *full_path, struct inode **pinode, 184 struct super_block *sb, int mode, int oflags, 185 int *poplock, __u16 *pnetfid, int xid) 186 { 187 int rc; 188 __u32 oplock; 189 + bool write_only = false; 190 FILE_UNIX_BASIC_INFO *presp_data; 191 __u32 posix_flags = 0; 192 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 172 if (oflags & O_DIRECT) 173 posix_flags |= SMB_O_DIRECT; 174 175 + if (!(oflags & FMODE_READ)) 176 + write_only = true; 177 178 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, 179 pnetfid, presp_data, &oplock, full_path, ··· 199 goto posix_open_ret; 200 201 posix_fill_in_inode(*pinode, presp_data, 1); 202 + 203 + cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); 204 205 posix_open_ret: 206 kfree(presp_data); ··· 241 char *full_path = NULL; 242 FILE_ALL_INFO *buf = NULL; 243 struct inode *newinode = NULL; 244 int disposition = FILE_OVERWRITE_IF; 245 bool write_only = false; 246 ··· 412 /* mknod case - do not leave file open */ 413 CIFSSMBClose(xid, tcon, fileHandle); 414 } else if (newinode) { 415 + cifs_fill_fileinfo(newinode, fileHandle, 416 + cifs_sb->tcon, write_only); 417 } 418 cifs_create_out: 419 kfree(buf); ··· 582 return rc; 583 } 584 585 struct dentry * 586 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, 587 struct nameidata *nd) 588 { 589 int xid; 590 int rc = 0; /* to get around spurious gcc warning, set to zero here */ 591 + int oplock = 0; 592 + int mode; 593 + __u16 fileHandle = 0; 594 + bool posix_open = false; 595 struct cifs_sb_info *cifs_sb; 596 struct cifsTconInfo *pTcon; 597 struct inode *newInode = NULL; 598 char *full_path = NULL; 599 + struct file *filp; 600 601 xid = GetXid(); 602 ··· 634 } 635 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); 636 637 + if (pTcon->unix_ext) { 638 + if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && 639 + (nd->flags & LOOKUP_OPEN)) { 640 + if (!((nd->intent.open.flags & O_CREAT) && 641 + (nd->intent.open.flags & O_EXCL))) { 642 + mode = nd->intent.open.create_mode & 643 + ~current->fs->umask; 644 + rc = cifs_posix_open(full_path, &newInode, 645 + parent_dir_inode->i_sb, mode, 646 + nd->intent.open.flags, &oplock, 647 + &fileHandle, xid); 648 + if ((rc != -EINVAL) && (rc != -EOPNOTSUPP)) 649 + posix_open = true; 650 + } 651 + } 652 + if (!posix_open) 653 + rc = cifs_get_inode_info_unix(&newInode, full_path, 654 + parent_dir_inode->i_sb, xid); 655 + } else 656 rc = cifs_get_inode_info(&newInode, full_path, NULL, 657 + parent_dir_inode->i_sb, xid, NULL); 658 659 if ((rc == 0) && (newInode != NULL)) { 660 if (pTcon->nocase) ··· 647 else 648 direntry->d_op = &cifs_dentry_ops; 649 d_add(direntry, newInode); 650 + if (posix_open) 651 + filp = lookup_instantiate_filp(nd, direntry, NULL); 652 /* since paths are not looked up by component - the parent 653 directories are presumed to be good here */ 654 renew_parental_timestamps(direntry);
+30 -31
fs/cifs/file.c
··· 46 memset(private_data, 0, sizeof(struct cifsFileInfo)); 47 private_data->netfid = netfid; 48 private_data->pid = current->tgid; 49 - init_MUTEX(&private_data->fh_sem); 50 mutex_init(&private_data->lock_mutex); 51 INIT_LIST_HEAD(&private_data->llist); 52 private_data->pfile = file; /* needed for writepage */ ··· 284 cifs_sb = CIFS_SB(inode->i_sb); 285 tcon = cifs_sb->tcon; 286 287 - if (file->f_flags & O_CREAT) { 288 - /* search inode for this file and fill in file->private_data */ 289 - pCifsInode = CIFS_I(file->f_path.dentry->d_inode); 290 - read_lock(&GlobalSMBSeslock); 291 - list_for_each(tmp, &pCifsInode->openFileList) { 292 - pCifsFile = list_entry(tmp, struct cifsFileInfo, 293 - flist); 294 - if ((pCifsFile->pfile == NULL) && 295 - (pCifsFile->pid == current->tgid)) { 296 - /* mode set in cifs_create */ 297 298 - /* needed for writepage */ 299 - pCifsFile->pfile = file; 300 301 - file->private_data = pCifsFile; 302 - break; 303 - } 304 } 305 - read_unlock(&GlobalSMBSeslock); 306 - if (file->private_data != NULL) { 307 - rc = 0; 308 - FreeXid(xid); 309 - return rc; 310 - } else { 311 - if (file->f_flags & O_EXCL) 312 - cERROR(1, ("could not find file instance for " 313 - "new file %p", file)); 314 - } 315 } 316 317 full_path = build_path_from_dentry(file->f_path.dentry); ··· 499 return -EBADF; 500 501 xid = GetXid(); 502 - down(&pCifsFile->fh_sem); 503 if (!pCifsFile->invalidHandle) { 504 - up(&pCifsFile->fh_sem); 505 FreeXid(xid); 506 return 0; 507 } ··· 532 if (full_path == NULL) { 533 rc = -ENOMEM; 534 reopen_error_exit: 535 - up(&pCifsFile->fh_sem); 536 FreeXid(xid); 537 return rc; 538 } ··· 574 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 575 CIFS_MOUNT_MAP_SPECIAL_CHR); 576 if (rc) { 577 - up(&pCifsFile->fh_sem); 578 cFYI(1, ("cifs_open returned 0x%x", rc)); 579 cFYI(1, ("oplock: %d", oplock)); 580 } else { 581 reopen_success: 582 pCifsFile->netfid = netfid; 583 pCifsFile->invalidHandle = false; 584 - up(&pCifsFile->fh_sem); 585 pCifsInode = CIFS_I(inode); 586 if (pCifsInode) { 587 if (can_flush) {
··· 46 memset(private_data, 0, sizeof(struct cifsFileInfo)); 47 private_data->netfid = netfid; 48 private_data->pid = current->tgid; 49 + mutex_init(&private_data->fh_mutex); 50 mutex_init(&private_data->lock_mutex); 51 INIT_LIST_HEAD(&private_data->llist); 52 private_data->pfile = file; /* needed for writepage */ ··· 284 cifs_sb = CIFS_SB(inode->i_sb); 285 tcon = cifs_sb->tcon; 286 287 + /* search inode for this file and fill in file->private_data */ 288 + pCifsInode = CIFS_I(file->f_path.dentry->d_inode); 289 + read_lock(&GlobalSMBSeslock); 290 + list_for_each(tmp, &pCifsInode->openFileList) { 291 + pCifsFile = list_entry(tmp, struct cifsFileInfo, 292 + flist); 293 + if ((pCifsFile->pfile == NULL) && 294 + (pCifsFile->pid == current->tgid)) { 295 + /* mode set in cifs_create */ 296 297 + /* needed for writepage */ 298 + pCifsFile->pfile = file; 299 300 + file->private_data = pCifsFile; 301 + break; 302 } 303 + } 304 + read_unlock(&GlobalSMBSeslock); 305 + 306 + if (file->private_data != NULL) { 307 + rc = 0; 308 + FreeXid(xid); 309 + return rc; 310 + } else { 311 + if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL)) 312 + cERROR(1, ("could not find file instance for " 313 + "new file %p", file)); 314 } 315 316 full_path = build_path_from_dentry(file->f_path.dentry); ··· 500 return -EBADF; 501 502 xid = GetXid(); 503 + mutex_unlock(&pCifsFile->fh_mutex); 504 if (!pCifsFile->invalidHandle) { 505 + mutex_lock(&pCifsFile->fh_mutex); 506 FreeXid(xid); 507 return 0; 508 } ··· 533 if (full_path == NULL) { 534 rc = -ENOMEM; 535 reopen_error_exit: 536 + mutex_lock(&pCifsFile->fh_mutex); 537 FreeXid(xid); 538 return rc; 539 } ··· 575 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 576 CIFS_MOUNT_MAP_SPECIAL_CHR); 577 if (rc) { 578 + mutex_lock(&pCifsFile->fh_mutex); 579 cFYI(1, ("cifs_open returned 0x%x", rc)); 580 cFYI(1, ("oplock: %d", oplock)); 581 } else { 582 reopen_success: 583 pCifsFile->netfid = netfid; 584 pCifsFile->invalidHandle = false; 585 + mutex_lock(&pCifsFile->fh_mutex); 586 pCifsInode = CIFS_I(inode); 587 if (pCifsInode) { 588 if (can_flush) {