NFS: Fix nfs_migrate_page()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 10 Dec 2009 14:05:55 +0000 (09:05 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 18 Dec 2009 22:04:09 +0000 (14:04 -0800)
commit 190f38e5cedc910940b1da9015f00458c18f97b4 upstream.

The call to migrate_page() will cause the page->private field to be
cleared.
Also fix up the locking around the page->private transfer, so that we ensure
that calls to nfs_page_find_request() don't end up racing.

Finally, fix up a double free bug: nfs_unlock_request() already calls
nfs_release_request() for us...

Reported-by: Wu Fengguang <fengguang.wu@intel.com>
Tested-by: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/nfs/write.c

index 53eb26c16b50a06c0126f156a1ee6fddc1480413..6fc37762c495c967d9d3edefe0dcecc83dad6341 100644 (file)
@@ -1612,15 +1612,16 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
        if (ret)
                goto out_unlock;
        page_cache_get(newpage);
+       spin_lock(&mapping->host->i_lock);
        req->wb_page = newpage;
        SetPagePrivate(newpage);
-       set_page_private(newpage, page_private(page));
+       set_page_private(newpage, (unsigned long)req);
        ClearPagePrivate(page);
        set_page_private(page, 0);
+       spin_unlock(&mapping->host->i_lock);
        page_cache_release(page);
 out_unlock:
        nfs_clear_page_tag_locked(req);
-       nfs_release_request(req);
 out:
        return ret;
 }