xfs
[Top] [All Lists]

grab_cache_page deadlock | was Re: set_buffer_dirty_uptodate

To: Rajagopal Ananthanarayanan <ananth@xxxxxxx>
Subject: grab_cache_page deadlock | was Re: set_buffer_dirty_uptodate
From: Marcelo Tosatti <marcelo@xxxxxxxxxxxxxxxx>
Date: Wed, 27 Dec 2000 14:48:17 -0200 (BRST)
Cc: linux-xfs@xxxxxxxxxxx
In-reply-to: <Pine.LNX.4.21.0012261924330.872-100000@freak.distro.conectiva>
Sender: owner-linux-xfs@xxxxxxxxxxx
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);


<Prev in Thread] Current Thread [Next in Thread>