xfs
[Top] [All Lists]

[PATCH] XFS OOM hardening

To: linux-xfs@xxxxxxxxxxx
Subject: [PATCH] XFS OOM hardening
From: Andi Kleen <ak@xxxxxxx>
Date: Tue, 14 Aug 2001 21:14:07 +0200
Sender: owner-linux-xfs@xxxxxxxxxxx
User-agent: Mutt/1.2.5i
I ran into a few problems  with XFS running out of memory and crashing
and did a few changes to fix the most obvious problems. The only tricky
bit is the ENOMEM return in xfs_trans_read_buf(); there may be some
callers that handle NULL correctly but most seem not to when the error
return is zero. The others are straight forward. I replace the panics 
in kmem.c with random retries with printks to give it some chance to
recover. Sometimes it deadlocks unfortunately (probably because too
many locks are held), but in other cases it recovers and that's better 
than a panic. I also fixed oom checking in some other easy cases.

This patch also fixes an unrelated bug -- pagebuf sometimes sets 
pb_error to negative errno when the rest of XFS expects positive here.

-Andi


--- linux-xfs/fs/pagebuf/page_buf.c-XFSMEM      Tue Aug 14 01:12:43 2001
+++ linux-xfs/fs/pagebuf/page_buf.c     Tue Aug 14 20:43:57 2001
@@ -1055,6 +1055,8 @@
 int pagebuf_geterror(          /* return buffer error          */
     page_buf_t * pb)           /* buffer                       */
 {
+       if (!pb) 
+               return ENOMEM;
        return (pb->pb_error);
 }
 
@@ -1200,7 +1202,7 @@
        page = bh->b_page;
        if (!test_bit(BH_Uptodate, &bh->b_state)) {
                set_bit(PG_error, &page->flags);
-               pb->pb_error = -EIO;
+               pb->pb_error = EIO;
        }
 
        unlock_buffer(bh);
@@ -1221,7 +1223,7 @@
        page = bh->b_page;
        if (!test_bit(BH_Uptodate, &bh->b_state)) {
                set_bit(PG_error, &page->flags);
-               pb->pb_error = -EIO;
+               pb->pb_error = EIO;
        }
 
        unlock_buffer(bh);
@@ -1244,7 +1246,7 @@
        page = bh->b_page;
        if (!test_bit(BH_Uptodate, &bh->b_state)) {
                set_bit(PG_error, &page->flags);
-               pb->pb_error = -EIO;
+               pb->pb_error = EIO;
        }
 
        unlock_buffer(bh);
--- linux-xfs/fs/xfs/linux/xfs_vfs.c-XFSMEM     Tue Aug 14 01:12:44 2001
+++ linux-xfs/fs/xfs/linux/xfs_vfs.c    Tue Aug 14 04:51:07 2001
@@ -52,6 +52,8 @@
        vfs_t   *vfsp;
 
         vfsp = kmalloc(sizeof(vfs_t), GFP_KERNEL);
+       if (!vfsp)
+               return NULL;
        memset(vfsp, 0, sizeof(vfs_t));
        ASSERT(vfsp);
        VFS_INIT(vfsp);
--- linux-xfs/fs/xfs/linux/xfs_super.c-XFSMEM   Tue Aug 14 01:12:44 2001
+++ linux-xfs/fs/xfs/linux/xfs_super.c  Tue Aug 14 02:06:09 2001
@@ -357,6 +357,8 @@
        /*  Set up the vfs_t structure  */
 
        vfsp = vfs_allocate();
+       if (!vfsp) 
+               return NULL; 
 
        if (sb->s_flags & MS_RDONLY)
                 vfsp->vfs_flag |= VFS_RDONLY;
@@ -364,6 +366,11 @@
        /*  Setup up the cvp structure  */
 
        cip = (struct inode *)kmem_alloc(sizeof(struct inode),0);
+       if (!cip) { 
+               vfs_deallocate(vfsp);
+               return NULL;
+       } 
+
        bzero(cip, sizeof(*cip));
 
        atomic_set(&cip->i_count, 1);
--- linux-xfs/fs/xfs/xfs_buf.h-XFSMEM   Tue Aug 14 01:44:21 2001
+++ linux-xfs/fs/xfs/xfs_buf.h  Tue Aug 14 01:50:01 2001
@@ -238,6 +238,9 @@
 
 static inline void     xfs_buf_relse(page_buf_t *bp)
 {
+       if (!bp) 
+               return;
+
        if (bp->pb_relse == NULL)
                pagebuf_unlock(bp);
 
--- linux-xfs/fs/xfs/xfs_trans_buf.c-XFSMEM     Tue Aug 14 01:12:46 2001
+++ linux-xfs/fs/xfs/xfs_trans_buf.c    Tue Aug 14 20:28:33 2001
@@ -295,6 +295,9 @@
         */
        if (tp == NULL) {
                bp = xfs_buf_read_flags(target, blkno, len, flags);
+               if (!bp) 
+                       return XFS_ERROR(ENOMEM);
+
                if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) {
                        xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                          target->dev, blkno);
--- linux-xfs/fs/xfs_support/kmem.c-XFSMEM      Tue Aug 14 01:12:46 2001
+++ linux-xfs/fs/xfs_support/kmem.c     Tue Aug 14 01:51:14 2001
@@ -47,6 +47,15 @@
 #define GFP_NOFS        GFP_BUFFER
 #endif
 
+/* random generator stolen from net/core/utils.c. */
+static unsigned long xfs_rand_seed = 152L;
+
+unsigned long xfs_random(void)
+{
+       xfs_rand_seed=xfs_rand_seed*69069L+1;
+        return xfs_rand_seed^jiffies;
+}
+
 static __inline__ unsigned int flag_convert(int flags)
 {
        if (flags & KM_NOSLEEP) return GFP_ATOMIC;
@@ -79,8 +88,13 @@
                rval = kmalloc(size, flag_convert(flags));
        }
 
-       if (rval || (flags & KM_NOSLEEP))
-               return rval;
+       if (!rval) { 
+               if ((flags & KM_NOSLEEP) == 0) { 
+                       printk(KERN_ERR "xfs [%d]: failed to allocate %d 
bytes.\n", current->pid, size);
+                       return NULL;
+               }
+       } else
+               return rval; 
 
        /*
         * KM_SLEEP callers don't expect a failure
@@ -93,8 +107,16 @@
        }
 
        rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL);
-       if (!rval && (flags & KM_SLEEP))
-               panic("kmem_alloc: NULL memory on KM_SLEEP request!");
+       if (!rval) { 
+               if (flags & KM_SLEEP) { 
+                       printk(KERN_ERR "xfs [%d]: failed to allocate %d bytes. 
waiting and retry.\n", 
+                              current->pid, size);
+                       delay(5 + xfs_random()%10);
+                       shrink = DEF_PRIORITY; 
+                       goto repeat;
+               } 
+               printk(KERN_ERR "xfs [%d]: failed to allocate %d bytes.\n", 
current->pid, size);
+       }
 
        return rval;
 }
@@ -157,8 +179,11 @@
 repeat:
        ptr = kmem_cache_alloc(zone, flag_convert(flags));
 
-       if (ptr || (flags & KM_NOSLEEP))
+       if (ptr || (flags & KM_NOSLEEP)) { 
+               if (!ptr) 
+                       printk(KERN_ERR "xfs [%d]: failed to allocate from 
zone.\n", current->pid); 
                return ptr;
+       } 
 
        /*
         * KM_SLEEP callers don't expect a failure
@@ -170,8 +195,13 @@
                goto repeat;
        }
 
-       if (flags & KM_SLEEP)
-               panic("kmem_zone_alloc: NULL memory on KM_SLEEP request!");
+       if (flags & KM_SLEEP) {                 
+               printk(KERN_ERR "xfs [%d]: failed to allocate from zone. 
waiting and retry.\n", 
+                      current->pid);
+               delay(5 + xfs_random()%10);
+               shrink = DEF_PRIORITY; 
+               goto repeat;
+       } 
 
        return NULL;
 }
@@ -185,21 +215,29 @@
 repeat:
        ptr = kmem_cache_zalloc(zone, flag_convert(flags));
 
-       if (ptr || (flags & KM_NOSLEEP))
+       if (ptr || (flags & KM_NOSLEEP)) { 
+               if (!ptr) 
+                       printk(KERN_ERR "xfs [%d]: failed to allocate from 
zone.\n", current->pid);
                return ptr;
+       }
 
        /*
         * KM_SLEEP callers don't expect a failure
         */
        if (shrink) {
                kmem_shake();
-
+       
                shrink--;
                goto repeat;
        }
 
-       if (flags & KM_SLEEP)
-               panic("kmem_zone_zalloc: NULL memory on KM_SLEEP request!");
+       if (flags & KM_SLEEP) { 
+               printk(KERN_ERR "xfs [%d]: failed to allocate from zone. 
waiting and retry.\n", 
+                      current->pid);
+               delay(5 + xfs_random()%10);
+               shrink = DEF_PRIORITY; 
+               goto repeat;
+       } 
 
        return NULL;
 }


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