Commit a6ce4932fbdbcd8f8e8c6df76812014351c32892

Authored by Steve French
1 parent d9fb5c091b

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

Showing 3 changed files with 118 additions and 80 deletions Side-by-side Diff

... ... @@ -350,7 +350,7 @@
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  
... ... @@ -129,12 +129,64 @@
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);
... ... @@ -172,6 +224,8 @@
172 224 if (oflags & O_DIRECT)
173 225 posix_flags |= SMB_O_DIRECT;
174 226  
  227 + if (!(oflags & FMODE_READ))
  228 + write_only = true;
175 229  
176 230 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
177 231 pnetfid, presp_data, &oplock, full_path,
... ... @@ -200,6 +254,8 @@
200 254  
201 255 posix_fill_in_inode(*pinode, presp_data, 1);
202 256  
  257 + cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
  258 +
203 259 posix_open_ret:
204 260 kfree(presp_data);
205 261 return rc;
... ... @@ -241,7 +297,6 @@
241 297 char *full_path = NULL;
242 298 FILE_ALL_INFO *buf = NULL;
243 299 struct inode *newinode = NULL;
244   - struct cifsInodeInfo *pCifsInode;
245 300 int disposition = FILE_OVERWRITE_IF;
246 301 bool write_only = false;
247 302  
... ... @@ -412,44 +467,8 @@
412 467 /* mknod case - do not leave file open */
413 468 CIFSSMBClose(xid, tcon, fileHandle);
414 469 } else if (newinode) {
415   - struct cifsFileInfo *pCifsFile =
416   - kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
417   -
418   - if (pCifsFile == NULL)
419   - goto cifs_create_out;
420   - pCifsFile->netfid = fileHandle;
421   - pCifsFile->pid = current->tgid;
422   - pCifsFile->pInode = newinode;
423   - pCifsFile->invalidHandle = false;
424   - pCifsFile->closePend = false;
425   - init_MUTEX(&pCifsFile->fh_sem);
426   - mutex_init(&pCifsFile->lock_mutex);
427   - INIT_LIST_HEAD(&pCifsFile->llist);
428   - atomic_set(&pCifsFile->wrtPending, 0);
429   -
430   - /* set the following in open now
431   - pCifsFile->pfile = file; */
432   - write_lock(&GlobalSMBSeslock);
433   - list_add(&pCifsFile->tlist, &tcon->openFileList);
434   - pCifsInode = CIFS_I(newinode);
435   - if (pCifsInode) {
436   - /* if readable file instance put first in list*/
437   - if (write_only) {
438   - list_add_tail(&pCifsFile->flist,
439   - &pCifsInode->openFileList);
440   - } else {
441   - list_add(&pCifsFile->flist,
442   - &pCifsInode->openFileList);
443   - }
444   - if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
445   - pCifsInode->clientCanCacheAll = true;
446   - pCifsInode->clientCanCacheRead = true;
447   - cFYI(1, ("Exclusive Oplock inode %p",
448   - newinode));
449   - } else if ((oplock & 0xF) == OPLOCK_READ)
450   - pCifsInode->clientCanCacheRead = true;
451   - }
452   - write_unlock(&GlobalSMBSeslock);
  470 + cifs_fill_fileinfo(newinode, fileHandle,
  471 + cifs_sb->tcon, write_only);
453 472 }
454 473 cifs_create_out:
455 474 kfree(buf);
456 475  
457 476  
... ... @@ -582,17 +601,21 @@
582 601 return rc;
583 602 }
584 603  
585   -
586 604 struct dentry *
587 605 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
588 606 struct nameidata *nd)
589 607 {
590 608 int xid;
591 609 int rc = 0; /* to get around spurious gcc warning, set to zero here */
  610 + int oplock = 0;
  611 + int mode;
  612 + __u16 fileHandle = 0;
  613 + bool posix_open = false;
592 614 struct cifs_sb_info *cifs_sb;
593 615 struct cifsTconInfo *pTcon;
594 616 struct inode *newInode = NULL;
595 617 char *full_path = NULL;
  618 + struct file *filp;
596 619  
597 620 xid = GetXid();
598 621  
599 622  
... ... @@ -634,12 +657,27 @@
634 657 }
635 658 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
636 659  
637   - if (pTcon->unix_ext)
638   - rc = cifs_get_inode_info_unix(&newInode, full_path,
639   - parent_dir_inode->i_sb, xid);
640   - else
  660 + if (pTcon->unix_ext) {
  661 + if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
  662 + (nd->flags & LOOKUP_OPEN)) {
  663 + if (!((nd->intent.open.flags & O_CREAT) &&
  664 + (nd->intent.open.flags & O_EXCL))) {
  665 + mode = nd->intent.open.create_mode &
  666 + ~current->fs->umask;
  667 + rc = cifs_posix_open(full_path, &newInode,
  668 + parent_dir_inode->i_sb, mode,
  669 + nd->intent.open.flags, &oplock,
  670 + &fileHandle, xid);
  671 + if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
  672 + posix_open = true;
  673 + }
  674 + }
  675 + if (!posix_open)
  676 + rc = cifs_get_inode_info_unix(&newInode, full_path,
  677 + parent_dir_inode->i_sb, xid);
  678 + } else
641 679 rc = cifs_get_inode_info(&newInode, full_path, NULL,
642   - parent_dir_inode->i_sb, xid, NULL);
  680 + parent_dir_inode->i_sb, xid, NULL);
643 681  
644 682 if ((rc == 0) && (newInode != NULL)) {
645 683 if (pTcon->nocase)
... ... @@ -647,7 +685,8 @@
647 685 else
648 686 direntry->d_op = &cifs_dentry_ops;
649 687 d_add(direntry, newInode);
650   -
  688 + if (posix_open)
  689 + filp = lookup_instantiate_filp(nd, direntry, NULL);
651 690 /* since paths are not looked up by component - the parent
652 691 directories are presumed to be good here */
653 692 renew_parental_timestamps(direntry);
... ... @@ -46,7 +46,7 @@
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 */
53 53  
54 54  
55 55  
56 56  
57 57  
... ... @@ -284,36 +284,35 @@
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   - }
315 303 }
  304 + read_unlock(&GlobalSMBSeslock);
316 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 +
317 316 full_path = build_path_from_dentry(file->f_path.dentry);
318 317 if (full_path == NULL) {
319 318 FreeXid(xid);
320 319  
... ... @@ -500,9 +499,9 @@
500 499 return -EBADF;
501 500  
502 501 xid = GetXid();
503   - down(&pCifsFile->fh_sem);
  502 + mutex_unlock(&pCifsFile->fh_mutex);
504 503 if (!pCifsFile->invalidHandle) {
505   - up(&pCifsFile->fh_sem);
  504 + mutex_lock(&pCifsFile->fh_mutex);
506 505 FreeXid(xid);
507 506 return 0;
508 507 }
... ... @@ -533,7 +532,7 @@
533 532 if (full_path == NULL) {
534 533 rc = -ENOMEM;
535 534 reopen_error_exit:
536   - up(&pCifsFile->fh_sem);
  535 + mutex_lock(&pCifsFile->fh_mutex);
537 536 FreeXid(xid);
538 537 return rc;
539 538 }
540 539  
... ... @@ -575,14 +574,14 @@
575 574 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
576 575 CIFS_MOUNT_MAP_SPECIAL_CHR);
577 576 if (rc) {
578   - up(&pCifsFile->fh_sem);
  577 + mutex_lock(&pCifsFile->fh_mutex);
579 578 cFYI(1, ("cifs_open returned 0x%x", rc));
580 579 cFYI(1, ("oplock: %d", oplock));
581 580 } else {
582 581 reopen_success:
583 582 pCifsFile->netfid = netfid;
584 583 pCifsFile->invalidHandle = false;
585   - up(&pCifsFile->fh_sem);
  584 + mutex_lock(&pCifsFile->fh_mutex);
586 585 pCifsInode = CIFS_I(inode);
587 586 if (pCifsInode) {
588 587 if (can_flush) {