From c61ea5668634a215fd1c9000beb7f6d2853b3468 Mon Sep 17 00:00:00 2001 From: George Wilson Date: Wed, 20 Feb 2013 22:50:16 -0800 Subject: [PATCH] 3557 dumpvp_size is not updated correctly when a dump zvol's size is changed 3558 setting the volsize on a dump device does not return back ENOSPC 3559 setting a volsize larger than the space available sometimes succeeds 3560 dumpadm should be able to remove a dump device Reviewed by: Adam Leventhal Reviewed by: Matthew Ahrens Reviewed by: Christopher Siden Approved by: Albert Lee --- usr/src/cmd/dumpadm/dconf.c | 13 +++- usr/src/cmd/zfs/zfs_main.c | 12 +++- usr/src/lib/libzfs/common/libzfs_dataset.c | 22 +++++-- usr/src/lib/libzfs/common/mapfile-vers | 1 + usr/src/man/man1m/dumpadm.1m | 16 ++++- usr/src/uts/common/fs/zfs/sys/zvol.h | 2 +- usr/src/uts/common/fs/zfs/zfs_ioctl.c | 3 +- usr/src/uts/common/fs/zfs/zvol.c | 97 +++++++++++++++++------------- usr/src/uts/common/io/dump.c | 8 +++ usr/src/uts/common/sys/dumpadm.h | 2 + 10 files changed, 120 insertions(+), 56 deletions(-) diff --git a/usr/src/cmd/dumpadm/dconf.c b/usr/src/cmd/dumpadm/dconf.c index 488b802462..81b0db25c1 100644 --- a/usr/src/cmd/dumpadm/dconf.c +++ b/usr/src/cmd/dumpadm/dconf.c @@ -70,6 +70,7 @@ static const char DC_STR_OFF[] = "off"; /* Off string */ static const char DC_STR_YES[] = "yes"; /* Enable on string */ static const char DC_STR_NO[] = "no"; /* Enable off string */ static const char DC_STR_SWAP[] = "swap"; /* Default dump device */ +static const char DC_STR_NONE[] = "none"; /* The pages included in the dump */ static const char DC_STR_KERNEL[] = "kernel"; /* Kernel only */ @@ -367,7 +368,7 @@ dconf_dev_ioctl(dumpconf_t *dcp, int cmd) int dconf_update(dumpconf_t *dcp, int checkinuse) { - int oconf; + int oconf; int error; char *msg; @@ -438,6 +439,11 @@ dconf_update(dumpconf_t *dcp, int checkinuse) } free(swt); + } else if (strcmp(dcp->dc_device, DC_STR_NONE) == 0) { + if (ioctl(dcp->dc_dump_fd, DIOCRMDEV, NULL) == -1) { + warn(gettext("failed to remove dump device")); + return (-1); + } } else if (dcp->dc_device[0] != '\0') { /* * If we're not in forcible update mode, then fail the change @@ -564,6 +570,11 @@ dconf_str2device(dumpconf_t *dcp, char *buf) return (0); } + if (strcasecmp(buf, DC_STR_NONE) == 0) { + (void) strcpy(dcp->dc_device, DC_STR_NONE); + return (0); + } + if (valid_abspath(buf)) { (void) strcpy(dcp->dc_device, buf); return (0); diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index ee9d289a11..e5e35e6f16 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -775,10 +775,12 @@ zfs_do_create(int argc, char **argv) if (type == ZFS_TYPE_VOLUME && !noreserve) { zpool_handle_t *zpool_handle; + nvlist_t *real_props; uint64_t spa_version; char *p; zfs_prop_t resv_prop; char *strval; + char msg[1024]; if (p = strchr(argv[0], '/')) *p = '\0'; @@ -794,7 +796,15 @@ zfs_do_create(int argc, char **argv) resv_prop = ZFS_PROP_REFRESERVATION; else resv_prop = ZFS_PROP_RESERVATION; - volsize = zvol_volsize_to_reservation(volsize, props); + + (void) snprintf(msg, sizeof (msg), + gettext("cannot create '%s'"), argv[0]); + if (props && (real_props = zfs_valid_proplist(g_zfs, type, + props, 0, NULL, msg)) == NULL) + goto error; + + volsize = zvol_volsize_to_reservation(volsize, real_props); + nvlist_free(real_props); if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop), &strval) != 0) { diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 35d27d9d1f..3ad1ed69d5 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -1283,6 +1283,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) uint64_t old_reservation; uint64_t new_reservation; zfs_prop_t resv_prop; + nvlist_t *props; /* * If this is an existing volume, and someone is setting the volsize, @@ -1292,16 +1293,25 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_reservation = zfs_prop_get_int(zhp, resv_prop); - if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) != - old_reservation) || nvlist_lookup_uint64(nvl, - zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) { + + props = fnvlist_alloc(); + fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), + zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE)); + + if ((zvol_volsize_to_reservation(old_volsize, props) != + old_reservation) || nvlist_exists(nvl, + zfs_prop_to_name(resv_prop))) { + fnvlist_free(props); return (0); } if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), - &new_volsize) != 0) + &new_volsize) != 0) { + fnvlist_free(props); return (-1); - new_reservation = zvol_volsize_to_reservation(new_volsize, - zhp->zfs_props); + } + new_reservation = zvol_volsize_to_reservation(new_volsize, props); + fnvlist_free(props); + if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), new_reservation) != 0) { (void) no_memory(zhp->zfs_hdl); diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index 15075e3bb5..1cc52f5f79 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -158,6 +158,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_unshareall_nfs; zfs_unshareall_smb; zfs_userspace; + zfs_valid_proplist; zfs_get_fsacl; zfs_set_fsacl; zfs_userquota_prop_prefixes; diff --git a/usr/src/man/man1m/dumpadm.1m b/usr/src/man/man1m/dumpadm.1m index 6bc71bea9c..d46160d7c3 100644 --- a/usr/src/man/man1m/dumpadm.1m +++ b/usr/src/man/man1m/dumpadm.1m @@ -1,10 +1,11 @@ '\" te -.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved .\" Copyright 2013 Nexenta Systems, Inc. All Rights Reserved. +.\" Copyright (c) 2013 by Delphix. All rights reserved. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH DUMPADM 1M "Jan 30, 2013" +.TH DUMPADM 1M "Feb 15, 2013" .SH NAME dumpadm \- configure operating system crash dump .SH SYNOPSIS @@ -172,6 +173,17 @@ given ZFS volume cannot be configured for both the swap area and the dump device. .RE +.sp +.ne 2 +.na +\fB\fBnone\fR\fR +.ad +.sp .6 +.RS 4n +If the special token \fBnone\fR is specified, the active dump device is removed +and crash dumps are disabled. +.RE + .RE .sp diff --git a/usr/src/uts/common/fs/zfs/sys/zvol.h b/usr/src/uts/common/fs/zfs/sys/zvol.h index 0059bf5102..db1f05ae9c 100644 --- a/usr/src/uts/common/fs/zfs/sys/zvol.h +++ b/usr/src/uts/common/fs/zfs/sys/zvol.h @@ -43,7 +43,7 @@ extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); extern int zvol_create_minor(const char *); extern int zvol_remove_minor(const char *); extern void zvol_remove_minors(const char *); -extern int zvol_set_volsize(const char *, major_t, uint64_t); +extern int zvol_set_volsize(const char *, uint64_t); extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr); extern int zvol_dump(dev_t dev, caddr_t addr, daddr_t offset, int nblocks); diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 090d6c9417..38adc1940f 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -2368,8 +2368,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, err = dsl_dataset_set_reservation(dsname, source, intval); break; case ZFS_PROP_VOLSIZE: - err = zvol_set_volsize(dsname, ddi_driver_major(zfs_dip), - intval); + err = zvol_set_volsize(dsname, intval); break; case ZFS_PROP_VERSION: { diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c index da1b0efda5..b413f5ed8b 100644 --- a/usr/src/uts/common/fs/zfs/zvol.c +++ b/usr/src/uts/common/fs/zfs/zvol.c @@ -145,10 +145,11 @@ static int zvol_dump_fini(zvol_state_t *zv); static int zvol_dump_init(zvol_state_t *zv, boolean_t resize); static void -zvol_size_changed(uint64_t volsize, major_t maj, minor_t min) +zvol_size_changed(zvol_state_t *zv, uint64_t volsize) { - dev_t dev = makedevice(maj, min); + dev_t dev = makedevice(ddi_driver_major(zfs_dip), zv->zv_minor); + zv->zv_volsize = volsize; VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Size", volsize) == DDI_SUCCESS); VERIFY(ddi_prop_update_int64(dev, zfs_dip, @@ -610,22 +611,22 @@ zvol_first_open(zvol_state_t *zv) if (error) return (error); + zv->zv_objset = os; error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); if (error) { ASSERT(error == 0); dmu_objset_disown(os, zvol_tag); return (error); } - zv->zv_objset = os; + error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); if (error) { dmu_objset_disown(os, zvol_tag); return (error); } - zv->zv_volsize = volsize; + + zvol_size_changed(zv, volsize); zv->zv_zilog = zil_open(os, zvol_get_data); - zvol_size_changed(zv->zv_volsize, ddi_driver_major(zfs_dip), - zv->zv_minor); VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &readonly, NULL) == 0); @@ -747,56 +748,37 @@ zvol_remove_minors(const char *name) mutex_exit(&zfsdev_state_lock); } -int -zvol_set_volsize(const char *name, major_t maj, uint64_t volsize) +static int +zvol_set_volsize_impl(objset_t *os, zvol_state_t *zv, uint64_t volsize) { - zvol_state_t *zv = NULL; - objset_t *os; - int error; - dmu_object_info_t doi; uint64_t old_volsize = 0ULL; - uint64_t readonly; - - mutex_enter(&zfsdev_state_lock); - zv = zvol_minor_lookup(name); - if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) { - mutex_exit(&zfsdev_state_lock); - return (error); - } - - if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 || - (error = zvol_check_volsize(volsize, - doi.doi_data_block_size)) != 0) - goto out; - - VERIFY(dsl_prop_get_integer(name, "readonly", &readonly, - NULL) == 0); - if (readonly) { - error = EROFS; - goto out; - } + int error; + ASSERT(MUTEX_HELD(&zfsdev_state_lock)); error = zvol_update_volsize(os, volsize); + /* * Reinitialize the dump area to the new size. If we * failed to resize the dump area then restore it back to - * its original size. + * its original size. We must set the new volsize prior + * to calling dumpvp_resize() to ensure that the devices' + * size(9P) is not visible by the dump subsystem. */ if (zv && error == 0) { + old_volsize = zv->zv_volsize; + zvol_size_changed(zv, volsize); + if (zv->zv_flags & ZVOL_DUMPIFIED) { - old_volsize = zv->zv_volsize; - zv->zv_volsize = volsize; if ((error = zvol_dumpify(zv)) != 0 || (error = dumpvp_resize()) != 0) { + int dumpify_error; + (void) zvol_update_volsize(os, old_volsize); - zv->zv_volsize = old_volsize; - error = zvol_dumpify(zv); + zvol_size_changed(zv, old_volsize); + dumpify_error = zvol_dumpify(zv); + error = dumpify_error ? dumpify_error : error; } } - if (error == 0) { - zv->zv_volsize = volsize; - zvol_size_changed(volsize, maj, zv->zv_minor); - } } /* @@ -819,12 +801,41 @@ zvol_set_volsize(const char *name, major_t maj, uint64_t volsize) nvlist_free(attr); kmem_free(physpath, MAXPATHLEN); } + return (error); +} +int +zvol_set_volsize(const char *name, uint64_t volsize) +{ + zvol_state_t *zv = NULL; + objset_t *os; + int error; + dmu_object_info_t doi; + uint64_t readonly; + + mutex_enter(&zfsdev_state_lock); + zv = zvol_minor_lookup(name); + if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) { + mutex_exit(&zfsdev_state_lock); + return (error); + } + + if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 || + (error = zvol_check_volsize(volsize, + doi.doi_data_block_size)) != 0) + goto out; + + VERIFY3U(dsl_prop_get_integer(name, + zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL), ==, 0); + if (readonly) { + error = EROFS; + goto out; + } + + error = zvol_set_volsize_impl(os, zv, volsize); out: dmu_objset_rele(os, FTAG); - mutex_exit(&zfsdev_state_lock); - return (error); } diff --git a/usr/src/uts/common/io/dump.c b/usr/src/uts/common/io/dump.c index 70a61bf9b8..ab5a9d0240 100644 --- a/usr/src/uts/common/io/dump.c +++ b/usr/src/uts/common/io/dump.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Delphix (c) 2012 by Delphix. All rights reserved. */ @@ -208,6 +209,13 @@ dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) error = copyoutstr(dump_get_uuid(), (void *)arg, 37, NULL); break; + case DIOCRMDEV: + mutex_enter(&dump_lock); + if (dumpvp != NULL) + dumpfini(); + mutex_exit(&dump_lock); + break; + default: error = ENXIO; } diff --git a/usr/src/uts/common/sys/dumpadm.h b/usr/src/uts/common/sys/dumpadm.h index 4e3704985d..616828bb2b 100644 --- a/usr/src/uts/common/sys/dumpadm.h +++ b/usr/src/uts/common/sys/dumpadm.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #ifndef _SYS_DUMPADM_H @@ -42,6 +43,7 @@ extern "C" { #define DIOCDUMP (DDIOC | 0x16) #define DIOCSETUUID (DDIOC | 0x17) #define DIOCGETUUID (DDIOC | 0x18) +#define DIOCRMDEV (DDIOC | 0x19) /* * Kernel-controlled dump state flags for dump_conflags -- 2.11.4.GIT