]> git.hungrycats.org Git - linux/commitdiff
cifs: ensure that we always do cifsFileInfo_get under the spinlock
authorJeff Layton <jlayton@redhat.com>
Wed, 25 Jul 2012 18:59:54 +0000 (14:59 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Aug 2012 15:22:54 +0000 (08:22 -0700)
commit 764a1b1acecedfe204cb2e80d8e2cc7c6df1b0b8 upstream.

The readpages bug is a regression that was introduced in 6993f74a5.
This also fixes a couple of similar bugs in the uncached read and write
codepaths.

Also, prevent this sort of thing in the future by having cifsFileInfo_get
take the spinlock itself, and adding a _locked variant for use in places
that are already holding the lock. The _put code has always done that
so this makes for a less confusing interface.

Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsglob.h
fs/cifs/file.c

index 6df0cbe1cbc90bc1fd7e978172ed7f05f36e3cbe..d86ba9f251936ed0e5459a2cdcfbd989ea2c003b 100644 (file)
@@ -657,13 +657,13 @@ struct cifs_io_parms {
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
  */
-static inline
-struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file)
+static inline void
+cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
 {
        ++cifs_file->count;
-       return cifs_file;
 }
 
+struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
 
 /*
index 513adbc211d7029d1c8b1d6670a1a37d9029cac6..2cbda4eb9e1e953355c8daa25b09e62e0cf4b04f 100644 (file)
@@ -284,6 +284,15 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
 
 static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
 
+struct cifsFileInfo *
+cifsFileInfo_get(struct cifsFileInfo *cifs_file)
+{
+       spin_lock(&cifs_file_list_lock);
+       cifsFileInfo_get_locked(cifs_file);
+       spin_unlock(&cifs_file_list_lock);
+       return cifs_file;
+}
+
 /*
  * Release a reference on the file private data. This may involve closing
  * the filehandle out on the server. Must be called without holding
@@ -1563,7 +1572,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
                        if (!open_file->invalidHandle) {
                                /* found a good file */
                                /* lock it so it will not be closed on us */
-                               cifsFileInfo_get(open_file);
+                               cifsFileInfo_get_locked(open_file);
                                spin_unlock(&cifs_file_list_lock);
                                return open_file;
                        } /* else might as well continue, and look for
@@ -1615,7 +1624,7 @@ refind_writable:
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
-                               cifsFileInfo_get(open_file);
+                               cifsFileInfo_get_locked(open_file);
                                spin_unlock(&cifs_file_list_lock);
                                return open_file;
                        } else {
@@ -1632,7 +1641,7 @@ refind_writable:
 
        if (inv_file) {
                any_available = false;
-               cifsFileInfo_get(inv_file);
+               cifsFileInfo_get_locked(inv_file);
        }
 
        spin_unlock(&cifs_file_list_lock);
@@ -3082,8 +3091,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        break;
                }
 
-               spin_lock(&cifs_file_list_lock);
-               spin_unlock(&cifs_file_list_lock);
                rdata->cfile = cifsFileInfo_get(open_file);
                rdata->mapping = mapping;
                rdata->offset = offset;