--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h @@ -544,6 +544,7 @@ extern void zio_add_child(zio_t *pio, zio_t *cio); extern void *zio_buf_alloc(size_t size); +extern void *zio_buf_alloc_flags(size_t size, int aflags); extern void zio_buf_free(void *buf, size_t size); extern void *zio_data_buf_alloc(size_t size); extern void zio_data_buf_free(void *buf, size_t size); --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c @@ -288,7 +288,7 @@ * excess / transient data in-core during a crashdump. */ void * -zio_buf_alloc(size_t size) +zio_buf_alloc_flags(size_t size, int aflags) { size_t c = (size - 1) >> SPA_MINBLOCKSHIFT; int flags = zio_exclude_metadata ? KM_NODEBUG : 0; @@ -298,7 +298,14 @@ if (zio_use_uma) return (kmem_cache_alloc(zio_buf_cache[c], KM_PUSHPAGE)); else - return (kmem_alloc(size, KM_SLEEP|flags)); + return (kmem_alloc(size, aflags | flags)); +} + +void * +zio_buf_alloc(size_t size) +{ + + return (zio_buf_alloc_flags(size, KM_SLEEP)); } /* --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c @@ -211,10 +211,10 @@ { zio_t *fio, *lio, *aio, *dio, *nio, *mio; avl_tree_t *t; - int flags; uint64_t maxspan = zfs_vdev_aggregation_limit; - uint64_t maxgap; - int stretch; + uint64_t maxgap, size; + int flags, stretch; + void *buf; again: ASSERT(MUTEX_HELD(&vq->vq_lock)); @@ -302,25 +302,39 @@ } } - if (stretch) { - /* This may be a no-op. */ - VERIFY((dio = AVL_NEXT(t, lio)) != NULL); - dio->io_flags &= ~ZIO_FLAG_OPTIONAL; - } else { + if (!stretch) { while (lio != mio && lio != fio) { ASSERT(lio->io_flags & ZIO_FLAG_OPTIONAL); lio = AVL_PREV(t, lio); ASSERT(lio != NULL); } } - } + + if (fio == lio) { + /* Nothing to aggregate. */ + goto out; + } - if (fio != lio) { - uint64_t size = IO_SPAN(fio, lio); + size = IO_SPAN(fio, lio); ASSERT(size <= zfs_vdev_aggregation_limit); - aio = zio_vdev_delegated_io(fio->io_vd, fio->io_offset, - zio_buf_alloc(size), size, fio->io_type, ZIO_PRIORITY_AGG, + buf = zio_buf_alloc_flags(size, KM_NOSLEEP); + if (buf == NULL) { + /* + * Not enough memory? Skip aggregation to avoid + * possible deadlock with the pageout daemon. + */ + goto out; + } + + if (stretch) { + /* This may be a no-op. */ + VERIFY((dio = AVL_NEXT(t, lio)) != NULL); + dio->io_flags &= ~ZIO_FLAG_OPTIONAL; + } + + aio = zio_vdev_delegated_io(fio->io_vd, fio->io_offset, buf, + size, fio->io_type, ZIO_PRIORITY_AGG, flags | ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE, vdev_queue_agg_io_done, NULL); aio->io_timestamp = fio->io_timestamp; @@ -353,6 +367,7 @@ return (aio); } +out: ASSERT(fio->io_vdev_tree == t); vdev_queue_io_remove(vq, fio);