[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>
This commit is contained in:
Steve French 2009-04-09 01:14:32 +00:00
parent d9fb5c091b
commit a6ce4932fb
3 changed files with 116 additions and 78 deletions

View File

@ -350,7 +350,7 @@ struct cifsFileInfo {
bool invalidHandle:1; /* file closed via session abend */ bool invalidHandle:1; /* file closed via session abend */
bool messageMode:1; /* for pipes: message vs byte mode */ bool messageMode:1; /* for pipes: message vs byte mode */
atomic_t wrtPending; /* handle in use - defer close */ atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/ struct mutex fh_mutex; /* prevents reopen race after dead ses*/
struct cifs_search_info srch_inf; struct cifs_search_info srch_inf;
}; };

View File

@ -129,12 +129,64 @@ cifs_bp_rename_retry:
return full_path; return full_path;
} }
static void
cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
struct cifsTconInfo *tcon, bool write_only)
{
int oplock = 0;
struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode;
pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (pCifsFile == NULL)
return;
if (oplockEnabled)
oplock = REQ_OPLOCK;
pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid;
pCifsFile->pInode = newinode;
pCifsFile->invalidHandle = false;
pCifsFile->closePend = false;
mutex_init(&pCifsFile->fh_mutex);
mutex_init(&pCifsFile->lock_mutex);
INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->wrtPending, 0);
/* set the following in open now
pCifsFile->pfile = file; */
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &tcon->openFileList);
pCifsInode = CIFS_I(newinode);
if (pCifsInode) {
/* if readable file instance put first in list*/
if (write_only) {
list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList);
} else {
list_add(&pCifsFile->flist,
&pCifsInode->openFileList);
}
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, ("Exclusive Oplock inode %p",
newinode));
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
}
write_unlock(&GlobalSMBSeslock);
}
int cifs_posix_open(char *full_path, struct inode **pinode, int cifs_posix_open(char *full_path, struct inode **pinode,
struct super_block *sb, int mode, int oflags, struct super_block *sb, int mode, int oflags,
int *poplock, __u16 *pnetfid, int xid) int *poplock, __u16 *pnetfid, int xid)
{ {
int rc; int rc;
__u32 oplock; __u32 oplock;
bool write_only = false;
FILE_UNIX_BASIC_INFO *presp_data; FILE_UNIX_BASIC_INFO *presp_data;
__u32 posix_flags = 0; __u32 posix_flags = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@ -172,6 +224,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
if (oflags & O_DIRECT) if (oflags & O_DIRECT)
posix_flags |= SMB_O_DIRECT; posix_flags |= SMB_O_DIRECT;
if (!(oflags & FMODE_READ))
write_only = true;
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
pnetfid, presp_data, &oplock, full_path, pnetfid, presp_data, &oplock, full_path,
@ -200,6 +254,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
posix_fill_in_inode(*pinode, presp_data, 1); posix_fill_in_inode(*pinode, presp_data, 1);
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
posix_open_ret: posix_open_ret:
kfree(presp_data); kfree(presp_data);
return rc; return rc;
@ -241,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
char *full_path = NULL; char *full_path = NULL;
FILE_ALL_INFO *buf = NULL; FILE_ALL_INFO *buf = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
struct cifsInodeInfo *pCifsInode;
int disposition = FILE_OVERWRITE_IF; int disposition = FILE_OVERWRITE_IF;
bool write_only = false; bool write_only = false;
@ -412,44 +467,8 @@ cifs_create_set_dentry:
/* mknod case - do not leave file open */ /* mknod case - do not leave file open */
CIFSSMBClose(xid, tcon, fileHandle); CIFSSMBClose(xid, tcon, fileHandle);
} else if (newinode) { } else if (newinode) {
struct cifsFileInfo *pCifsFile = cifs_fill_fileinfo(newinode, fileHandle,
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); cifs_sb->tcon, write_only);
if (pCifsFile == NULL)
goto cifs_create_out;
pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid;
pCifsFile->pInode = newinode;
pCifsFile->invalidHandle = false;
pCifsFile->closePend = false;
init_MUTEX(&pCifsFile->fh_sem);
mutex_init(&pCifsFile->lock_mutex);
INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->wrtPending, 0);
/* set the following in open now
pCifsFile->pfile = file; */
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &tcon->openFileList);
pCifsInode = CIFS_I(newinode);
if (pCifsInode) {
/* if readable file instance put first in list*/
if (write_only) {
list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList);
} else {
list_add(&pCifsFile->flist,
&pCifsInode->openFileList);
}
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, ("Exclusive Oplock inode %p",
newinode));
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
}
write_unlock(&GlobalSMBSeslock);
} }
cifs_create_out: cifs_create_out:
kfree(buf); kfree(buf);
@ -582,17 +601,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
return rc; return rc;
} }
struct dentry * struct dentry *
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
struct nameidata *nd) struct nameidata *nd)
{ {
int xid; int xid;
int rc = 0; /* to get around spurious gcc warning, set to zero here */ int rc = 0; /* to get around spurious gcc warning, set to zero here */
int oplock = 0;
int mode;
__u16 fileHandle = 0;
bool posix_open = false;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *newInode = NULL; struct inode *newInode = NULL;
char *full_path = NULL; char *full_path = NULL;
struct file *filp;
xid = GetXid(); xid = GetXid();
@ -634,12 +657,27 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} }
cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
if (pTcon->unix_ext) if (pTcon->unix_ext) {
rc = cifs_get_inode_info_unix(&newInode, full_path, if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
parent_dir_inode->i_sb, xid); (nd->flags & LOOKUP_OPEN)) {
else if (!((nd->intent.open.flags & O_CREAT) &&
(nd->intent.open.flags & O_EXCL))) {
mode = nd->intent.open.create_mode &
~current->fs->umask;
rc = cifs_posix_open(full_path, &newInode,
parent_dir_inode->i_sb, mode,
nd->intent.open.flags, &oplock,
&fileHandle, xid);
if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
posix_open = true;
}
}
if (!posix_open)
rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid);
} else
rc = cifs_get_inode_info(&newInode, full_path, NULL, rc = cifs_get_inode_info(&newInode, full_path, NULL,
parent_dir_inode->i_sb, xid, NULL); parent_dir_inode->i_sb, xid, NULL);
if ((rc == 0) && (newInode != NULL)) { if ((rc == 0) && (newInode != NULL)) {
if (pTcon->nocase) if (pTcon->nocase)
@ -647,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
else else
direntry->d_op = &cifs_dentry_ops; direntry->d_op = &cifs_dentry_ops;
d_add(direntry, newInode); d_add(direntry, newInode);
if (posix_open)
filp = lookup_instantiate_filp(nd, direntry, NULL);
/* since paths are not looked up by component - the parent /* since paths are not looked up by component - the parent
directories are presumed to be good here */ directories are presumed to be good here */
renew_parental_timestamps(direntry); renew_parental_timestamps(direntry);

View File

@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
memset(private_data, 0, sizeof(struct cifsFileInfo)); memset(private_data, 0, sizeof(struct cifsFileInfo));
private_data->netfid = netfid; private_data->netfid = netfid;
private_data->pid = current->tgid; private_data->pid = current->tgid;
init_MUTEX(&private_data->fh_sem); mutex_init(&private_data->fh_mutex);
mutex_init(&private_data->lock_mutex); mutex_init(&private_data->lock_mutex);
INIT_LIST_HEAD(&private_data->llist); INIT_LIST_HEAD(&private_data->llist);
private_data->pfile = file; /* needed for writepage */ private_data->pfile = file; /* needed for writepage */
@ -284,35 +284,34 @@ int cifs_open(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
tcon = cifs_sb->tcon; tcon = cifs_sb->tcon;
if (file->f_flags & O_CREAT) { /* search inode for this file and fill in file->private_data */
/* search inode for this file and fill in file->private_data */ pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
pCifsInode = CIFS_I(file->f_path.dentry->d_inode); read_lock(&GlobalSMBSeslock);
read_lock(&GlobalSMBSeslock); list_for_each(tmp, &pCifsInode->openFileList) {
list_for_each(tmp, &pCifsInode->openFileList) { pCifsFile = list_entry(tmp, struct cifsFileInfo,
pCifsFile = list_entry(tmp, struct cifsFileInfo, flist);
flist); if ((pCifsFile->pfile == NULL) &&
if ((pCifsFile->pfile == NULL) && (pCifsFile->pid == current->tgid)) {
(pCifsFile->pid == current->tgid)) { /* mode set in cifs_create */
/* mode set in cifs_create */
/* needed for writepage */ /* needed for writepage */
pCifsFile->pfile = file; pCifsFile->pfile = file;
file->private_data = pCifsFile; file->private_data = pCifsFile;
break; break;
}
}
read_unlock(&GlobalSMBSeslock);
if (file->private_data != NULL) {
rc = 0;
FreeXid(xid);
return rc;
} else {
if (file->f_flags & O_EXCL)
cERROR(1, ("could not find file instance for "
"new file %p", file));
} }
} }
read_unlock(&GlobalSMBSeslock);
if (file->private_data != NULL) {
rc = 0;
FreeXid(xid);
return rc;
} else {
if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
cERROR(1, ("could not find file instance for "
"new file %p", file));
}
full_path = build_path_from_dentry(file->f_path.dentry); full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) { if (full_path == NULL) {
@ -500,9 +499,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
return -EBADF; return -EBADF;
xid = GetXid(); xid = GetXid();
down(&pCifsFile->fh_sem); mutex_unlock(&pCifsFile->fh_mutex);
if (!pCifsFile->invalidHandle) { if (!pCifsFile->invalidHandle) {
up(&pCifsFile->fh_sem); mutex_lock(&pCifsFile->fh_mutex);
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} }
@ -533,7 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
reopen_error_exit: reopen_error_exit:
up(&pCifsFile->fh_sem); mutex_lock(&pCifsFile->fh_mutex);
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
@ -575,14 +574,14 @@ reopen_error_exit:
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) { if (rc) {
up(&pCifsFile->fh_sem); mutex_lock(&pCifsFile->fh_mutex);
cFYI(1, ("cifs_open returned 0x%x", rc)); cFYI(1, ("cifs_open returned 0x%x", rc));
cFYI(1, ("oplock: %d", oplock)); cFYI(1, ("oplock: %d", oplock));
} else { } else {
reopen_success: reopen_success:
pCifsFile->netfid = netfid; pCifsFile->netfid = netfid;
pCifsFile->invalidHandle = false; pCifsFile->invalidHandle = false;
up(&pCifsFile->fh_sem); mutex_lock(&pCifsFile->fh_mutex);
pCifsInode = CIFS_I(inode); pCifsInode = CIFS_I(inode);
if (pCifsInode) { if (pCifsInode) {
if (can_flush) { if (can_flush) {