Fix stack overflow in vn_rdwr() due to memory reclaim
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>
This commit is contained in:
parent
46aa7b3939
commit
4be55565fe
|
@ -180,6 +180,7 @@ typedef struct vnode {
|
||||||
struct stdata *v_stream; /* associated stream */
|
struct stdata *v_stream; /* associated stream */
|
||||||
enum vtype v_type; /* vnode type */
|
enum vtype v_type; /* vnode type */
|
||||||
dev_t v_rdev; /* device (VCHR, VBLK) */
|
dev_t v_rdev; /* device (VCHR, VBLK) */
|
||||||
|
gfp_t v_gfp_mask; /* original mapping gfp mask */
|
||||||
} vnode_t;
|
} vnode_t;
|
||||||
|
|
||||||
typedef struct vn_file {
|
typedef struct vn_file {
|
||||||
|
|
|
@ -104,6 +104,7 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
int rc, saved_umask = 0;
|
int rc, saved_umask = 0;
|
||||||
|
gfp_t saved_gfp;
|
||||||
vnode_t *vp;
|
vnode_t *vp;
|
||||||
SENTRY;
|
SENTRY;
|
||||||
|
|
||||||
|
@ -145,9 +146,13 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
|
||||||
SRETURN(ENOMEM);
|
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);
|
mutex_enter(&vp->v_lock);
|
||||||
vp->v_type = vn_get_sol_type(stat.mode);
|
vp->v_type = vn_get_sol_type(stat.mode);
|
||||||
vp->v_file = fp;
|
vp->v_file = fp;
|
||||||
|
vp->v_gfp_mask = saved_gfp;
|
||||||
*vpp = vp;
|
*vpp = vp;
|
||||||
mutex_exit(&vp->v_lock);
|
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);
|
||||||
ASSERT(vp->v_file);
|
ASSERT(vp->v_file);
|
||||||
|
|
||||||
|
mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
|
||||||
rc = filp_close(vp->v_file, 0);
|
rc = filp_close(vp->v_file, 0);
|
||||||
vn_free(vp);
|
vn_free(vp);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue