Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[pandora-kernel.git] / fs / cifs / file.c
index c10f085..45af003 100644 (file)
@@ -60,34 +60,32 @@ static inline int cifs_convert_flags(unsigned int flags)
                FILE_READ_DATA);
 }
 
-static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
+static u32 cifs_posix_convert_flags(unsigned int flags)
 {
-       fmode_t posix_flags = 0;
+       u32 posix_flags = 0;
 
        if ((flags & O_ACCMODE) == O_RDONLY)
-               posix_flags = FMODE_READ;
+               posix_flags = SMB_O_RDONLY;
        else if ((flags & O_ACCMODE) == O_WRONLY)
-               posix_flags = FMODE_WRITE;
-       else if ((flags & O_ACCMODE) == O_RDWR) {
-               /* GENERIC_ALL is too much permission to request
-                  can cause unnecessary access denied on create */
-               /* return GENERIC_ALL; */
-               posix_flags = FMODE_READ | FMODE_WRITE;
-       }
-       /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
-          reopening a file.  They had their effect on the original open */
-       if (flags & O_APPEND)
-               posix_flags |= (fmode_t)O_APPEND;
+               posix_flags = SMB_O_WRONLY;
+       else if ((flags & O_ACCMODE) == O_RDWR)
+               posix_flags = SMB_O_RDWR;
+
+       if (flags & O_CREAT)
+               posix_flags |= SMB_O_CREAT;
+       if (flags & O_EXCL)
+               posix_flags |= SMB_O_EXCL;
+       if (flags & O_TRUNC)
+               posix_flags |= SMB_O_TRUNC;
+       /* be safe and imply O_SYNC for O_DSYNC */
        if (flags & O_DSYNC)
-               posix_flags |= (fmode_t)O_DSYNC;
-       if (flags & __O_SYNC)
-               posix_flags |= (fmode_t)__O_SYNC;
+               posix_flags |= SMB_O_SYNC;
        if (flags & O_DIRECTORY)
-               posix_flags |= (fmode_t)O_DIRECTORY;
+               posix_flags |= SMB_O_DIRECTORY;
        if (flags & O_NOFOLLOW)
-               posix_flags |= (fmode_t)O_NOFOLLOW;
+               posix_flags |= SMB_O_NOFOLLOW;
        if (flags & O_DIRECT)
-               posix_flags |= (fmode_t)O_DIRECT;
+               posix_flags |= SMB_O_DIRECT;
 
        return posix_flags;
 }
@@ -159,6 +157,165 @@ client_can_cache:
        return rc;
 }
 
+int cifs_posix_open(char *full_path, struct inode **pinode,
+                       struct super_block *sb, int mode, unsigned int f_flags,
+                       __u32 *poplock, __u16 *pnetfid, int xid)
+{
+       int rc;
+       FILE_UNIX_BASIC_INFO *presp_data;
+       __u32 posix_flags = 0;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       struct cifs_fattr fattr;
+       struct tcon_link *tlink;
+       struct cifsTconInfo *tcon;
+
+       cFYI(1, "posix open %s", full_path);
+
+       presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+       if (presp_data == NULL)
+               return -ENOMEM;
+
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               rc = PTR_ERR(tlink);
+               goto posix_open_ret;
+       }
+
+       tcon = tlink_tcon(tlink);
+       mode &= ~current_umask();
+
+       posix_flags = cifs_posix_convert_flags(f_flags);
+       rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data,
+                            poplock, full_path, cifs_sb->local_nls,
+                            cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+       cifs_put_tlink(tlink);
+
+       if (rc)
+               goto posix_open_ret;
+
+       if (presp_data->Type == cpu_to_le32(-1))
+               goto posix_open_ret; /* open ok, caller does qpathinfo */
+
+       if (!pinode)
+               goto posix_open_ret; /* caller does not need info */
+
+       cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
+
+       /* get new inode and set it up */
+       if (*pinode == NULL) {
+               cifs_fill_uniqueid(sb, &fattr);
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode) {
+                       rc = -ENOMEM;
+                       goto posix_open_ret;
+               }
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
+       }
+
+posix_open_ret:
+       kfree(presp_data);
+       return rc;
+}
+
+struct cifsFileInfo *
+cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+                 struct tcon_link *tlink, __u32 oplock)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
+       struct cifsFileInfo *pCifsFile;
+
+       pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+       if (pCifsFile == NULL)
+               return pCifsFile;
+
+       pCifsFile->netfid = fileHandle;
+       pCifsFile->pid = current->tgid;
+       pCifsFile->uid = current_fsuid();
+       pCifsFile->dentry = dget(dentry);
+       pCifsFile->f_flags = file->f_flags;
+       pCifsFile->invalidHandle = false;
+       pCifsFile->tlink = cifs_get_tlink(tlink);
+       mutex_init(&pCifsFile->fh_mutex);
+       mutex_init(&pCifsFile->lock_mutex);
+       INIT_LIST_HEAD(&pCifsFile->llist);
+       atomic_set(&pCifsFile->count, 1);
+       INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
+
+       spin_lock(&cifs_file_list_lock);
+       list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
+       /* if readable file instance put first in list*/
+       if (file->f_mode & FMODE_READ)
+               list_add(&pCifsFile->flist, &pCifsInode->openFileList);
+       else
+               list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
+       spin_unlock(&cifs_file_list_lock);
+
+       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+               pCifsInode->clientCanCacheAll = true;
+               pCifsInode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock inode %p", inode);
+       } else if ((oplock & 0xF) == OPLOCK_READ)
+               pCifsInode->clientCanCacheRead = true;
+
+       file->private_data = pCifsFile;
+       return pCifsFile;
+}
+
+/*
+ * Release a reference on the file private data. This may involve closing
+ * the filehandle out on the server.
+ */
+void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
+{
+       struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
+       struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
+       struct cifsLockInfo *li, *tmp;
+
+       spin_lock(&cifs_file_list_lock);
+       if (!atomic_dec_and_test(&cifs_file->count)) {
+               spin_unlock(&cifs_file_list_lock);
+               return;
+       }
+
+       /* remove it from the lists */
+       list_del(&cifs_file->flist);
+       list_del(&cifs_file->tlist);
+
+       if (list_empty(&cifsi->openFileList)) {
+               cFYI(1, "closing last open instance for inode %p",
+                       cifs_file->dentry->d_inode);
+               cifsi->clientCanCacheRead = false;
+               cifsi->clientCanCacheAll  = false;
+       }
+       spin_unlock(&cifs_file_list_lock);
+
+       if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+               int xid, rc;
+
+               xid = GetXid();
+               rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
+               FreeXid(xid);
+       }
+
+       /* Delete any outstanding lock records. We'll lose them when the file
+        * is closed anyway.
+        */
+       mutex_lock(&cifs_file->lock_mutex);
+       list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
+               list_del(&li->llist);
+               kfree(li);
+       }
+       mutex_unlock(&cifs_file->lock_mutex);
+
+       cifs_put_tlink(cifs_file->tlink);
+       dput(cifs_file->dentry);
+       kfree(cifs_file);
+}
+
 int cifs_open(struct inode *inode, struct file *file)
 {
        int rc = -EACCES;
@@ -205,17 +362,15 @@ int cifs_open(struct inode *inode, struct file *file)
            (tcon->ses->capabilities & CAP_UNIX) &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-               int oflags = (int) cifs_posix_convert_flags(file->f_flags);
-               oflags |= SMB_O_CREAT;
                /* can not refresh inode info since size could be stale */
                rc = cifs_posix_open(full_path, &inode, inode->i_sb,
                                cifs_sb->mnt_file_mode /* ignored */,
-                               oflags, &oplock, &netfid, xid);
+                               file->f_flags, &oplock, &netfid, xid);
                if (rc == 0) {
                        cFYI(1, "posix open succeeded");
 
-                       pCifsFile = cifs_new_fileinfo(inode, netfid, file,
-                                                       tlink, oflags, oplock);
+                       pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
+                                                     oplock);
                        if (pCifsFile == NULL) {
                                CIFSSMBClose(xid, tcon, netfid);
                                rc = -ENOMEM;
@@ -307,8 +462,7 @@ int cifs_open(struct inode *inode, struct file *file)
        if (rc != 0)
                goto out;
 
-       pCifsFile = cifs_new_fileinfo(inode, netfid, file, tlink,
-                                       file->f_flags, oplock);
+       pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
        if (pCifsFile == NULL) {
                rc = -ENOMEM;
                goto out;
@@ -355,14 +509,13 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
        return rc;
 }
 
-static int cifs_reopen_file(struct file *file, bool can_flush)
+static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 {
        int rc = -EACCES;
        int xid;
        __u32 oplock;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *tcon;
-       struct cifsFileInfo *pCifsFile;
        struct cifsInodeInfo *pCifsInode;
        struct inode *inode;
        char *full_path = NULL;
@@ -370,11 +523,6 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        int disposition = FILE_OPEN;
        __u16 netfid;
 
-       if (file->private_data)
-               pCifsFile = file->private_data;
-       else
-               return -EBADF;
-
        xid = GetXid();
        mutex_lock(&pCifsFile->fh_mutex);
        if (!pCifsFile->invalidHandle) {
@@ -384,21 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
                return rc;
        }
 
-       if (file->f_path.dentry == NULL) {
-               cERROR(1, "no valid name if dentry freed");
-               dump_stack();
-               rc = -EBADF;
-               goto reopen_error_exit;
-       }
-
-       inode = file->f_path.dentry->d_inode;
-       if (inode == NULL) {
-               cERROR(1, "inode not valid");
-               dump_stack();
-               rc = -EBADF;
-               goto reopen_error_exit;
-       }
-
+       inode = pCifsFile->dentry->d_inode;
        cifs_sb = CIFS_SB(inode->i_sb);
        tcon = tlink_tcon(pCifsFile->tlink);
 
@@ -406,17 +540,16 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
    those that already have the rename sem can end up causing writepage
    to get called and if the server was down that means we end up here,
    and we can never tell if the caller already has the rename_sem */
-       full_path = build_path_from_dentry(file->f_path.dentry);
+       full_path = build_path_from_dentry(pCifsFile->dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-reopen_error_exit:
                mutex_unlock(&pCifsFile->fh_mutex);
                FreeXid(xid);
                return rc;
        }
 
        cFYI(1, "inode = 0x%p file flags 0x%x for %s",
-                inode, file->f_flags, full_path);
+                inode, pCifsFile->f_flags, full_path);
 
        if (oplockEnabled)
                oplock = REQ_OPLOCK;
@@ -426,8 +559,14 @@ reopen_error_exit:
        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-               int oflags = (int) cifs_posix_convert_flags(file->f_flags);
-               /* can not refresh inode info since size could be stale */
+
+               /*
+                * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
+                * original open. Must mask them off for a reopen.
+                */
+               unsigned int oflags = pCifsFile->f_flags &
+                                               ~(O_CREAT | O_EXCL | O_TRUNC);
+
                rc = cifs_posix_open(full_path, NULL, inode->i_sb,
                                cifs_sb->mnt_file_mode /* ignored */,
                                oflags, &oplock, &netfid, xid);
@@ -439,7 +578,7 @@ reopen_error_exit:
                   in the reconnect path it is important to retry hard */
        }
 
-       desiredAccess = cifs_convert_flags(file->f_flags);
+       desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
 
        /* Can not refresh inode by passing in file_info buf to be returned
           by SMBOpen and then calling get_inode_info with returned buf
@@ -455,49 +594,50 @@ reopen_error_exit:
                mutex_unlock(&pCifsFile->fh_mutex);
                cFYI(1, "cifs_open returned 0x%x", rc);
                cFYI(1, "oplock: %d", oplock);
-       } else {
+               goto reopen_error_exit;
+       }
+
 reopen_success:
-               pCifsFile->netfid = netfid;
-               pCifsFile->invalidHandle = false;
-               mutex_unlock(&pCifsFile->fh_mutex);
-               pCifsInode = CIFS_I(inode);
-               if (pCifsInode) {
-                       if (can_flush) {
-                               rc = filemap_write_and_wait(inode->i_mapping);
-                               if (rc != 0)
-                                       CIFS_I(inode)->write_behind_rc = rc;
-                       /* temporarily disable caching while we
-                          go to server to get inode info */
-                               pCifsInode->clientCanCacheAll = false;
-                               pCifsInode->clientCanCacheRead = false;
-                               if (tcon->unix_ext)
-                                       rc = cifs_get_inode_info_unix(&inode,
-                                               full_path, inode->i_sb, xid);
-                               else
-                                       rc = cifs_get_inode_info(&inode,
-                                               full_path, NULL, inode->i_sb,
-                                               xid, NULL);
-                       } /* else we are writing out data to server already
-                            and could deadlock if we tried to flush data, and
-                            since we do not know if we have data that would
-                            invalidate the current end of file on the server
-                            we can not go to the server to get the new inod
-                            info */
-                       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-                               pCifsInode->clientCanCacheAll = true;
-                               pCifsInode->clientCanCacheRead = true;
-                               cFYI(1, "Exclusive Oplock granted on inode %p",
-                                        file->f_path.dentry->d_inode);
-                       } else if ((oplock & 0xF) == OPLOCK_READ) {
-                               pCifsInode->clientCanCacheRead = true;
-                               pCifsInode->clientCanCacheAll = false;
-                       } else {
-                               pCifsInode->clientCanCacheRead = false;
-                               pCifsInode->clientCanCacheAll = false;
-                       }
-                       cifs_relock_file(pCifsFile);
-               }
+       pCifsFile->netfid = netfid;
+       pCifsFile->invalidHandle = false;
+       mutex_unlock(&pCifsFile->fh_mutex);
+       pCifsInode = CIFS_I(inode);
+
+       if (can_flush) {
+               rc = filemap_write_and_wait(inode->i_mapping);
+               if (rc != 0)
+                       CIFS_I(inode)->write_behind_rc = rc;
+
+               pCifsInode->clientCanCacheAll = false;
+               pCifsInode->clientCanCacheRead = false;
+               if (tcon->unix_ext)
+                       rc = cifs_get_inode_info_unix(&inode,
+                               full_path, inode->i_sb, xid);
+               else
+                       rc = cifs_get_inode_info(&inode,
+                               full_path, NULL, inode->i_sb,
+                               xid, NULL);
+       } /* else we are writing out data to server already
+            and could deadlock if we tried to flush data, and
+            since we do not know if we have data that would
+            invalidate the current end of file on the server
+            we can not go to the server to get the new inod
+            info */
+       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+               pCifsInode->clientCanCacheAll = true;
+               pCifsInode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                        pCifsFile->dentry->d_inode);
+       } else if ((oplock & 0xF) == OPLOCK_READ) {
+               pCifsInode->clientCanCacheRead = true;
+               pCifsInode->clientCanCacheAll = false;
+       } else {
+               pCifsInode->clientCanCacheRead = false;
+               pCifsInode->clientCanCacheAll = false;
        }
+       cifs_relock_file(pCifsFile);
+
+reopen_error_exit:
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -505,79 +645,11 @@ reopen_success:
 
 int cifs_close(struct inode *inode, struct file *file)
 {
-       int rc = 0;
-       int xid, timeout;
-       struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
-       struct cifsFileInfo *pSMBFile = file->private_data;
+       cifsFileInfo_put(file->private_data);
+       file->private_data = NULL;
 
-       xid = GetXid();
-
-       cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = tlink_tcon(pSMBFile->tlink);
-       if (pSMBFile) {
-               struct cifsLockInfo *li, *tmp;
-               write_lock(&GlobalSMBSeslock);
-               pSMBFile->closePend = true;
-               if (pTcon) {
-                       /* no sense reconnecting to close a file that is
-                          already closed */
-                       if (!pTcon->need_reconnect) {
-                               write_unlock(&GlobalSMBSeslock);
-                               timeout = 2;
-                               while ((atomic_read(&pSMBFile->count) != 1)
-                                       && (timeout <= 2048)) {
-                                       /* Give write a better chance to get to
-                                       server ahead of the close.  We do not
-                                       want to add a wait_q here as it would
-                                       increase the memory utilization as
-                                       the struct would be in each open file,
-                                       but this should give enough time to
-                                       clear the socket */
-                                       cFYI(DBG2, "close delay, write pending");
-                                       msleep(timeout);
-                                       timeout *= 4;
-                               }
-                               if (!pTcon->need_reconnect &&
-                                   !pSMBFile->invalidHandle)
-                                       rc = CIFSSMBClose(xid, pTcon,
-                                                 pSMBFile->netfid);
-                       } else
-                               write_unlock(&GlobalSMBSeslock);
-               } else
-                       write_unlock(&GlobalSMBSeslock);
-
-               /* Delete any outstanding lock records.
-                  We'll lose them when the file is closed anyway. */
-               mutex_lock(&pSMBFile->lock_mutex);
-               list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
-                       list_del(&li->llist);
-                       kfree(li);
-               }
-               mutex_unlock(&pSMBFile->lock_mutex);
-
-               write_lock(&GlobalSMBSeslock);
-               list_del(&pSMBFile->flist);
-               list_del(&pSMBFile->tlist);
-               write_unlock(&GlobalSMBSeslock);
-               cifsFileInfo_put(file->private_data);
-               file->private_data = NULL;
-       } else
-               rc = -EBADF;
-
-       read_lock(&GlobalSMBSeslock);
-       if (list_empty(&(CIFS_I(inode)->openFileList))) {
-               cFYI(1, "closing last open instance for inode %p", inode);
-               /* if the file is not open we do not know if we can cache info
-                  on this inode, much less write behind and read ahead */
-               CIFS_I(inode)->clientCanCacheRead = false;
-               CIFS_I(inode)->clientCanCacheAll  = false;
-       }
-       read_unlock(&GlobalSMBSeslock);
-       if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
-               rc = CIFS_I(inode)->write_behind_rc;
-       FreeXid(xid);
-       return rc;
+       /* return code from the ->release op is always ignored */
+       return 0;
 }
 
 int cifs_closedir(struct inode *inode, struct file *file)
@@ -595,18 +667,18 @@ int cifs_closedir(struct inode *inode, struct file *file)
                struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink);
 
                cFYI(1, "Freeing private data in close dir");
-               write_lock(&GlobalSMBSeslock);
+               spin_lock(&cifs_file_list_lock);
                if (!pCFileStruct->srch_inf.endOfSearch &&
                    !pCFileStruct->invalidHandle) {
                        pCFileStruct->invalidHandle = true;
-                       write_unlock(&GlobalSMBSeslock);
+                       spin_unlock(&cifs_file_list_lock);
                        rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
                        cFYI(1, "Closing uncompleted readdir with rc %d",
                                 rc);
                        /* not much we can do if it fails anyway, ignore rc */
                        rc = 0;
                } else
-                       write_unlock(&GlobalSMBSeslock);
+                       spin_unlock(&cifs_file_list_lock);
                ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
                if (ptmp) {
                        cFYI(1, "closedir free smb buf in srch struct");
@@ -924,19 +996,12 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                           we blocked so return what we managed to write */
                                return total_written;
                        }
-                       if (open_file->closePend) {
-                               FreeXid(xid);
-                               if (total_written)
-                                       return total_written;
-                               else
-                                       return -EBADF;
-                       }
                        if (open_file->invalidHandle) {
                                /* we could deadlock if we called
                                   filemap_fdatawait from here so tell
                                   reopen_file not to flush data to server
                                   now */
-                               rc = cifs_reopen_file(file, false);
+                               rc = cifs_reopen_file(open_file, false);
                                if (rc != 0)
                                        break;
                        }
@@ -984,8 +1049,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        return total_written;
 }
 
-static ssize_t cifs_write(struct file *file, const char *write_data,
-                         size_t write_size, loff_t *poffset)
+static ssize_t cifs_write(struct cifsFileInfo *open_file,
+                         const char *write_data, size_t write_size,
+                         loff_t *poffset)
 {
        int rc = 0;
        unsigned int bytes_written = 0;
@@ -993,17 +1059,14 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        int xid, long_op;
-       struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
+       struct dentry *dentry = open_file->dentry;
+       struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       cifs_sb = CIFS_SB(dentry->d_sb);
 
        cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
-          *poffset, file->f_path.dentry->d_name.name);
+          *poffset, dentry->d_name.name);
 
-       if (file->private_data == NULL)
-               return -EBADF;
-       open_file = file->private_data;
        pTcon = tlink_tcon(open_file->tlink);
 
        xid = GetXid();
@@ -1013,28 +1076,12 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
             total_written += bytes_written) {
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       if (file->private_data == NULL) {
-                               /* file has been closed on us */
-                               FreeXid(xid);
-                       /* if we have gotten here we have written some data
-                          and blocked, and the file has been freed on us
-                          while we blocked so return what we managed to
-                          write */
-                               return total_written;
-                       }
-                       if (open_file->closePend) {
-                               FreeXid(xid);
-                               if (total_written)
-                                       return total_written;
-                               else
-                                       return -EBADF;
-                       }
                        if (open_file->invalidHandle) {
                                /* we could deadlock if we called
                                   filemap_fdatawait from here so tell
                                   reopen_file not to flush data to
                                   server now */
-                               rc = cifs_reopen_file(file, false);
+                               rc = cifs_reopen_file(open_file, false);
                                if (rc != 0)
                                        break;
                        }
@@ -1081,20 +1128,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
        cifs_stats_bytes_written(pTcon, total_written);
 
-       /* since the write may have blocked check these pointers again */
-       if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
-/*BB We could make this contingent on superblock ATIME flag too */
-/*             file->f_path.dentry->d_inode->i_ctime =
-               file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
-               if (total_written > 0) {
-                       spin_lock(&file->f_path.dentry->d_inode->i_lock);
-                       if (*poffset > file->f_path.dentry->d_inode->i_size)
-                               i_size_write(file->f_path.dentry->d_inode,
-                                            *poffset);
-                       spin_unlock(&file->f_path.dentry->d_inode->i_lock);
-               }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+       if (total_written > 0) {
+               spin_lock(&dentry->d_inode->i_lock);
+               if (*poffset > dentry->d_inode->i_size)
+                       i_size_write(dentry->d_inode, *poffset);
+               spin_unlock(&dentry->d_inode->i_lock);
        }
+       mark_inode_dirty_sync(dentry->d_inode);
        FreeXid(xid);
        return total_written;
 }
@@ -1110,22 +1150,19 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
 
-       read_lock(&GlobalSMBSeslock);
+       spin_lock(&cifs_file_list_lock);
        /* we could simply get the first_list_entry since write-only entries
           are always at the end of the list but since the first entry might
           have a close pending, we go through the whole list */
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-               if (open_file->closePend)
-                       continue;
                if (fsuid_only && open_file->uid != current_fsuid())
                        continue;
-               if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
-                   (open_file->pfile->f_flags & O_RDONLY))) {
+               if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) {
                        if (!open_file->invalidHandle) {
                                /* found a good file */
                                /* lock it so it will not be closed on us */
                                cifsFileInfo_get(open_file);
-                               read_unlock(&GlobalSMBSeslock);
+                               spin_unlock(&cifs_file_list_lock);
                                return open_file;
                        } /* else might as well continue, and look for
                             another, or simply have the caller reopen it
@@ -1133,7 +1170,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
                } else /* write only file */
                        break; /* write only files are last so must be done */
        }
-       read_unlock(&GlobalSMBSeslock);
+       spin_unlock(&cifs_file_list_lock);
        return NULL;
 }
 #endif
@@ -1160,55 +1197,35 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
 
-       read_lock(&GlobalSMBSeslock);
+       spin_lock(&cifs_file_list_lock);
 refind_writable:
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-               if (open_file->closePend)
-                       continue;
                if (!any_available && open_file->pid != current->tgid)
                        continue;
                if (fsuid_only && open_file->uid != current_fsuid())
                        continue;
-               if (open_file->pfile &&
-                   ((open_file->pfile->f_flags & O_RDWR) ||
-                    (open_file->pfile->f_flags & O_WRONLY))) {
+               if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        cifsFileInfo_get(open_file);
 
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
-                               read_unlock(&GlobalSMBSeslock);
+                               spin_unlock(&cifs_file_list_lock);
                                return open_file;
                        }
 
-                       read_unlock(&GlobalSMBSeslock);
+                       spin_unlock(&cifs_file_list_lock);
+
                        /* Had to unlock since following call can block */
-                       rc = cifs_reopen_file(open_file->pfile, false);
-                       if (!rc) {
-                               if (!open_file->closePend)
-                                       return open_file;
-                               else { /* start over in case this was deleted */
-                                      /* since the list could be modified */
-                                       read_lock(&GlobalSMBSeslock);
-                                       cifsFileInfo_put(open_file);
-                                       goto refind_writable;
-                               }
-                       }
+                       rc = cifs_reopen_file(open_file, false);
+                       if (!rc)
+                               return open_file;
 
-                       /* if it fails, try another handle if possible -
-                       (we can not do this if closePending since
-                       loop could be modified - in which case we
-                       have to start at the beginning of the list
-                       again. Note that it would be bad
-                       to hold up writepages here (rather than
-                       in caller) with continuous retries */
+                       /* if it fails, try another handle if possible */
                        cFYI(1, "wp failed on reopen file");
-                       read_lock(&GlobalSMBSeslock);
-                       /* can not use this handle, no write
-                          pending on this one after all */
                        cifsFileInfo_put(open_file);
 
-                       if (open_file->closePend) /* list could have changed */
-                               goto refind_writable;
+                       spin_lock(&cifs_file_list_lock);
+
                        /* else we simply continue to the next entry. Thus
                           we do not loop on reopen errors.  If we
                           can not reopen the file, for example if we
@@ -1223,7 +1240,7 @@ refind_writable:
                any_available = true;
                goto refind_writable;
        }
-       read_unlock(&GlobalSMBSeslock);
+       spin_unlock(&cifs_file_list_lock);
        return NULL;
 }
 
@@ -1265,8 +1282,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 
        open_file = find_writable_file(CIFS_I(mapping->host), false);
        if (open_file) {
-               bytes_written = cifs_write(open_file->pfile, write_data,
-                                          to-from, &offset);
+               bytes_written = cifs_write(open_file, write_data,
+                                          to - from, &offset);
                cifsFileInfo_put(open_file);
                /* Does mm or vfs already set times? */
                inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
@@ -1286,7 +1303,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 static int cifs_writepages(struct address_space *mapping,
                           struct writeback_control *wbc)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        unsigned int bytes_to_write;
        unsigned int bytes_written;
        struct cifs_sb_info *cifs_sb;
@@ -1309,15 +1325,6 @@ static int cifs_writepages(struct address_space *mapping,
        int scanned = 0;
        int xid, long_op;
 
-       /*
-        * BB: Is this meaningful for a non-block-device file system?
-        * If it is, we should test it again after we do I/O
-        */
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
        cifs_sb = CIFS_SB(mapping->host->i_sb);
 
        /*
@@ -1581,7 +1588,8 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
                /* BB check if anything else missing out of ppw
                   such as updating last write time */
                page_data = kmap(page);
-               rc = cifs_write(file, page_data + offset, copied, &pos);
+               rc = cifs_write(file->private_data, page_data + offset,
+                               copied, &pos);
                /* if (rc < 0) should we set writebehind rc? */
                kunmap(page);
 
@@ -1728,9 +1736,8 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                smb_read_data = NULL;
                while (rc == -EAGAIN) {
                        int buf_type = CIFS_NO_BUFFER;
-                       if ((open_file->invalidHandle) &&
-                           (!open_file->closePend)) {
-                               rc = cifs_reopen_file(file, true);
+                       if (open_file->invalidHandle) {
+                               rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
                        }
@@ -1814,9 +1821,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                }
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       if ((open_file->invalidHandle) &&
-                           (!open_file->closePend)) {
-                               rc = cifs_reopen_file(file, true);
+                       if (open_file->invalidHandle) {
+                               rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
                        }
@@ -1979,9 +1985,8 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                read_size, contig_pages);
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       if ((open_file->invalidHandle) &&
-                           (!open_file->closePend)) {
-                               rc = cifs_reopen_file(file, true);
+                       if (open_file->invalidHandle) {
+                               rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
                        }
@@ -2130,18 +2135,14 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
 {
        struct cifsFileInfo *open_file;
 
-       read_lock(&GlobalSMBSeslock);
+       spin_lock(&cifs_file_list_lock);
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-               if (open_file->closePend)
-                       continue;
-               if (open_file->pfile &&
-                   ((open_file->pfile->f_flags & O_RDWR) ||
-                    (open_file->pfile->f_flags & O_WRONLY))) {
-                       read_unlock(&GlobalSMBSeslock);
+               if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
+                       spin_unlock(&cifs_file_list_lock);
                        return 1;
                }
        }
-       read_unlock(&GlobalSMBSeslock);
+       spin_unlock(&cifs_file_list_lock);
        return 0;
 }
 
@@ -2294,7 +2295,7 @@ void cifs_oplock_break(struct work_struct *work)
         * not bother sending an oplock release if session to server still is
         * disconnected since oplock already released by the server
         */
-       if (!cfile->closePend && !cfile->oplock_break_cancelled) {
+       if (!cfile->oplock_break_cancelled) {
                rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
                                 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
                cFYI(1, "Oplock release rc = %d", rc);
@@ -2305,8 +2306,8 @@ void cifs_oplock_break(struct work_struct *work)
         * finished grabbing reference for us.  Make sure it's done by
         * waiting for GlobalSMSSeslock.
         */
-       write_lock(&GlobalSMBSeslock);
-       write_unlock(&GlobalSMBSeslock);
+       spin_lock(&cifs_file_list_lock);
+       spin_unlock(&cifs_file_list_lock);
 
        cifs_oplock_break_put(cfile);
 }