[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 350 bool invalidHandle:1; /* file closed via session abend */ 351 351 bool messageMode:1; /* for pipes: message vs byte mode */ 352 352 atomic_t wrtPending; /* handle in use - defer close */ 353 - struct semaphore fh_sem; /* prevents reopen race after dead ses*/ 353 + struct mutex fh_mutex; /* prevents reopen race after dead ses*/ 354 354 struct cifs_search_info srch_inf; 355 355 }; 356 356
+85 -46
fs/cifs/dir.c
··· 129 129 return full_path; 130 130 } 131 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 + 132 183 int cifs_posix_open(char *full_path, struct inode **pinode, 133 184 struct super_block *sb, int mode, int oflags, 134 185 int *poplock, __u16 *pnetfid, int xid) 135 186 { 136 187 int rc; 137 188 __u32 oplock; 189 + bool write_only = false; 138 190 FILE_UNIX_BASIC_INFO *presp_data; 139 191 __u32 posix_flags = 0; 140 192 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 224 172 if (oflags & O_DIRECT) 225 173 posix_flags |= SMB_O_DIRECT; 226 174 175 + if (!(oflags & FMODE_READ)) 176 + write_only = true; 227 177 228 178 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, 229 179 pnetfid, presp_data, &oplock, full_path, ··· 253 199 goto posix_open_ret; 254 200 255 201 posix_fill_in_inode(*pinode, presp_data, 1); 202 + 203 + cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); 256 204 257 205 posix_open_ret: 258 206 kfree(presp_data); ··· 297 241 char *full_path = NULL; 298 242 FILE_ALL_INFO *buf = NULL; 299 243 struct inode *newinode = NULL; 300 - struct cifsInodeInfo *pCifsInode; 301 244 int disposition = FILE_OVERWRITE_IF; 302 245 bool write_only = false; 303 246 ··· 467 412 /* mknod case - do not leave file open */ 468 413 CIFSSMBClose(xid, tcon, fileHandle); 469 414 } 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); 415 + cifs_fill_fileinfo(newinode, fileHandle, 416 + cifs_sb->tcon, write_only); 508 417 } 509 418 cifs_create_out: 510 419 kfree(buf); ··· 601 582 return rc; 602 583 } 603 584 604 - 605 585 struct dentry * 606 586 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, 607 587 struct nameidata *nd) 608 588 { 609 589 int xid; 610 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; 611 595 struct cifs_sb_info *cifs_sb; 612 596 struct cifsTconInfo *pTcon; 613 597 struct inode *newInode = NULL; 614 598 char *full_path = NULL; 599 + struct file *filp; 615 600 616 601 xid = GetXid(); 617 602 ··· 657 634 } 658 635 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); 659 636 660 - if (pTcon->unix_ext) 661 - rc = cifs_get_inode_info_unix(&newInode, full_path, 662 - parent_dir_inode->i_sb, xid); 663 - else 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 664 656 rc = cifs_get_inode_info(&newInode, full_path, NULL, 665 - parent_dir_inode->i_sb, xid, NULL); 657 + parent_dir_inode->i_sb, xid, NULL); 666 658 667 659 if ((rc == 0) && (newInode != NULL)) { 668 660 if (pTcon->nocase) ··· 685 647 else 686 648 direntry->d_op = &cifs_dentry_ops; 687 649 d_add(direntry, newInode); 688 - 650 + if (posix_open) 651 + filp = lookup_instantiate_filp(nd, direntry, NULL); 689 652 /* since paths are not looked up by component - the parent 690 653 directories are presumed to be good here */ 691 654 renew_parental_timestamps(direntry);
+30 -31
fs/cifs/file.c
··· 46 46 memset(private_data, 0, sizeof(struct cifsFileInfo)); 47 47 private_data->netfid = netfid; 48 48 private_data->pid = current->tgid; 49 - init_MUTEX(&private_data->fh_sem); 49 + mutex_init(&private_data->fh_mutex); 50 50 mutex_init(&private_data->lock_mutex); 51 51 INIT_LIST_HEAD(&private_data->llist); 52 52 private_data->pfile = file; /* needed for writepage */ ··· 284 284 cifs_sb = CIFS_SB(inode->i_sb); 285 285 tcon = cifs_sb->tcon; 286 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 */ 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 */ 297 296 298 - /* needed for writepage */ 299 - pCifsFile->pfile = file; 297 + /* needed for writepage */ 298 + pCifsFile->pfile = file; 300 299 301 - file->private_data = pCifsFile; 302 - break; 303 - } 300 + file->private_data = pCifsFile; 301 + break; 304 302 } 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 - } 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)); 315 314 } 316 315 317 316 full_path = build_path_from_dentry(file->f_path.dentry); ··· 499 500 return -EBADF; 500 501 501 502 xid = GetXid(); 502 - down(&pCifsFile->fh_sem); 503 + mutex_unlock(&pCifsFile->fh_mutex); 503 504 if (!pCifsFile->invalidHandle) { 504 - up(&pCifsFile->fh_sem); 505 + mutex_lock(&pCifsFile->fh_mutex); 505 506 FreeXid(xid); 506 507 return 0; 507 508 } ··· 532 533 if (full_path == NULL) { 533 534 rc = -ENOMEM; 534 535 reopen_error_exit: 535 - up(&pCifsFile->fh_sem); 536 + mutex_lock(&pCifsFile->fh_mutex); 536 537 FreeXid(xid); 537 538 return rc; 538 539 } ··· 574 575 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 575 576 CIFS_MOUNT_MAP_SPECIAL_CHR); 576 577 if (rc) { 577 - up(&pCifsFile->fh_sem); 578 + mutex_lock(&pCifsFile->fh_mutex); 578 579 cFYI(1, ("cifs_open returned 0x%x", rc)); 579 580 cFYI(1, ("oplock: %d", oplock)); 580 581 } else { 581 582 reopen_success: 582 583 pCifsFile->netfid = netfid; 583 584 pCifsFile->invalidHandle = false; 584 - up(&pCifsFile->fh_sem); 585 + mutex_lock(&pCifsFile->fh_mutex); 585 586 pCifsInode = CIFS_I(inode); 586 587 if (pCifsInode) { 587 588 if (can_flush) {