]> granicus.if.org Git - spl/commitdiff
Fix stack overflow in vn_rdwr() due to memory reclaim
authorLi Wei <W.Li@Sun.COM>
Thu, 12 Aug 2010 16:24:31 +0000 (09:24 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 12 Aug 2010 16:34:33 +0000 (09:34 -0700)
Unless __GFP_IO and __GFP_FS are removed from the file mapping gfp
mask we may enter memory reclaim during IO.  In this case shrink_slab()
entered another file system which is notoriously hungry for stack.
This additional stack usage may cause a stack overflow.  This patch
removes __GFP_IO and __GFP_FS from the mapping gfp mask of each file
during vn_open() to avoid any reclaim in the vn_rdwr() IO path.  The
original mask is then restored at vn_close() time.  Hats off to the
loop driver which does something similiar for the same reason.

  [...]
  shrink_slab+0xdc/0x153
  try_to_free_pages+0x1da/0x2d7
  __alloc_pages+0x1d7/0x2da
  do_generic_mapping_read+0x2c9/0x36f
  file_read_actor+0x0/0x145
  __generic_file_aio_read+0x14f/0x19b
  generic_file_aio_read+0x34/0x39
  do_sync_read+0xc7/0x104
  vfs_read+0xcb/0x171
  :spl:vn_rdwr+0x2b8/0x402
  :zfs:vdev_file_io_start+0xad/0xe1
  [...]

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
include/sys/vnode.h
module/spl/spl-vnode.c

index 09d8433669be50b304e2ee2db5c0bb200f451b16..104e65d15e6cabfc7ef580b176dfb7c3ffe26112 100644 (file)
@@ -180,6 +180,7 @@ typedef struct vnode {
        struct stdata   *v_stream;      /* associated stream */
        enum vtype      v_type;         /* vnode type */
        dev_t           v_rdev;         /* device (VCHR, VBLK) */
+       gfp_t           v_gfp_mask;     /* original mapping gfp mask */
 } vnode_t;
 
 typedef struct vn_file {
index dd759bf7fb81fd384805262a322ab3dfc9d4fce0..29028c3c0d41ec504114a927c3d59db44771878e 100644 (file)
@@ -104,6 +104,7 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
        struct file *fp;
        struct kstat stat;
        int rc, saved_umask = 0;
+       gfp_t saved_gfp;
        vnode_t *vp;
        SENTRY;
 
@@ -145,9 +146,13 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
                SRETURN(ENOMEM);
        }
 
+       saved_gfp = mapping_gfp_mask(fp->f_mapping);
+       mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
+
        mutex_enter(&vp->v_lock);
        vp->v_type = vn_get_sol_type(stat.mode);
        vp->v_file = fp;
+       vp->v_gfp_mask = saved_gfp;
        *vpp = vp;
        mutex_exit(&vp->v_lock);
 
@@ -237,6 +242,7 @@ vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
        ASSERT(vp);
        ASSERT(vp->v_file);
 
+       mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
        rc = filp_close(vp->v_file, 0);
        vn_free(vp);