lkml.org 
[lkml]   [2002]   [Dec]   [12]   [last100]   RSS Feed
Views: [more markup]   [less markup]   [headers]   [forward]  
 
Messages in this thread
Patch in this message
/
DateThu, 12 Dec 2002 11:26:58 +0100
Subject[PATCH 2.4.21-pre] Fix possible SMP race in nfs_sync_page()
FromTrond Myklebust <>
Hi Marcelo,

  The following patch fixes a race in nfs_sync_page() whereby one
thread may call the generic sync_page() and then block on a given page
while another thread is working in mapping->a_ops->readpage().

Cheers,
  Trond

diff -u --recursive --new-file linux-2.4.21-pre1/fs/nfs/file.c linux-2.4.21-01-nfs_sync/fs/nfs/file.c
--- linux-2.4.21-pre1/fs/nfs/file.c	2002-02-05 15:10:21.000000000 +0100
+++ linux-2.4.21-01-nfs_sync/fs/nfs/file.c	2002-12-12 11:23:09.000000000 +0100
@@ -187,6 +187,7 @@
 	if (!inode)
 		return 0;
 
+	NFS_SetPageSync(page);
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
diff -u --recursive --new-file linux-2.4.21-pre1/fs/nfs/read.c linux-2.4.21-01-nfs_sync/fs/nfs/read.c
--- linux-2.4.21-pre1/fs/nfs/read.c	2002-10-06 01:03:40.000000000 +0200
+++ linux-2.4.21-01-nfs_sync/fs/nfs/read.c	2002-12-12 11:23:09.000000000 +0100
@@ -171,11 +171,16 @@
 	struct nfs_page	*new;
 
 	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
-	if (IS_ERR(new))
+	if (IS_ERR(new)) {
+		SetPageError(page);
+		NFS_ClearPageSync(page);
+		UnlockPage(page);
 		return PTR_ERR(new);
+	}
 	nfs_mark_request_read(new);
 
-	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	if (NFS_TestClearPageSync(page) ||
+	    inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
 	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
 		nfs_pagein_inode(inode, 0, 0);
 	return 0;
@@ -222,6 +227,7 @@
 		req = nfs_list_entry(head->next);
 		page = req->wb_page;
 		nfs_list_remove_request(req);
+		NFS_ClearPageSync(page);
 		SetPageError(page);
 		UnlockPage(page);
 		nfs_clear_request(req);
@@ -429,6 +435,7 @@
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
+		NFS_ClearPageSync(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
@@ -482,6 +489,7 @@
 	return error;
 
 out_error:
+	NFS_ClearPageSync(page);
 	UnlockPage(page);
 	goto out;
 }
diff -u --recursive --new-file linux-2.4.21-pre1/include/linux/mm.h linux-2.4.21-01-nfs_sync/include/linux/mm.h
--- linux-2.4.21-pre1/include/linux/mm.h	2002-03-27 00:11:32.000000000 +0100
+++ linux-2.4.21-01-nfs_sync/include/linux/mm.h	2002-12-12 11:23:09.000000000 +0100
@@ -297,6 +297,7 @@
 #define PG_arch_1		13
 #define PG_reserved		14
 #define PG_launder		15	/* written out by VM pressure.. */
+#define PG_fs_1			16	/* Filesystem specific */
 
 /* Make it prettier to test the above... */
 #define UnlockPage(page)	unlock_page(page)
diff -u --recursive --new-file linux-2.4.21-pre1/include/linux/nfs_fs.h linux-2.4.21-01-nfs_sync/include/linux/nfs_fs.h
--- linux-2.4.21-pre1/include/linux/nfs_fs.h	2002-10-15 18:32:18.000000000 +0200
+++ linux-2.4.21-01-nfs_sync/include/linux/nfs_fs.h	2002-12-12 11:23:09.000000000 +0100
@@ -269,6 +269,10 @@
 extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 
+#define NFS_SetPageSync(page)		set_bit(PG_fs_1, &(page)->flags)
+#define NFS_ClearPageSync(page)		clear_bit(PG_fs_1, &(page)->flags)
+#define NFS_TestClearPageSync(page)	test_and_clear_bit(PG_fs_1, &(page)->flags)
+
 /*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 11:31    [W:0.306 / U:0.180 seconds]
©2003-2008 Jasper Spaans