aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2009-04-08 21:14:32 -0400
committerSteve French <sfrench@us.ibm.com>2009-04-16 21:26:49 -0400
commita6ce4932fbdbcd8f8e8c6df76812014351c32892 (patch)
tree4ffe9ea3379cb3227924491c93960108cf762b96 /fs/cifs
parentd9fb5c091b419e0495c50c1cce9e4cf9f7105072 (diff)
[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>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/dir.c131
-rw-r--r--fs/cifs/file.c65
3 files changed, 118 insertions, 80 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7ae19868fdc4..df40ab64cd95 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -350,7 +350,7 @@ struct cifsFileInfo {
350 bool invalidHandle:1; /* file closed via session abend */ 350 bool invalidHandle:1; /* file closed via session abend */
351 bool messageMode:1; /* for pipes: message vs byte mode */ 351 bool messageMode:1; /* for pipes: message vs byte mode */
352 atomic_t wrtPending; /* handle in use - defer close */ 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 struct cifs_search_info srch_inf; 354 struct cifs_search_info srch_inf;
355}; 355};
356 356
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e457e1434349..d9006b04324e 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -129,12 +129,64 @@ cifs_bp_rename_retry:
129 return full_path; 129 return full_path;
130} 130}
131 131
132static void
133cifs_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
132int cifs_posix_open(char *full_path, struct inode **pinode, 183int cifs_posix_open(char *full_path, struct inode **pinode,
133 struct super_block *sb, int mode, int oflags, 184 struct super_block *sb, int mode, int oflags,
134 int *poplock, __u16 *pnetfid, int xid) 185 int *poplock, __u16 *pnetfid, int xid)
135{ 186{
136 int rc; 187 int rc;
137 __u32 oplock; 188 __u32 oplock;
189 bool write_only = false;
138 FILE_UNIX_BASIC_INFO *presp_data; 190 FILE_UNIX_BASIC_INFO *presp_data;
139 __u32 posix_flags = 0; 191 __u32 posix_flags = 0;
140 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 192 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -172,6 +224,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
172 if (oflags & O_DIRECT) 224 if (oflags & O_DIRECT)
173 posix_flags |= SMB_O_DIRECT; 225 posix_flags |= SMB_O_DIRECT;
174 226
227 if (!(oflags & FMODE_READ))
228 write_only = true;
175 229
176 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, 230 rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
177 pnetfid, presp_data, &oplock, full_path, 231 pnetfid, presp_data, &oplock, full_path,
@@ -200,6 +254,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
200 254
201 posix_fill_in_inode(*pinode, presp_data, 1); 255 posix_fill_in_inode(*pinode, presp_data, 1);
202 256
257 cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
258
203posix_open_ret: 259posix_open_ret:
204 kfree(presp_data); 260 kfree(presp_data);
205 return rc; 261 return rc;
@@ -241,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
241 char *full_path = NULL; 297 char *full_path = NULL;
242 FILE_ALL_INFO *buf = NULL; 298 FILE_ALL_INFO *buf = NULL;
243 struct inode *newinode = NULL; 299 struct inode *newinode = NULL;
244 struct cifsInodeInfo *pCifsInode;
245 int disposition = FILE_OVERWRITE_IF; 300 int disposition = FILE_OVERWRITE_IF;
246 bool write_only = false; 301 bool write_only = false;
247 302
@@ -412,44 +467,8 @@ cifs_create_set_dentry:
412 /* mknod case - do not leave file open */ 467 /* mknod case - do not leave file open */
413 CIFSSMBClose(xid, tcon, fileHandle); 468 CIFSSMBClose(xid, tcon, fileHandle);
414 } else if (newinode) { 469 } else if (newinode) {
415 struct cifsFileInfo *pCifsFile = 470 cifs_fill_fileinfo(newinode, fileHandle,
416 kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 471 cifs_sb->tcon, write_only);
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);
453 } 472 }
454cifs_create_out: 473cifs_create_out:
455 kfree(buf); 474 kfree(buf);
@@ -582,17 +601,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
582 return rc; 601 return rc;
583} 602}
584 603
585
586struct dentry * 604struct dentry *
587cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, 605cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
588 struct nameidata *nd) 606 struct nameidata *nd)
589{ 607{
590 int xid; 608 int xid;
591 int rc = 0; /* to get around spurious gcc warning, set to zero here */ 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 struct cifs_sb_info *cifs_sb; 614 struct cifs_sb_info *cifs_sb;
593 struct cifsTconInfo *pTcon; 615 struct cifsTconInfo *pTcon;
594 struct inode *newInode = NULL; 616 struct inode *newInode = NULL;
595 char *full_path = NULL; 617 char *full_path = NULL;
618 struct file *filp;
596 619
597 xid = GetXid(); 620 xid = GetXid();
598 621
@@ -634,12 +657,27 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
634 } 657 }
635 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); 658 cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
636 659
637 if (pTcon->unix_ext) 660 if (pTcon->unix_ext) {
638 rc = cifs_get_inode_info_unix(&newInode, full_path, 661 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
639 parent_dir_inode->i_sb, xid); 662 (nd->flags & LOOKUP_OPEN)) {
640 else 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 rc = cifs_get_inode_info(&newInode, full_path, NULL, 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 if ((rc == 0) && (newInode != NULL)) { 682 if ((rc == 0) && (newInode != NULL)) {
645 if (pTcon->nocase) 683 if (pTcon->nocase)
@@ -647,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
647 else 685 else
648 direntry->d_op = &cifs_dentry_ops; 686 direntry->d_op = &cifs_dentry_ops;
649 d_add(direntry, newInode); 687 d_add(direntry, newInode);
650 688 if (posix_open)
689 filp = lookup_instantiate_filp(nd, direntry, NULL);
651 /* since paths are not looked up by component - the parent 690 /* since paths are not looked up by component - the parent
652 directories are presumed to be good here */ 691 directories are presumed to be good here */
653 renew_parental_timestamps(direntry); 692 renew_parental_timestamps(direntry);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dfd3e6c52a1e..48c9ae09f3d6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
46 memset(private_data, 0, sizeof(struct cifsFileInfo)); 46 memset(private_data, 0, sizeof(struct cifsFileInfo));
47 private_data->netfid = netfid; 47 private_data->netfid = netfid;
48 private_data->pid = current->tgid; 48 private_data->pid = current->tgid;
49 init_MUTEX(&private_data->fh_sem); 49 mutex_init(&private_data->fh_mutex);
50 mutex_init(&private_data->lock_mutex); 50 mutex_init(&private_data->lock_mutex);
51 INIT_LIST_HEAD(&private_data->llist); 51 INIT_LIST_HEAD(&private_data->llist);
52 private_data->pfile = file; /* needed for writepage */ 52 private_data->pfile = file; /* needed for writepage */
@@ -284,35 +284,34 @@ int cifs_open(struct inode *inode, struct file *file)
284 cifs_sb = CIFS_SB(inode->i_sb); 284 cifs_sb = CIFS_SB(inode->i_sb);
285 tcon = cifs_sb->tcon; 285 tcon = cifs_sb->tcon;
286 286
287 if (file->f_flags & O_CREAT) { 287 /* search inode for this file and fill in file->private_data */
288 /* search inode for this file and fill in file->private_data */ 288 pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
289 pCifsInode = CIFS_I(file->f_path.dentry->d_inode); 289 read_lock(&GlobalSMBSeslock);
290 read_lock(&GlobalSMBSeslock); 290 list_for_each(tmp, &pCifsInode->openFileList) {
291 list_for_each(tmp, &pCifsInode->openFileList) { 291 pCifsFile = list_entry(tmp, struct cifsFileInfo,
292 pCifsFile = list_entry(tmp, struct cifsFileInfo, 292 flist);
293 flist); 293 if ((pCifsFile->pfile == NULL) &&
294 if ((pCifsFile->pfile == NULL) && 294 (pCifsFile->pid == current->tgid)) {
295 (pCifsFile->pid == current->tgid)) { 295 /* mode set in cifs_create */
296 /* mode set in cifs_create */ 296
297 297 /* needed for writepage */
298 /* needed for writepage */ 298 pCifsFile->pfile = file;
299 pCifsFile->pfile = file; 299
300 300 file->private_data = pCifsFile;
301 file->private_data = pCifsFile; 301 break;
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 } 302 }
315 } 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 }
316 315
317 full_path = build_path_from_dentry(file->f_path.dentry); 316 full_path = build_path_from_dentry(file->f_path.dentry);
318 if (full_path == NULL) { 317 if (full_path == NULL) {
@@ -500,9 +499,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
500 return -EBADF; 499 return -EBADF;
501 500
502 xid = GetXid(); 501 xid = GetXid();
503 down(&pCifsFile->fh_sem); 502 mutex_unlock(&pCifsFile->fh_mutex);
504 if (!pCifsFile->invalidHandle) { 503 if (!pCifsFile->invalidHandle) {
505 up(&pCifsFile->fh_sem); 504 mutex_lock(&pCifsFile->fh_mutex);
506 FreeXid(xid); 505 FreeXid(xid);
507 return 0; 506 return 0;
508 } 507 }
@@ -533,7 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
533 if (full_path == NULL) { 532 if (full_path == NULL) {
534 rc = -ENOMEM; 533 rc = -ENOMEM;
535reopen_error_exit: 534reopen_error_exit:
536 up(&pCifsFile->fh_sem); 535 mutex_lock(&pCifsFile->fh_mutex);
537 FreeXid(xid); 536 FreeXid(xid);
538 return rc; 537 return rc;
539 } 538 }
@@ -575,14 +574,14 @@ reopen_error_exit:
575 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 574 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
576 CIFS_MOUNT_MAP_SPECIAL_CHR); 575 CIFS_MOUNT_MAP_SPECIAL_CHR);
577 if (rc) { 576 if (rc) {
578 up(&pCifsFile->fh_sem); 577 mutex_lock(&pCifsFile->fh_mutex);
579 cFYI(1, ("cifs_open returned 0x%x", rc)); 578 cFYI(1, ("cifs_open returned 0x%x", rc));
580 cFYI(1, ("oplock: %d", oplock)); 579 cFYI(1, ("oplock: %d", oplock));
581 } else { 580 } else {
582reopen_success: 581reopen_success:
583 pCifsFile->netfid = netfid; 582 pCifsFile->netfid = netfid;
584 pCifsFile->invalidHandle = false; 583 pCifsFile->invalidHandle = false;
585 up(&pCifsFile->fh_sem); 584 mutex_lock(&pCifsFile->fh_mutex);
586 pCifsInode = CIFS_I(inode); 585 pCifsInode = CIFS_I(inode);
587 if (pCifsInode) { 586 if (pCifsInode) {
588 if (can_flush) { 587 if (can_flush) {