Commit a6ce4932fbdbcd8f8e8c6df76812014351c32892
1 parent
d9fb5c091b
Exists in
master
and in
4 other branches
[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
fs/cifs/cifsglob.h
... | ... | @@ -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 |
fs/cifs/dir.c
... | ... | @@ -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); |
fs/cifs/file.c
... | ... | @@ -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) { |