diff options
author | Bryan Cantrill <bryan@joyent.com> | 2013-09-05 06:53:03 +0000 |
---|---|---|
committer | Bryan Cantrill <bryan@joyent.com> | 2013-09-05 06:53:03 +0000 |
commit | 092fe49637e40ccc367f723900bcb91ba2fab46d (patch) | |
tree | 3bb6d2698378bacbff0aa02e613f3665a9925cdc /usr/src | |
parent | 64af696dbea3e718e4c758e173de5fa35826dd41 (diff) | |
download | illumos-joyent-release-20130905.tar.gz |
OS-2437 arc_get_data_buf() blocks in vmem_alloc() instead of evicting20130905release-20130905
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libzpool/common/sys/zfs_context.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/arc.c | 26 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zio.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zio.c | 30 |
4 files changed, 54 insertions, 7 deletions
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h index 3aa58fb05a..b6f6304f59 100644 --- a/usr/src/lib/libzpool/common/sys/zfs_context.h +++ b/usr/src/lib/libzpool/common/sys/zfs_context.h @@ -22,7 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #ifndef _SYS_ZFS_CONTEXT_H @@ -305,6 +305,7 @@ extern void kstat_runq_back_to_waitq(kstat_io_t *); #define KM_SLEEP UMEM_NOFAIL #define KM_PUSHPAGE KM_SLEEP #define KM_NOSLEEP UMEM_DEFAULT +#define KM_NORMALPRI 0 #define KMC_NODEBUG UMC_NODEBUG #define KMC_NOTOUCH 0 /* not needed for userland caches */ #define kmem_alloc(_s, _f) umem_alloc(_s, _f) diff --git a/usr/src/uts/common/fs/zfs/arc.c b/usr/src/uts/common/fs/zfs/arc.c index dfd02dc69f..0b762ebdb9 100644 --- a/usr/src/uts/common/fs/zfs/arc.c +++ b/usr/src/uts/common/fs/zfs/arc.c @@ -280,6 +280,7 @@ typedef struct arc_stats { * not from the spa we're trying to evict from. */ kstat_named_t arcstat_evict_skip; + kstat_named_t arcstat_evict_allocfail; kstat_named_t arcstat_evict_l2_cached; kstat_named_t arcstat_evict_l2_eligible; kstat_named_t arcstat_evict_l2_ineligible; @@ -346,6 +347,7 @@ static arc_stats_t arc_stats = { { "recycle_miss", KSTAT_DATA_UINT64 }, { "mutex_miss", KSTAT_DATA_UINT64 }, { "evict_skip", KSTAT_DATA_UINT64 }, + { "evict_allocfail", KSTAT_DATA_UINT64 }, { "evict_l2_cached", KSTAT_DATA_UINT64 }, { "evict_l2_eligible", KSTAT_DATA_UINT64 }, { "evict_l2_ineligible", KSTAT_DATA_UINT64 }, @@ -2513,15 +2515,27 @@ arc_get_data_buf(arc_buf_t *buf) */ if (!arc_evict_needed(type)) { if (type == ARC_BUFC_METADATA) { - buf->b_data = zio_buf_alloc(size); - arc_space_consume(size, ARC_SPACE_DATA); + buf->b_data = zio_buf_alloc_canfail(size); + if (buf->b_data != NULL) { + arc_space_consume(size, ARC_SPACE_DATA); + goto out; + } } else { ASSERT(type == ARC_BUFC_DATA); - buf->b_data = zio_data_buf_alloc(size); - ARCSTAT_INCR(arcstat_data_size, size); - atomic_add_64(&arc_size, size); + buf->b_data = zio_data_buf_alloc_canfail(size); + if (buf->b_data != NULL) { + ARCSTAT_INCR(arcstat_data_size, size); + atomic_add_64(&arc_size, size); + goto out; + } } - goto out; + + /* + * Memory allocation failed, presumably due to excessive + * fragmentation; we'll bump a counter and drop into the ARC + * eviction case. + */ + ARCSTAT_BUMP(arcstat_evict_allocfail); } /* diff --git a/usr/src/uts/common/fs/zfs/sys/zio.h b/usr/src/uts/common/fs/zfs/sys/zio.h index eb4b1f8e71..7b383e4a74 100644 --- a/usr/src/uts/common/fs/zfs/sys/zio.h +++ b/usr/src/uts/common/fs/zfs/sys/zio.h @@ -504,8 +504,10 @@ extern zio_t *zio_unique_parent(zio_t *cio); extern void zio_add_child(zio_t *pio, zio_t *cio); extern void *zio_buf_alloc(size_t size); +extern void *zio_buf_alloc_canfail(size_t size); extern void zio_buf_free(void *buf, size_t size); extern void *zio_data_buf_alloc(size_t size); +extern void *zio_data_buf_alloc_canfail(size_t size); extern void zio_data_buf_free(void *buf, size_t size); extern void zio_resubmit_stage_async(void *); diff --git a/usr/src/uts/common/fs/zfs/zio.c b/usr/src/uts/common/fs/zfs/zio.c index eb06151cee..dfd8fa3f65 100644 --- a/usr/src/uts/common/fs/zfs/zio.c +++ b/usr/src/uts/common/fs/zfs/zio.c @@ -22,6 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. */ #include <sys/zfs_context.h> @@ -228,6 +229,20 @@ zio_buf_alloc(size_t size) } /* + * Same as zio_buf_alloc, but won't sleep in case memory cannot be allocated + * and will instead return immediately with a failure. + */ +void * +zio_buf_alloc_canfail(size_t size) +{ + size_t c = (size - 1) >> SPA_MINBLOCKSHIFT; + + ASSERT(c < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT); + + return (kmem_cache_alloc(zio_buf_cache[c], KM_NOSLEEP | KM_NORMALPRI)); +} + +/* * Use zio_data_buf_alloc to allocate data. The data will not appear in a * crashdump if the kernel panics. This exists so that we will limit the amount * of ZFS data that shows up in a kernel crashdump. (Thus reducing the amount @@ -243,6 +258,21 @@ zio_data_buf_alloc(size_t size) return (kmem_cache_alloc(zio_data_buf_cache[c], KM_PUSHPAGE)); } +/* + * Same as zio_data_buf_alloc, but won't sleep in case memory cannot be + * allocated and will instead return immediately with a failure. + */ +void * +zio_data_buf_alloc_canfail(size_t size) +{ + size_t c = (size - 1) >> SPA_MINBLOCKSHIFT; + + ASSERT(c < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT); + + return (kmem_cache_alloc(zio_data_buf_cache[c], + KM_NOSLEEP | KM_NORMALPRI)); +} + void zio_buf_free(void *buf, size_t size) { |