Print this page
3744 zfs shouldn't ignore errors unmounting snapshots
Submitted by: Will Andrews <willa@spectralogic.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
*** 3366,3410 ****
* The dp_config_rwlock must not be held when calling this, because the
* unmount may need to write out data.
*
* This function is best-effort. Callers must deal gracefully if it
* remains mounted (or is remounted after this call).
*/
! void
zfs_unmount_snap(const char *snapname)
{
vfs_t *vfsp;
zfsvfs_t *zfsvfs;
if (strchr(snapname, '@') == NULL)
! return;
vfsp = zfs_get_vfs(snapname);
if (vfsp == NULL)
! return;
zfsvfs = vfsp->vfs_data;
ASSERT(!dsl_pool_config_held(dmu_objset_pool(zfsvfs->z_os)));
! if (vn_vfswlock(vfsp->vfs_vnodecovered) != 0) {
! VFS_RELE(vfsp);
! return;
! }
VFS_RELE(vfsp);
/*
* Always force the unmount for snapshots.
*/
(void) dounmount(vfsp, MS_FORCE, kcred);
}
/* ARGSUSED */
static int
zfs_unmount_snap_cb(const char *snapname, void *arg)
{
! zfs_unmount_snap(snapname);
! return (0);
}
/*
* When a clone is destroyed, its origin may also need to be destroyed,
* in which case it must be unmounted. This routine will do that unmount
--- 3366,3413 ----
* The dp_config_rwlock must not be held when calling this, because the
* unmount may need to write out data.
*
* This function is best-effort. Callers must deal gracefully if it
* remains mounted (or is remounted after this call).
+ *
+ * Returns 0 if the argument is not a snapshot, or it is not currently a
+ * filesystem, or we were able to unmount it. Returns error code otherwise.
*/
! int
zfs_unmount_snap(const char *snapname)
{
vfs_t *vfsp;
zfsvfs_t *zfsvfs;
+ int err;
if (strchr(snapname, '@') == NULL)
! return (0);
vfsp = zfs_get_vfs(snapname);
if (vfsp == NULL)
! return (0);
zfsvfs = vfsp->vfs_data;
ASSERT(!dsl_pool_config_held(dmu_objset_pool(zfsvfs->z_os)));
! err = vn_vfswlock(vfsp->vfs_vnodecovered);
VFS_RELE(vfsp);
+ if (err != 0)
+ return (err);
/*
* Always force the unmount for snapshots.
*/
(void) dounmount(vfsp, MS_FORCE, kcred);
+ return (0);
}
/* ARGSUSED */
static int
zfs_unmount_snap_cb(const char *snapname, void *arg)
{
! return (zfs_unmount_snap(snapname));
}
/*
* When a clone is destroyed, its origin may also need to be destroyed,
* in which case it must be unmounted. This routine will do that unmount
*** 3423,3433 ****
ds = dmu_objset_ds(os);
if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) {
char originname[MAXNAMELEN];
dsl_dataset_name(ds->ds_prev, originname);
dmu_objset_rele(os, FTAG);
! zfs_unmount_snap(originname);
} else {
dmu_objset_rele(os, FTAG);
}
}
--- 3426,3436 ----
ds = dmu_objset_ds(os);
if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) {
char originname[MAXNAMELEN];
dsl_dataset_name(ds->ds_prev, originname);
dmu_objset_rele(os, FTAG);
! (void) zfs_unmount_snap(originname);
} else {
dmu_objset_rele(os, FTAG);
}
}
*** 3441,3451 ****
*
*/
static int
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
! int poollen;
nvlist_t *snaps;
nvpair_t *pair;
boolean_t defer;
if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
--- 3444,3454 ----
*
*/
static int
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
! int error, poollen;
nvlist_t *snaps;
nvpair_t *pair;
boolean_t defer;
if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
*** 3462,3472 ****
*/
if (strncmp(name, poolname, poollen) != 0 ||
(name[poollen] != '/' && name[poollen] != '@'))
return (SET_ERROR(EXDEV));
! zfs_unmount_snap(name);
}
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
}
--- 3465,3477 ----
*/
if (strncmp(name, poolname, poollen) != 0 ||
(name[poollen] != '/' && name[poollen] != '@'))
return (SET_ERROR(EXDEV));
! error = zfs_unmount_snap(name);
! if (error)
! return (SET_ERROR(error));
}
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
}
*** 3480,3491 ****
*/
static int
zfs_ioc_destroy(zfs_cmd_t *zc)
{
int err;
! if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS)
! zfs_unmount_snap(zc->zc_name);
if (strchr(zc->zc_name, '@'))
err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
else
err = dsl_destroy_head(zc->zc_name);
--- 3485,3500 ----
*/
static int
zfs_ioc_destroy(zfs_cmd_t *zc)
{
int err;
!
! if (zc->zc_objset_type == DMU_OST_ZFS) {
! err = zfs_unmount_snap(zc->zc_name);
! if (err)
! return (err);
! }
if (strchr(zc->zc_name, '@'))
err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
else
err = dsl_destroy_head(zc->zc_name);
*** 3527,3538 ****
{
const char *snapname = arg;
char fullname[MAXNAMELEN];
(void) snprintf(fullname, sizeof (fullname), "%s@%s", fsname, snapname);
! zfs_unmount_snap(fullname);
! return (0);
}
/*
* inputs:
* zc_name old name of dataset
--- 3536,3546 ----
{
const char *snapname = arg;
char fullname[MAXNAMELEN];
(void) snprintf(fullname, sizeof (fullname), "%s@%s", fsname, snapname);
! return (zfs_unmount_snap(fullname));
}
/*
* inputs:
* zc_name old name of dataset
*** 4987,5004 ****
/* ARGSUSED */
static int
zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
{
nvpair_t *pair;
/*
* The release may cause the snapshot to be destroyed; make sure it
* is not mounted.
*/
for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
! pair = nvlist_next_nvpair(holds, pair))
! zfs_unmount_snap(nvpair_name(pair));
return (dsl_dataset_user_release(holds, errlist));
}
/*
--- 4995,5016 ----
/* ARGSUSED */
static int
zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
{
nvpair_t *pair;
+ int err;
/*
* The release may cause the snapshot to be destroyed; make sure it
* is not mounted.
*/
for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
! pair = nvlist_next_nvpair(holds, pair)) {
! err = zfs_unmount_snap(nvpair_name(pair));
! if (err)
! return (err);
! }
return (dsl_dataset_user_release(holds, errlist));
}
/*