Skip to content

Commit

Permalink
3112 ztest does not honor ZFS_DEBUG
Browse files Browse the repository at this point in the history
3113 ztest should use watchpoints to protect frozen arc bufs
3114 some leaked nvlists in zfsdev_ioctl
3115 poll(2) returns prematurely in presence of spurious wakeups
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matt Amdur <Matt.Amdur@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Christopher Siden <chris.siden@delphix.com>
Approved by: Eric Schrock <eric.schrock@delphix.com>
  • Loading branch information
ahrens committed Aug 30, 2012
1 parent 31495a1 commit cd1c8b8
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 111 deletions.
2 changes: 2 additions & 0 deletions usr/src/cmd/ztest/ztest.c
Original file line number Diff line number Diff line change
Expand Up @@ -5835,6 +5835,8 @@ main(int argc, char **argv)

(void) setvbuf(stdout, NULL, _IOLBF, 0);

dprintf_setup(&argc, argv);

if (!ischild) {
process_options(argc, argv);

Expand Down
1 change: 1 addition & 0 deletions usr/src/lib/libzpool/common/sys/zfs_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extern "C" {
#include <atomic.h>
#include <dirent.h>
#include <time.h>
#include <procfs.h>
#include <libsysevent.h>
#include <sys/note.h>
#include <sys/types.h>
Expand Down
74 changes: 65 additions & 9 deletions usr/src/uts/common/fs/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@
#include <sys/kstat.h>
#include <zfs_fletcher.h>

#ifndef _KERNEL
/* set with ZFS_DEBUG=watch, to enable watchpoints on frozen buffers */
boolean_t arc_watch = B_FALSE;
int arc_procfd;
#endif

static kmutex_t arc_reclaim_thr_lock;
static kcondvar_t arc_reclaim_thr_cv; /* used to signal reclaim thr */
static uint8_t arc_thread_exit;
Expand Down Expand Up @@ -474,6 +480,7 @@ static void arc_get_data_buf(arc_buf_t *buf);
static void arc_access(arc_buf_hdr_t *buf, kmutex_t *hash_lock);
static int arc_evict_needed(arc_buf_contents_t type);
static void arc_evict_ghost(arc_state_t *state, uint64_t spa, int64_t bytes);
static void arc_buf_watch(arc_buf_t *buf);

static boolean_t l2arc_write_eligible(uint64_t spa_guid, arc_buf_hdr_t *ab);

Expand Down Expand Up @@ -949,6 +956,50 @@ arc_cksum_compute(arc_buf_t *buf, boolean_t force)
fletcher_2_native(buf->b_data, buf->b_hdr->b_size,
buf->b_hdr->b_freeze_cksum);
mutex_exit(&buf->b_hdr->b_freeze_lock);
arc_buf_watch(buf);
}

#ifndef _KERNEL
typedef struct procctl {
long cmd;
prwatch_t prwatch;
} procctl_t;
#endif

/* ARGSUSED */
static void
arc_buf_unwatch(arc_buf_t *buf)
{
#ifndef _KERNEL
if (arc_watch) {
int result;
procctl_t ctl;
ctl.cmd = PCWATCH;
ctl.prwatch.pr_vaddr = (uintptr_t)buf->b_data;
ctl.prwatch.pr_size = 0;
ctl.prwatch.pr_wflags = 0;
result = write(arc_procfd, &ctl, sizeof (ctl));
ASSERT3U(result, ==, sizeof (ctl));
}
#endif
}

/* ARGSUSED */
static void
arc_buf_watch(arc_buf_t *buf)
{
#ifndef _KERNEL
if (arc_watch) {
int result;
procctl_t ctl;
ctl.cmd = PCWATCH;
ctl.prwatch.pr_vaddr = (uintptr_t)buf->b_data;
ctl.prwatch.pr_size = buf->b_hdr->b_size;
ctl.prwatch.pr_wflags = WA_WRITE;
result = write(arc_procfd, &ctl, sizeof (ctl));
ASSERT3U(result, ==, sizeof (ctl));
}
#endif
}

void
Expand All @@ -975,6 +1026,8 @@ arc_buf_thaw(arc_buf_t *buf)
}

mutex_exit(&buf->b_hdr->b_freeze_lock);

arc_buf_unwatch(buf);
}

void
Expand All @@ -992,6 +1045,7 @@ arc_buf_freeze(arc_buf_t *buf)
buf->b_hdr->b_state == arc_anon);
arc_cksum_compute(buf, B_FALSE);
mutex_exit(hash_lock);

}

static void
Expand Down Expand Up @@ -1348,21 +1402,22 @@ arc_buf_add_ref(arc_buf_t *buf, void* tag)
* the buffer is placed on l2arc_free_on_write to be freed later.
*/
static void
arc_buf_data_free(arc_buf_hdr_t *hdr, void (*free_func)(void *, size_t),
void *data, size_t size)
arc_buf_data_free(arc_buf_t *buf, void (*free_func)(void *, size_t))
{
arc_buf_hdr_t *hdr = buf->b_hdr;

if (HDR_L2_WRITING(hdr)) {
l2arc_data_free_t *df;
df = kmem_alloc(sizeof (l2arc_data_free_t), KM_SLEEP);
df->l2df_data = data;
df->l2df_size = size;
df->l2df_data = buf->b_data;
df->l2df_size = hdr->b_size;
df->l2df_func = free_func;
mutex_enter(&l2arc_free_on_write_mtx);
list_insert_head(l2arc_free_on_write, df);
mutex_exit(&l2arc_free_on_write_mtx);
ARCSTAT_BUMP(arcstat_l2_free_on_write);
} else {
free_func(data, size);
free_func(buf->b_data, hdr->b_size);
}
}

Expand All @@ -1378,16 +1433,15 @@ arc_buf_destroy(arc_buf_t *buf, boolean_t recycle, boolean_t all)
arc_buf_contents_t type = buf->b_hdr->b_type;

arc_cksum_verify(buf);
arc_buf_unwatch(buf);

if (!recycle) {
if (type == ARC_BUFC_METADATA) {
arc_buf_data_free(buf->b_hdr, zio_buf_free,
buf->b_data, size);
arc_buf_data_free(buf, zio_buf_free);
arc_space_return(size, ARC_SPACE_DATA);
} else {
ASSERT(type == ARC_BUFC_DATA);
arc_buf_data_free(buf->b_hdr,
zio_data_buf_free, buf->b_data, size);
arc_buf_data_free(buf, zio_data_buf_free);
ARCSTAT_INCR(arcstat_data_size, -size);
atomic_add_64(&arc_size, -size);
}
Expand Down Expand Up @@ -2556,6 +2610,7 @@ arc_read_done(zio_t *zio)
}

arc_cksum_compute(buf, B_FALSE);
arc_buf_watch(buf);

if (hash_lock && zio->io_error == 0 && hdr->b_state == arc_anon) {
/*
Expand Down Expand Up @@ -3113,6 +3168,7 @@ arc_release(arc_buf_t *buf, void *tag)
}
hdr->b_datacnt -= 1;
arc_cksum_verify(buf);
arc_buf_unwatch(buf);

mutex_exit(hash_lock);

Expand Down
1 change: 0 additions & 1 deletion usr/src/uts/common/fs/zfs/dsl_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,6 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
}
}
}

}

void
Expand Down
7 changes: 1 addition & 6 deletions usr/src/uts/common/fs/zfs/dsl_synctask.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,7 @@ dsl_sync_task_do_nowait(dsl_pool_t *dp,
dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx)
{
dsl_sync_task_group_t *dstg;

if (!spa_writeable(dp->dp_spa))
return;

dstg = dsl_sync_task_group_create(dp);
dsl_sync_task_group_t *dstg = dsl_sync_task_group_create(dp);
dsl_sync_task_create(dstg, checkfunc, syncfunc,
arg1, arg2, blocks_modified);
dsl_sync_task_group_nowait(dstg, tx);
Expand Down
5 changes: 3 additions & 2 deletions usr/src/uts/common/fs/zfs/spa_history.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
dmu_tx_t *tx;
nvlist_t *nvarg;

if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY)
if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY || !spa_writeable(spa))
return (EINVAL);

tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
Expand Down Expand Up @@ -439,8 +439,9 @@ log_internal(nvlist_t *nvl, const char *operation, spa_t *spa,
/*
* If this is part of creating a pool, not everything is
* initialized yet, so don't bother logging the internal events.
* Likewise if the pool is not writeable.
*/
if (tx->tx_txg == TXG_INITIAL) {
if (tx->tx_txg == TXG_INITIAL || !spa_writeable(spa)) {
fnvlist_free(nvl);
return;
}
Expand Down
12 changes: 12 additions & 0 deletions usr/src/uts/common/fs/zfs/spa_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,18 @@ spa_init(int mode)

spa_mode_global = mode;

#ifndef _KERNEL
if (spa_mode_global != FREAD && dprintf_find_string("watch")) {
arc_procfd = open("/proc/self/ctl", O_WRONLY);
if (arc_procfd == -1) {
perror("could not enable watchpoints: "
"opening /proc/self/ctl failed: ");
} else {
arc_watch = B_TRUE;
}
}
#endif

refcount_init();
unique_init();
zio_init();
Expand Down
6 changes: 6 additions & 0 deletions usr/src/uts/common/fs/zfs/sys/arc.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/

#ifndef _SYS_ARC_H
Expand Down Expand Up @@ -135,6 +136,11 @@ void l2arc_fini(void);
void l2arc_start(void);
void l2arc_stop(void);

#ifndef _KERNEL
extern boolean_t arc_watch;
extern int arc_procfd;
#endif

#ifdef __cplusplus
}
#endif
Expand Down
5 changes: 5 additions & 0 deletions usr/src/uts/common/fs/zfs/sys/zfs_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/

#ifndef _SYS_ZFS_DEBUG_H
Expand Down Expand Up @@ -75,6 +76,10 @@ extern void zfs_dbgmsg_init(void);
extern void zfs_dbgmsg_fini(void);
extern void zfs_dbgmsg(const char *fmt, ...);

#ifndef _KERNEL
extern int dprintf_find_string(const char *string);
#endif

#ifdef __cplusplus
}
#endif
Expand Down
14 changes: 12 additions & 2 deletions usr/src/uts/common/fs/zfs/zio.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,21 @@ zio_init(void)
while (p2 & (p2 - 1))
p2 &= p2 - 1;

#ifndef _KERNEL
/*
* If we are using watchpoints, put each buffer on its own page,
* to eliminate the performance overhead of trapping to the
* kernel when modifying a non-watched buffer that shares the
* page with a watched buffer.
*/
if (arc_watch && !IS_P2ALIGNED(size, PAGESIZE))
continue;
#endif
if (size <= 4 * SPA_MINBLOCKSIZE) {
align = SPA_MINBLOCKSIZE;
} else if (P2PHASE(size, PAGESIZE) == 0) {
} else if (IS_P2ALIGNED(size, PAGESIZE)) {
align = PAGESIZE;
} else if (P2PHASE(size, p2 >> 2) == 0) {
} else if (IS_P2ALIGNED(size, p2 >> 2)) {
align = p2 >> 2;
}

Expand Down
Loading

0 comments on commit cd1c8b8

Please sign in to comment.