summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2013-09-05 06:53:03 +0000
committerBryan Cantrill <bryan@joyent.com>2013-09-05 06:53:03 +0000
commit092fe49637e40ccc367f723900bcb91ba2fab46d (patch)
tree3bb6d2698378bacbff0aa02e613f3665a9925cdc /usr/src
parent64af696dbea3e718e4c758e173de5fa35826dd41 (diff)
downloadillumos-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.h3
-rw-r--r--usr/src/uts/common/fs/zfs/arc.c26
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zio.h2
-rw-r--r--usr/src/uts/common/fs/zfs/zio.c30
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)
{