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>
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 {
struct file *fp;
struct kstat stat;
int rc, saved_umask = 0;
+ gfp_t saved_gfp;
vnode_t *vp;
SENTRY;
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);
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);