Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / fs / cifs / file.c
index 26048dc..ae82159 100644 (file)
@@ -131,8 +131,7 @@ static inline int cifs_open_inode_helper(struct inode *inode,
                        /* BB no need to lock inode until after invalidate
                        since namei code should already have it locked? */
                        rc = filemap_write_and_wait(inode->i_mapping);
-                       if (rc != 0)
-                               pCifsInode->write_behind_rc = rc;
+                       mapping_set_error(inode->i_mapping, rc);
                }
                cFYI(1, "invalidating remote inode since open detected it "
                         "changed");
@@ -232,18 +231,17 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
        if (pCifsFile == NULL)
                return pCifsFile;
 
+       pCifsFile->count = 1;
        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->closePend = 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);
@@ -266,6 +264,58 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
        return pCifsFile;
 }
 
+/*
+ * Release a reference on the file private data. This may involve closing
+ * the filehandle out on the server. Must be called without holding
+ * cifs_file_list_lock.
+ */
+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 (--cifs_file->count > 0) {
+               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;
@@ -555,8 +605,7 @@ reopen_success:
 
        if (can_flush) {
                rc = filemap_write_and_wait(inode->i_mapping);
-               if (rc != 0)
-                       CIFS_I(inode)->write_behind_rc = rc;
+               mapping_set_error(inode->i_mapping, rc);
 
                pCifsInode->clientCanCacheAll = false;
                pCifsInode->clientCanCacheRead = false;
@@ -595,79 +644,11 @@ reopen_error_exit:
 
 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;
-
-       xid = GetXid();
-
-       cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = tlink_tcon(pSMBFile->tlink);
-       if (pSMBFile) {
-               struct cifsLockInfo *li, *tmp;
-               spin_lock(&cifs_file_list_lock);
-               pSMBFile->closePend = true;
-               if (pTcon) {
-                       /* no sense reconnecting to close a file that is
-                          already closed */
-                       if (!pTcon->need_reconnect) {
-                               spin_unlock(&cifs_file_list_lock);
-                               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
-                               spin_unlock(&cifs_file_list_lock);
-               } else
-                       spin_unlock(&cifs_file_list_lock);
-
-               /* 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);
+       cifsFileInfo_put(file->private_data);
+       file->private_data = NULL;
 
-               spin_lock(&cifs_file_list_lock);
-               list_del(&pSMBFile->flist);
-               list_del(&pSMBFile->tlist);
-               spin_unlock(&cifs_file_list_lock);
-               cifsFileInfo_put(file->private_data);
-               file->private_data = NULL;
-       } else
-               rc = -EBADF;
-
-       spin_lock(&cifs_file_list_lock);
-       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;
-       }
-       spin_unlock(&cifs_file_list_lock);
-       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)
@@ -1014,13 +995,6 @@ 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
@@ -1101,13 +1075,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
             total_written += bytes_written) {
                rc = -EAGAIN;
                while (rc == -EAGAIN) {
-                       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
@@ -1187,8 +1154,6 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
           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_FMODE(open_file->f_flags) & FMODE_READ) {
@@ -1234,8 +1199,6 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
        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())
@@ -1250,34 +1213,18 @@ refind_writable:
                        }
 
                        spin_unlock(&cifs_file_list_lock);
+
                        /* Had to unlock since following call can block */
                        rc = cifs_reopen_file(open_file, false);
-                       if (!rc) {
-                               if (!open_file->closePend)
-                                       return open_file;
-                               else { /* start over in case this was deleted */
-                                      /* since the list could be modified */
-                                       spin_lock(&cifs_file_list_lock);
-                                       cifsFileInfo_put(open_file);
-                                       goto refind_writable;
-                               }
-                       }
+                       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");
-                       spin_lock(&cifs_file_list_lock);
-                       /* 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
@@ -1355,7 +1302,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;
@@ -1378,15 +1324,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);
 
        /*
@@ -1415,6 +1352,7 @@ static int cifs_writepages(struct address_space *mapping,
        if (!experimEnabled && tcon->ses->server->secMode &
                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
                cifsFileInfo_put(open_file);
+               kfree(iov);
                return generic_writepages(mapping, wbc);
        }
        cifsFileInfo_put(open_file);
@@ -1540,12 +1478,7 @@ retry:
                        if (rc || bytes_written < bytes_to_write) {
                                cERROR(1, "Write2 ret %d, wrote %d",
                                          rc, bytes_written);
-                               /* BB what if continued retry is
-                                  requested via mount flags? */
-                               if (rc == -ENOSPC)
-                                       set_bit(AS_ENOSPC, &mapping->flags);
-                               else
-                                       set_bit(AS_EIO, &mapping->flags);
+                               mapping_set_error(mapping, rc);
                        } else {
                                cifs_stats_bytes_written(tcon, bytes_written);
                        }
@@ -1690,11 +1623,10 @@ int cifs_fsync(struct file *file, int datasync)
 
        rc = filemap_write_and_wait(inode->i_mapping);
        if (rc == 0) {
-               rc = CIFS_I(inode)->write_behind_rc;
-               CIFS_I(inode)->write_behind_rc = 0;
+               struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+
                tcon = tlink_tcon(smbfile->tlink);
-               if (!rc && tcon && smbfile &&
-                  !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+               if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
                        rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
        }
 
@@ -1739,21 +1671,8 @@ int cifs_flush(struct file *file, fl_owner_t id)
        struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
 
-       /* Rather than do the steps manually:
-          lock the inode for writing
-          loop through pages looking for write behind data (dirty pages)
-          coalesce into contiguous 16K (or smaller) chunks to write to server
-          send to server (prefer in parallel)
-          deal with writebehind errors
-          unlock inode for writing
-          filemapfdatawrite appears easier for the time being */
-
-       rc = filemap_fdatawrite(inode->i_mapping);
-       /* reset wb rc if we were able to write out dirty pages */
-       if (!rc) {
-               rc = CIFS_I(inode)->write_behind_rc;
-               CIFS_I(inode)->write_behind_rc = 0;
-       }
+       if (file->f_mode & FMODE_WRITE)
+               rc = filemap_write_and_wait(inode->i_mapping);
 
        cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc);
 
@@ -1798,8 +1717,7 @@ 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)) {
+                       if (open_file->invalidHandle) {
                                rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
@@ -1884,8 +1802,7 @@ 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)) {
+                       if (open_file->invalidHandle) {
                                rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
@@ -2049,8 +1966,7 @@ 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)) {
+                       if (open_file->invalidHandle) {
                                rc = cifs_reopen_file(open_file, true);
                                if (rc != 0)
                                        break;
@@ -2202,8 +2118,6 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
 
        spin_lock(&cifs_file_list_lock);
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-               if (open_file->closePend)
-                       continue;
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        spin_unlock(&cifs_file_list_lock);
                        return 1;
@@ -2337,7 +2251,7 @@ void cifs_oplock_break(struct work_struct *work)
                                                  oplock_break);
        struct inode *inode = cfile->dentry->d_inode;
        struct cifsInodeInfo *cinode = CIFS_I(inode);
-       int rc, waitrc = 0;
+       int rc = 0;
 
        if (inode && S_ISREG(inode->i_mode)) {
                if (cinode->clientCanCacheRead)
@@ -2346,13 +2260,10 @@ void cifs_oplock_break(struct work_struct *work)
                        break_lease(inode, O_WRONLY);
                rc = filemap_fdatawrite(inode->i_mapping);
                if (cinode->clientCanCacheRead == 0) {
-                       waitrc = filemap_fdatawait(inode->i_mapping);
+                       rc = filemap_fdatawait(inode->i_mapping);
+                       mapping_set_error(inode->i_mapping, rc);
                        invalidate_remote_inode(inode);
                }
-               if (!rc)
-                       rc = waitrc;
-               if (rc)
-                       cinode->write_behind_rc = rc;
                cFYI(1, "Oplock flush inode %p rc %d", inode, rc);
        }
 
@@ -2362,7 +2273,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);
@@ -2371,7 +2282,7 @@ void cifs_oplock_break(struct work_struct *work)
        /*
         * We might have kicked in before is_valid_oplock_break()
         * finished grabbing reference for us.  Make sure it's done by
-        * waiting for GlobalSMSSeslock.
+        * waiting for cifs_file_list_lock.
         */
        spin_lock(&cifs_file_list_lock);
        spin_unlock(&cifs_file_list_lock);
@@ -2379,6 +2290,7 @@ void cifs_oplock_break(struct work_struct *work)
        cifs_oplock_break_put(cfile);
 }
 
+/* must be called while holding cifs_file_list_lock */
 void cifs_oplock_break_get(struct cifsFileInfo *cfile)
 {
        cifs_sb_active(cfile->dentry->d_sb);