On Tue, 26 Dec 2000, Marcelo Tosatti wrote:
> The correct solution to your problem is to not pass __GFP_IO in the
> allocation flag passed to __alloc_pages.
>
> This way the allocation routines will not try to do any kind of IO and
> will not wait for kswapd.
>
> Its pretty easy to change page_cache_alloc() to pass our own
> allocation flag and fix this problem.
>
> I'm going home soon but I'll do that tomorrow if you're not going to do
> it.
So here it goes.
Ananth,
Could you try to reproduce the deadlock with this patch applied?
The patch is against latest XFS CVS tree.
Index: linux/fs/nfs/dir.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/fs/nfs/dir.c,v
retrieving revision 1.24
diff -u -r1.24 dir.c
--- linux/fs/nfs/dir.c 2000/12/17 19:15:00 1.24
+++ linux/fs/nfs/dir.c 2000/12/27 18:32:52
@@ -321,7 +321,7 @@
desc->page = NULL;
}
- page = page_cache_alloc();
+ page = page_cache_alloc(GFP_HIGHUSER);
if (!page) {
status = -ENOMEM;
goto out;
Index: linux/fs/pagebuf/page_buf_io.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/fs/pagebuf/page_buf_io.c,v
retrieving revision 1.37
diff -u -r1.37 page_buf_io.c
--- linux/fs/pagebuf/page_buf_io.c 2000/12/17 19:15:00 1.37
+++ linux/fs/pagebuf/page_buf_io.c 2000/12/27 18:32:56
@@ -1477,8 +1477,9 @@
int at_eof;
unsigned long offset_in_page;
- page = grab_cache_page(inode->i_mapping,
- rounded_offset >> PAGE_CACHE_SHIFT);
+ page = _grab_cache_page(inode->i_mapping,
+ rounded_offset >> PAGE_CACHE_SHIFT,
+ __GFP_WAIT | __GFP_HIGHMEM);
if (!page) {
err = -ENOMEM;
Index: linux/include/linux/pagemap.h
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/include/linux/pagemap.h,v
retrieving revision 1.20
diff -u -r1.20 pagemap.h
--- linux/include/linux/pagemap.h 2000/12/21 05:48:12 1.20
+++ linux/include/linux/pagemap.h 2000/12/27 18:34:25
@@ -29,7 +29,7 @@
#define PAGE_CACHE_ALIGN(addr) (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
#define page_cache_get(x) get_page(x)
-#define page_cache_alloc() alloc_pages(GFP_HIGHUSER, 0)
+#define page_cache_alloc(flag) alloc_pages(flag, 0)
#define page_cache_free(x) __free_page(x)
#define page_cache_release(x) __free_page(x)
@@ -120,7 +120,8 @@
___wait_on_page(page);
}
-extern struct page * grab_cache_page (struct address_space *, unsigned long);
+#define grab_cache_page(mapping, index) _grab_cache_page(mapping, index,
GFP_HIGHUSER)
+extern struct page * _grab_cache_page (struct address_space *, unsigned long,
unsigned long);
typedef int filler_t(void *, struct page*);
Index: linux/kernel/ksyms.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/kernel/ksyms.c,v
retrieving revision 1.68
diff -u -r1.68 ksyms.c
--- linux/kernel/ksyms.c 2000/12/21 05:48:12 1.68
+++ linux/kernel/ksyms.c 2000/12/27 18:34:51
@@ -262,7 +262,7 @@
EXPORT_SYMBOL(ROOT_DEV);
EXPORT_SYMBOL(__find_lock_page);
EXPORT_SYMBOL(__find_lock_page_nowait);
-EXPORT_SYMBOL(grab_cache_page);
+EXPORT_SYMBOL(_grab_cache_page);
EXPORT_SYMBOL(read_cache_page);
EXPORT_SYMBOL(vfs_readlink);
EXPORT_SYMBOL(vfs_follow_link);
Index: linux/mm/filemap.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/mm/filemap.c,v
retrieving revision 1.60
diff -u -r1.60 filemap.c
--- linux/mm/filemap.c 2000/12/21 05:48:12 1.60
+++ linux/mm/filemap.c 2000/12/27 18:34:53
@@ -460,7 +460,7 @@
if (page)
return 0;
- page = page_cache_alloc();
+ page = page_cache_alloc(GFP_HIGHUSER);
if (!page)
return -ENOMEM;
@@ -1113,7 +1113,7 @@
#endif
if (!cached_page) {
spin_unlock(&pagecache_lock);
- cached_page = page_cache_alloc();
+ cached_page = page_cache_alloc(GFP_HIGHUSER);
if (!cached_page) {
desc->error = -ENOMEM;
break;
@@ -1413,7 +1413,7 @@
*/
old_page = page;
if (no_share) {
- struct page *new_page = page_cache_alloc();
+ struct page *new_page = page_cache_alloc(GFP_HIGHUSER);
if (new_page) {
copy_user_highpage(new_page, old_page, address);
@@ -2325,7 +2325,7 @@
page = __find_get_page(mapping, index, hash);
if (!page) {
if (!cached_page) {
- cached_page = page_cache_alloc();
+ cached_page = page_cache_alloc(GFP_HIGHUSER);
if (!cached_page)
return ERR_PTR(-ENOMEM);
}
@@ -2381,14 +2381,15 @@
}
static inline struct page * __grab_cache_page(struct address_space *mapping,
- unsigned long index, struct page **cached_page)
+ unsigned long index, struct page **cached_page,
+ unsigned long flags)
{
struct page *page, **hash = page_hash(mapping, index);
repeat:
page = __find_lock_page(mapping, index, hash);
if (!page) {
if (!*cached_page) {
- *cached_page = page_cache_alloc();
+ *cached_page = page_cache_alloc(flags);
if (!*cached_page)
return NULL;
}
@@ -2404,10 +2405,11 @@
* Returns locked page at given index in given cache, creating it if needed.
*/
-struct page *grab_cache_page(struct address_space *mapping, unsigned long
index)
+struct page * _grab_cache_page(struct address_space *mapping, unsigned long
index,
+ unsigned long flags)
{
struct page *cached_page = NULL;
- struct page *page = __grab_cache_page(mapping,index,&cached_page);
+ struct page *page = __grab_cache_page(mapping,index,&cached_page,flags);
if (cached_page)
page_cache_free(cached_page);
return page;
@@ -2512,7 +2514,7 @@
bytes = count;
status = -ENOMEM; /* we'll assign it later anyway */
- page = __grab_cache_page(mapping, index, &cached_page);
+ page = __grab_cache_page(mapping, index, &cached_page,
GFP_HIGHUSER);
if (!page)
break;
Index: linux/mm/memory.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/mm/memory.c,v
retrieving revision 1.40
diff -u -r1.40 memory.c
--- linux/mm/memory.c 2000/12/17 19:15:00 1.40
+++ linux/mm/memory.c 2000/12/27 18:34:54
@@ -865,7 +865,7 @@
* Ok, we need to copy. Oh, well..
*/
spin_unlock(&mm->page_table_lock);
- new_page = page_cache_alloc();
+ new_page = page_cache_alloc(GFP_HIGHUSER);
if (!new_page)
return -1;
spin_lock(&mm->page_table_lock);
Index: linux/mm/shmem.c
===================================================================
RCS file: /cvs/linux-2.4-xfs/linux/mm/shmem.c,v
retrieving revision 1.1
diff -u -r1.1 shmem.c
--- linux/mm/shmem.c 2000/12/21 05:48:12 1.1
+++ linux/mm/shmem.c 2000/12/27 18:34:54
@@ -317,7 +317,7 @@
inode->i_sb->u.shmem_sb.free_blocks--;
spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
/* Ok, get a new page */
- page = page_cache_alloc();
+ page = page_cache_alloc(GFP_HIGHUSER);
if (!page)
goto oom;
clear_user_highpage(page, address);
@@ -332,7 +332,7 @@
up(&inode->i_sem);
if (no_share) {
- struct page *new_page = page_cache_alloc();
+ struct page *new_page = page_cache_alloc(GFP_HIGHUSER);
if (new_page) {
copy_user_highpage(new_page, page, address);
|