From 287be44f536e27d377518badd2bd8e2758db2be6 Mon Sep 17 00:00:00 2001 From: Dan Swartzendruber Date: Fri, 29 Aug 2014 15:12:21 -0400 Subject: [PATCH] Improve handling of filesystem versions Change mount code to diagnose filesystem versions that are not supported by the current implementation. Change upgrade code to do likewise and refuse to upgrade a pool if any filesystems on it are a version which is not supported by the current implementation. Signed-off-by: Brian Behlendorf Signed-off-by: Dan Swartzendruber Closes: #2616 --- cmd/mount_zfs/mount_zfs.c | 57 ++++++++++++++++++++++++++++----------- cmd/zpool/zpool_main.c | 32 ++++++++++++++++++++++ module/zfs/zfs_vfsops.c | 7 +---- 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c index 6cb23d1c6..b168f719a 100644 --- a/cmd/mount_zfs/mount_zfs.c +++ b/cmd/mount_zfs/mount_zfs.c @@ -363,6 +363,7 @@ main(int argc, char **argv) { zfs_handle_t *zhp; char prop[ZFS_MAXPROPLEN]; + uint64_t zfs_version = 0; char mntopts[MNT_LINE_MAX] = { '\0' }; char badopt[MNT_LINE_MAX] = { '\0' }; char mtabopt[MNT_LINE_MAX] = { '\0' }; @@ -515,6 +516,18 @@ main(int argc, char **argv) (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop, sizeof (prop), NULL, NULL, 0, B_FALSE); + /* + * Fetch the max supported zfs version in case we get ENOTSUP + * back from the mount command, since we need the zfs handle + * to do so. + */ + zfs_version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); + if (zfs_version == 0) { + fprintf(stderr, gettext("unable to fetch " + "ZFS version for filesystem '%s'\n"), dataset); + return (MOUNT_SYSERR); + } + zfs_close(zhp); libzfs_fini(g_zfs); @@ -551,22 +564,36 @@ main(int argc, char **argv) if (!fake) { error = mount(dataset, mntpoint, MNTTYPE_ZFS, mntflags, mntopts); - if (error) { - switch (errno) { - case ENOENT: - (void) fprintf(stderr, gettext("mount point " - "'%s' does not exist\n"), mntpoint); - return (MOUNT_SYSERR); - case EBUSY: - (void) fprintf(stderr, gettext("filesystem " - "'%s' is already mounted\n"), dataset); - return (MOUNT_BUSY); - default: - (void) fprintf(stderr, gettext("filesystem " - "'%s' can not be mounted due to error " - "%d\n"), dataset, errno); - return (MOUNT_USAGE); + } + + if (error) { + switch (errno) { + case ENOENT: + (void) fprintf(stderr, gettext("mount point " + "'%s' does not exist\n"), mntpoint); + return (MOUNT_SYSERR); + case EBUSY: + (void) fprintf(stderr, gettext("filesystem " + "'%s' is already mounted\n"), dataset); + return (MOUNT_BUSY); + case ENOTSUP: + if (zfs_version > ZPL_VERSION) { + (void) fprintf(stderr, + gettext("filesystem '%s' (v%d) is not " + "supported by this implementation of " + "ZFS (max v%d).\n"), dataset, + (int) zfs_version, (int) ZPL_VERSION); + } else { + (void) fprintf(stderr, + gettext("filesystem '%s' mount " + "failed for unknown reason.\n"), dataset); } + return (MOUNT_SYSERR); + default: + (void) fprintf(stderr, gettext("filesystem " + "'%s' can not be mounted due to error " + "%d\n"), dataset, errno); + return (MOUNT_USAGE); } } diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 952645ea5..1086f9555 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -4601,12 +4601,33 @@ typedef struct upgrade_cbdata { char **cb_argv; } upgrade_cbdata_t; +static int +check_unsupp_fs(zfs_handle_t *zhp, void *unsupp_fs) +{ + int zfs_version = (int) zfs_prop_get_int(zhp, ZFS_PROP_VERSION); + int *count = (int *)unsupp_fs; + + if (zfs_version > ZPL_VERSION) { + (void) printf(gettext("%s (v%d) is not supported by this " + "implementation of ZFS.\n"), + zfs_get_name(zhp), zfs_version); + (*count)++; + } + + zfs_iter_filesystems(zhp, check_unsupp_fs, unsupp_fs); + + zfs_close(zhp); + + return (0); +} + static int upgrade_version(zpool_handle_t *zhp, uint64_t version) { int ret; nvlist_t *config; uint64_t oldversion; + int unsupp_fs = 0; config = zpool_get_config(zhp, NULL); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, @@ -4615,6 +4636,17 @@ upgrade_version(zpool_handle_t *zhp, uint64_t version) assert(SPA_VERSION_IS_SUPPORTED(oldversion)); assert(oldversion < version); + ret = zfs_iter_root(zpool_get_handle(zhp), check_unsupp_fs, &unsupp_fs); + if (ret != 0) + return (ret); + + if (unsupp_fs) { + (void) printf(gettext("Upgrade not performed due to %d " + "unsupported filesystems (max v%d).\n"), + unsupp_fs, (int) ZPL_VERSION); + return (1); + } + ret = zpool_upgrade(zhp, version); if (ret != 0) return (ret); diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index a27ac694d..eea78417a 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -679,12 +679,7 @@ zfs_sb_create(const char *osname, zfs_sb_t **zsbp) error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zsb->z_version); if (error) { goto out; - } else if (zsb->z_version > - zfs_zpl_version_map(spa_version(dmu_objset_spa(os)))) { - (void) printk("Can't mount a version %lld file system " - "on a version %lld pool\n. Pool must be upgraded to mount " - "this file system.", (u_longlong_t)zsb->z_version, - (u_longlong_t)spa_version(dmu_objset_spa(os))); + } else if (zsb->z_version > ZPL_VERSION) { error = SET_ERROR(ENOTSUP); goto out; }