Skip to content

Commit a6ce493

Browse files
author
Steve French
committed
[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>
1 parent d9fb5c0 commit a6ce493

File tree

3 files changed

+118
-80
lines changed

3 files changed

+118
-80
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ struct cifsFileInfo {
350350
bool invalidHandle:1; /* file closed via session abend */
351351
bool messageMode:1; /* for pipes: message vs byte mode */
352352
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*/
354354
struct cifs_search_info srch_inf;
355355
};
356356

fs/cifs/dir.c

Lines changed: 85 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,64 @@ build_path_from_dentry(struct dentry *direntry)
129129
return full_path;
130130
}
131131

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+
132183
int cifs_posix_open(char *full_path, struct inode **pinode,
133184
struct super_block *sb, int mode, int oflags,
134185
int *poplock, __u16 *pnetfid, int xid)
135186
{
136187
int rc;
137188
__u32 oplock;
189+
bool write_only = false;
138190
FILE_UNIX_BASIC_INFO *presp_data;
139191
__u32 posix_flags = 0;
140192
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -172,6 +224,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
172224
if (oflags & O_DIRECT)
173225
posix_flags |= SMB_O_DIRECT;
174226

227+
if (!(oflags & FMODE_READ))
228+
write_only = true;
175229

176230
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
177231
pnetfid, presp_data, &oplock, full_path,
@@ -200,6 +254,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
200254

201255
posix_fill_in_inode(*pinode, presp_data, 1);
202256

257+
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
258+
203259
posix_open_ret:
204260
kfree(presp_data);
205261
return rc;
@@ -241,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
241297
char *full_path = NULL;
242298
FILE_ALL_INFO *buf = NULL;
243299
struct inode *newinode = NULL;
244-
struct cifsInodeInfo *pCifsInode;
245300
int disposition = FILE_OVERWRITE_IF;
246301
bool write_only = false;
247302

@@ -412,44 +467,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
412467
/* mknod case - do not leave file open */
413468
CIFSSMBClose(xid, tcon, fileHandle);
414469
} 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);
453472
}
454473
cifs_create_out:
455474
kfree(buf);
@@ -582,17 +601,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
582601
return rc;
583602
}
584603

585-
586604
struct dentry *
587605
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
588606
struct nameidata *nd)
589607
{
590608
int xid;
591609
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;
592614
struct cifs_sb_info *cifs_sb;
593615
struct cifsTconInfo *pTcon;
594616
struct inode *newInode = NULL;
595617
char *full_path = NULL;
618+
struct file *filp;
596619

597620
xid = GetXid();
598621

@@ -634,20 +657,36 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
634657
}
635658
cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
636659

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
641679
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);
643681

644682
if ((rc == 0) && (newInode != NULL)) {
645683
if (pTcon->nocase)
646684
direntry->d_op = &cifs_ci_dentry_ops;
647685
else
648686
direntry->d_op = &cifs_dentry_ops;
649687
d_add(direntry, newInode);
650-
688+
if (posix_open)
689+
filp = lookup_instantiate_filp(nd, direntry, NULL);
651690
/* since paths are not looked up by component - the parent
652691
directories are presumed to be good here */
653692
renew_parental_timestamps(direntry);

fs/cifs/file.c

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
4646
memset(private_data, 0, sizeof(struct cifsFileInfo));
4747
private_data->netfid = netfid;
4848
private_data->pid = current->tgid;
49-
init_MUTEX(&private_data->fh_sem);
49+
mutex_init(&private_data->fh_mutex);
5050
mutex_init(&private_data->lock_mutex);
5151
INIT_LIST_HEAD(&private_data->llist);
5252
private_data->pfile = file; /* needed for writepage */
@@ -284,35 +284,34 @@ int cifs_open(struct inode *inode, struct file *file)
284284
cifs_sb = CIFS_SB(inode->i_sb);
285285
tcon = cifs_sb->tcon;
286286

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));
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;
314302
}
315303
}
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+
}
316315

317316
full_path = build_path_from_dentry(file->f_path.dentry);
318317
if (full_path == NULL) {
@@ -500,9 +499,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
500499
return -EBADF;
501500

502501
xid = GetXid();
503-
down(&pCifsFile->fh_sem);
502+
mutex_unlock(&pCifsFile->fh_mutex);
504503
if (!pCifsFile->invalidHandle) {
505-
up(&pCifsFile->fh_sem);
504+
mutex_lock(&pCifsFile->fh_mutex);
506505
FreeXid(xid);
507506
return 0;
508507
}
@@ -533,7 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
533532
if (full_path == NULL) {
534533
rc = -ENOMEM;
535534
reopen_error_exit:
536-
up(&pCifsFile->fh_sem);
535+
mutex_lock(&pCifsFile->fh_mutex);
537536
FreeXid(xid);
538537
return rc;
539538
}
@@ -575,14 +574,14 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
575574
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
576575
CIFS_MOUNT_MAP_SPECIAL_CHR);
577576
if (rc) {
578-
up(&pCifsFile->fh_sem);
577+
mutex_lock(&pCifsFile->fh_mutex);
579578
cFYI(1, ("cifs_open returned 0x%x", rc));
580579
cFYI(1, ("oplock: %d", oplock));
581580
} else {
582581
reopen_success:
583582
pCifsFile->netfid = netfid;
584583
pCifsFile->invalidHandle = false;
585-
up(&pCifsFile->fh_sem);
584+
mutex_lock(&pCifsFile->fh_mutex);
586585
pCifsInode = CIFS_I(inode);
587586
if (pCifsInode) {
588587
if (can_flush) {

0 commit comments

Comments
 (0)