[CIFS] Add support for posix open during lookup
Steve French [Thu, 9 Apr 2009 01:14:32 +0000 (01:14 +0000)]
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>

fs/cifs/cifsglob.h
fs/cifs/dir.c
fs/cifs/file.c

index 7ae1986..df40ab6 100644 (file)
@@ -350,7 +350,7 @@ struct cifsFileInfo {
        bool invalidHandle:1;   /* file closed via session abend */
        bool messageMode:1;     /* for pipes: message vs byte mode */
        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;
 };
 
index e457e14..d9006b0 100644 (file)
@@ -129,12 +129,64 @@ cifs_bp_rename_retry:
        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,
                    struct super_block *sb, int mode, int oflags,
                    int *poplock, __u16 *pnetfid, int xid)
 {
        int rc;
        __u32 oplock;
+       bool write_only = false;
        FILE_UNIX_BASIC_INFO *presp_data;
        __u32 posix_flags = 0;
        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)
                posix_flags |= SMB_O_DIRECT;
 
+       if (!(oflags & FMODE_READ))
+               write_only = true;
 
        rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
                        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);
 
+       cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
+
 posix_open_ret:
        kfree(presp_data);
        return rc;
@@ -241,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        char *full_path = NULL;
        FILE_ALL_INFO *buf = NULL;
        struct inode *newinode = NULL;
-       struct cifsInodeInfo *pCifsInode;
        int disposition = FILE_OVERWRITE_IF;
        bool write_only = false;
 
@@ -412,44 +467,8 @@ cifs_create_set_dentry:
                /* mknod case - do not leave file open */
                CIFSSMBClose(xid, tcon, fileHandle);
        } else if (newinode) {
-               struct cifsFileInfo *pCifsFile =
-                       kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-
-               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_fill_fileinfo(newinode, fileHandle,
+                                       cifs_sb->tcon, write_only);
        }
 cifs_create_out:
        kfree(buf);
@@ -582,17 +601,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        return rc;
 }
 
-
 struct dentry *
 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
            struct nameidata *nd)
 {
        int xid;
        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 cifsTconInfo *pTcon;
        struct inode *newInode = NULL;
        char *full_path = NULL;
+       struct file *filp;
 
        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));
 
-       if (pTcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&newInode, full_path,
-                                             parent_dir_inode->i_sb, xid);
-       else
+       if (pTcon->unix_ext) {
+               if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
+                               (nd->flags & LOOKUP_OPEN)) {
+                       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,
-                                        parent_dir_inode->i_sb, xid, NULL);
+                               parent_dir_inode->i_sb, xid, NULL);
 
        if ((rc == 0) && (newInode != NULL)) {
                if (pTcon->nocase)
@@ -647,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
                else
                        direntry->d_op = &cifs_dentry_ops;
                d_add(direntry, newInode);
-
+               if (posix_open)
+                       filp = lookup_instantiate_filp(nd, direntry, NULL);
                /* since paths are not looked up by component - the parent
                   directories are presumed to be good here */
                renew_parental_timestamps(direntry);
index dfd3e6c..48c9ae0 100644 (file)
@@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
        memset(private_data, 0, sizeof(struct cifsFileInfo));
        private_data->netfid = netfid;
        private_data->pid = current->tgid;
-       init_MUTEX(&private_data->fh_sem);
+       mutex_init(&private_data->fh_mutex);
        mutex_init(&private_data->lock_mutex);
        INIT_LIST_HEAD(&private_data->llist);
        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);
        tcon = cifs_sb->tcon;
 
-       if (file->f_flags & O_CREAT) {
-               /* search inode for this file and fill in file->private_data */
-               pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
-               read_lock(&GlobalSMBSeslock);
-               list_for_each(tmp, &pCifsInode->openFileList) {
-                       pCifsFile = list_entry(tmp, struct cifsFileInfo,
-                                              flist);
-                       if ((pCifsFile->pfile == NULL) &&
-                           (pCifsFile->pid == current->tgid)) {
-                               /* mode set in cifs_create */
-
-                               /* needed for writepage */
-                               pCifsFile->pfile = file;
-
-                               file->private_data = pCifsFile;
-                               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));
+       /* search inode for this file and fill in file->private_data */
+       pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
+       read_lock(&GlobalSMBSeslock);
+       list_for_each(tmp, &pCifsInode->openFileList) {
+               pCifsFile = list_entry(tmp, struct cifsFileInfo,
+                                      flist);
+               if ((pCifsFile->pfile == NULL) &&
+                   (pCifsFile->pid == current->tgid)) {
+                       /* mode set in cifs_create */
+
+                       /* needed for writepage */
+                       pCifsFile->pfile = file;
+
+                       file->private_data = pCifsFile;
+                       break;
                }
        }
+       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);
        if (full_path == NULL) {
@@ -500,9 +499,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
                return -EBADF;
 
        xid = GetXid();
-       down(&pCifsFile->fh_sem);
+       mutex_unlock(&pCifsFile->fh_mutex);
        if (!pCifsFile->invalidHandle) {
-               up(&pCifsFile->fh_sem);
+               mutex_lock(&pCifsFile->fh_mutex);
                FreeXid(xid);
                return 0;
        }
@@ -533,7 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        if (full_path == NULL) {
                rc = -ENOMEM;
 reopen_error_exit:
-               up(&pCifsFile->fh_sem);
+               mutex_lock(&pCifsFile->fh_mutex);
                FreeXid(xid);
                return rc;
        }
@@ -575,14 +574,14 @@ reopen_error_exit:
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
-               up(&pCifsFile->fh_sem);
+               mutex_lock(&pCifsFile->fh_mutex);
                cFYI(1, ("cifs_open returned 0x%x", rc));
                cFYI(1, ("oplock: %d", oplock));
        } else {
 reopen_success:
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = false;
-               up(&pCifsFile->fh_sem);
+               mutex_lock(&pCifsFile->fh_mutex);
                pCifsInode = CIFS_I(inode);
                if (pCifsInode) {
                        if (can_flush) {