diff -Nru zfs-linux-0.6.5.2/debian/changelog zfs-linux-0.6.5.3/debian/changelog --- zfs-linux-0.6.5.2/debian/changelog 2015-09-30 18:15:59.000000000 +0000 +++ zfs-linux-0.6.5.3/debian/changelog 2015-10-19 23:33:44.000000000 +0000 @@ -1,3 +1,19 @@ +zfs-linux (0.6.5.3-1~precise) precise; urgency=low + + [ James Lee ] + * zfs-import: Perform verbatim import using cache file + + [ Chunwei Chen ] + * Fix use-after-free in vdev_disk_physio_completion + + [ Justin T. Gibbs ] + * Illumos 6267 - dn_bonus evicted too early + + [ Ned Bass ] + * Prepare to tag zfs-0.6.5.3 + + -- Darik Horn Mon, 19 Oct 2015 19:33:04 -0400 + zfs-linux (0.6.5.2-1~precise) precise; urgency=low [ Ned Bass ] diff -Nru zfs-linux-0.6.5.2/etc/init.d/zfs-import.in zfs-linux-0.6.5.3/etc/init.d/zfs-import.in --- zfs-linux-0.6.5.2/etc/init.d/zfs-import.in 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/etc/init.d/zfs-import.in 2015-10-13 22:35:23.000000000 +0000 @@ -1,11 +1,10 @@ #!@SHELL@ # -# zfs-import This script will import/export zfs pools. +# zfs-import This script will import ZFS pools # # chkconfig: 2345 01 99 -# description: This script will import/export zfs pools during system -# boot/shutdown. -# It is also responsible for all userspace zfs services. +# description: This script will perform a verbatim import of ZFS pools +# during system boot. # probe: true # ### BEGIN INIT INFO @@ -17,7 +16,7 @@ # X-Start-Before: checkfs # X-Stop-After: zfs-mount # Short-Description: Import ZFS pools -# Description: Run the `zpool import` or `zpool export` commands. +# Description: Run the `zpool import` command. ### END INIT INFO # # NOTE: Not having '$local_fs' on Required-Start but only on Required-Stop @@ -43,6 +42,16 @@ keyword -lxc -openvz -prefix -vserver } +# Use the zpool cache file to import pools +do_verbatim_import() +{ + if [ -f "$ZPOOL_CACHE" ] + then + zfs_action "Importing ZFS pool(s)" \ + "$ZPOOL" import -c "$ZPOOL_CACHE" -N -a + fi +} + # Support function to get a list of all pools, separated with ';' find_pools() { @@ -60,8 +69,8 @@ echo "${pools%%;}" # Return without the last ';'. } -# Import all pools -do_import() +# Find and import all visible pools, even exported ones +do_import_all_visible() { local already_imported available_pools pool npools local exception dir ZPOOL_IMPORT_PATH RET=0 r=1 @@ -109,7 +118,7 @@ fi fi - # Filter out any exceptions... + # Filter out any exceptions... if [ -n "$ZFS_POOL_EXCEPTIONS" ] then local found="" @@ -249,41 +258,15 @@ return "$RET" } -# Export all pools -do_export() +do_import() { - local already_imported pool root_pool RET r - RET=0 - - root_pool=$(get_root_pool) - - [ -n "$init" ] && zfs_log_begin_msg "Exporting ZFS pool(s)" - - # Find list of already imported pools. - already_imported=$(find_pools "$ZPOOL" list -H -oname) - - OLD_IFS="$IFS" ; IFS=";" - for pool in $already_imported; do - [ "$pool" = "$root_pool" ] && continue - - if [ -z "$init" ] - then - # Interactive - one 'Importing ...' line per pool - zfs_log_begin_msg "Exporting ZFS pool $pool" - else - # Not interactive - a dot for each pool. - zfs_log_progress_msg "." - fi - - "$ZPOOL" export "$pool" - r="$?" ; RET=$((RET + r)) - [ -z "$init" ] && zfs_log_end_msg "$r" - done - IFS="$OLD_IFS" - - [ -n "$init" ] && zfs_log_end_msg "$RET" - - return "$RET" + if check_boolean "$ZPOOL_IMPORT_ALL_VISIBLE" + then + do_import_all_visible + else + # This is the default option + do_verbatim_import + fi } # Output the status and list of pools @@ -323,14 +306,6 @@ fi } -do_stop() -{ - # Check to see if the module is even loaded. - check_module_loaded "zfs" || exit 0 - - do_export -} - # ---------------------------------------------------- if [ ! -e /etc/gentoo-release ] @@ -340,7 +315,7 @@ do_start ;; stop) - do_stop + # no-op ;; status) do_status @@ -350,7 +325,7 @@ ;; *) [ -n "$1" ] && echo "Error: Unknown command $1." - echo "Usage: $0 {start|stop|status}" + echo "Usage: $0 {start|status}" exit 3 ;; esac @@ -360,6 +335,5 @@ # Create wrapper functions since Gentoo don't use the case part. depend() { do_depend; } start() { do_start; } - stop() { do_stop; } status() { do_status; } fi diff -Nru zfs-linux-0.6.5.2/etc/init.d/zfs.in zfs-linux-0.6.5.3/etc/init.d/zfs.in --- zfs-linux-0.6.5.2/etc/init.d/zfs.in 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/etc/init.d/zfs.in 2015-10-13 22:35:23.000000000 +0000 @@ -16,6 +16,24 @@ # Run `zfs unshare -a` during system stop? ZFS_UNSHARE='yes' +# By default, a verbatim import of all pools is performed at boot based on the +# contents of the default zpool cache file. The contents of the cache are +# managed automatically by the 'zpool import' and 'zpool export' commands. +# +# By setting this to 'yes', the system will instead search all devices for +# pools and attempt to import them all at boot, even those that have been +# exported. Under this mode, the search path can be controlled by the +# ZPOOL_IMPORT_PATH variable and a list of pools that should not be imported +# can be listed in the ZFS_POOL_EXCEPTIONS variable. +# +# Note that importing all visible pools may include pools that you don't +# expect, such as those on removable devices and SANs, and those pools may +# proceed to mount themselves in places you do not want them to. The results +# can be unpredictable and possibly dangerous. Only enable this option if you +# understand this risk and have complete physical control over your system and +# SAN to prevent the insertion of malicious pools. +ZPOOL_IMPORT_ALL_VISIBLE='no' + # Specify specific path(s) to look for device nodes and/or links for the # pool import(s). See zpool(8) for more information about this variable. # It supersedes the old USE_DISK_BY_ID which indicated that it would only @@ -23,6 +41,18 @@ # The old variable will still work in the code, but is deprecated. #ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:/dev/disk/by-id" +# List of pools that should NOT be imported at boot +# when ZPOOL_IMPORT_ALL_VISIBLE is 'yes'. +# This is a space separated list. +#ZFS_POOL_EXCEPTIONS="test2" + +# List of pools that SHOULD be imported at boot by the initramfs +# instead of trying to import all available pools. If this is set +# then ZFS_POOL_EXCEPTIONS is ignored. +# Only applicable for Debian GNU/Linux {dkms,initramfs}. +# This is a semi-colon separated list. +#ZFS_POOL_IMPORT="pool1;pool2" + # Should the datasets be mounted verbosely? # A mount counter will be used when mounting if set to 'yes'. VERBOSE_MOUNT='no' @@ -97,17 +127,6 @@ # Example: If root FS is 'rpool/ROOT/rootfs', this would make sense. #ZFS_INITRD_ADDITIONAL_DATASETS="rpool/ROOT/usr rpool/ROOT/var" -# List of pools that should NOT be imported at boot? -# This is a space separated list. -#ZFS_POOL_EXCEPTIONS="test2" - -# List of pools to import? -# If this variable is set, there will be NO auto-import of ANY other -# pool. In essence, there will be no auto detection of availible pools. -# This is a semi-colon separated list. -# Makes the variable ZFS_POOL_EXCEPTIONS above redundant (won't be checked). -#ZFS_POOL_IMPORT="pool1;pool2" - # Optional arguments for the ZFS Event Daemon (ZED). # See zed(8) for more information on available options. #ZED_ARGS="-M" diff -Nru zfs-linux-0.6.5.2/include/sys/dbuf.h zfs-linux-0.6.5.3/include/sys/dbuf.h --- zfs-linux-0.6.5.2/include/sys/dbuf.h 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/include/sys/dbuf.h 2015-10-13 22:35:23.000000000 +0000 @@ -230,9 +230,25 @@ /* User callback information. */ dmu_buf_user_t *db_user; - uint8_t db_immediate_evict; + /* + * Evict user data as soon as the dirty and reference + * counts are equal. + */ + uint8_t db_user_immediate_evict; + + /* + * This block was freed while a read or write was + * active. + */ uint8_t db_freed_in_flight; + /* + * dnode_evict_dbufs() or dnode_evict_bonus() tried to + * evict this dbuf, but couldn't due to outstanding + * references. Evict once the refcount drops to 0. + */ + uint8_t db_pending_evict; + uint8_t db_dirtycnt; } dmu_buf_impl_t; diff -Nru zfs-linux-0.6.5.2/include/sys/dmu_objset.h zfs-linux-0.6.5.3/include/sys/dmu_objset.h --- zfs-linux-0.6.5.2/include/sys/dmu_objset.h 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/include/sys/dmu_objset.h 2015-10-13 22:35:23.000000000 +0000 @@ -93,7 +93,6 @@ uint8_t os_copies; enum zio_checksum os_dedup_checksum; boolean_t os_dedup_verify; - boolean_t os_evicting; zfs_logbias_op_t os_logbias; zfs_cache_type_t os_primary_cache; zfs_cache_type_t os_secondary_cache; diff -Nru zfs-linux-0.6.5.2/META zfs-linux-0.6.5.3/META --- zfs-linux-0.6.5.2/META 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/META 2015-10-13 22:35:23.000000000 +0000 @@ -1,7 +1,7 @@ Meta: 1 Name: zfs Branch: 1.0 -Version: 0.6.5.2 +Version: 0.6.5.3 Release: 1 Release-Tags: relext License: CDDL diff -Nru zfs-linux-0.6.5.2/module/zfs/dbuf.c zfs-linux-0.6.5.3/module/zfs/dbuf.c --- zfs-linux-0.6.5.2/module/zfs/dbuf.c 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/module/zfs/dbuf.c 2015-10-13 22:35:23.000000000 +0000 @@ -303,7 +303,7 @@ */ ASSERT3U(holds, >=, db->db_dirtycnt); } else { - if (db->db_immediate_evict == TRUE) + if (db->db_user_immediate_evict == TRUE) ASSERT3U(holds, >=, db->db_dirtycnt); else ASSERT3U(holds, >, 0); @@ -1880,8 +1880,9 @@ db->db_blkptr = blkptr; db->db_user = NULL; - db->db_immediate_evict = 0; - db->db_freed_in_flight = 0; + db->db_user_immediate_evict = FALSE; + db->db_freed_in_flight = FALSE; + db->db_pending_evict = FALSE; if (blkid == DMU_BONUS_BLKID) { ASSERT3P(parent, ==, dn->dn_dbuf); @@ -2318,12 +2319,13 @@ arc_buf_freeze(db->db_buf); if (holds == db->db_dirtycnt && - db->db_level == 0 && db->db_immediate_evict) + db->db_level == 0 && db->db_user_immediate_evict) dbuf_evict_user(db); if (holds == 0) { if (db->db_blkid == DMU_BONUS_BLKID) { dnode_t *dn; + boolean_t evict_dbuf = db->db_pending_evict; /* * If the dnode moves here, we cannot cross this @@ -2338,7 +2340,7 @@ * Decrementing the dbuf count means that the bonus * buffer's dnode hold is no longer discounted in * dnode_move(). The dnode cannot move until after - * the dnode_rele_and_unlock() below. + * the dnode_rele() below. */ DB_DNODE_EXIT(db); @@ -2348,35 +2350,10 @@ */ mutex_exit(&db->db_mtx); - /* - * If the dnode has been freed, evict the bonus - * buffer immediately. The data in the bonus - * buffer is no longer relevant and this prevents - * a stale bonus buffer from being associated - * with this dnode_t should the dnode_t be reused - * prior to being destroyed. - */ - mutex_enter(&dn->dn_mtx); - if (dn->dn_type == DMU_OT_NONE || - dn->dn_free_txg != 0) { - /* - * Drop dn_mtx. It is a leaf lock and - * cannot be held when dnode_evict_bonus() - * acquires other locks in order to - * perform the eviction. - * - * Freed dnodes cannot be reused until the - * last hold is released. Since this bonus - * buffer has a hold, the dnode will remain - * in the free state, even without dn_mtx - * held, until the dnode_rele_and_unlock() - * below. - */ - mutex_exit(&dn->dn_mtx); + if (evict_dbuf) dnode_evict_bonus(dn); - mutex_enter(&dn->dn_mtx); - } - dnode_rele_and_unlock(dn, db); + + dnode_rele(dn, db); } else if (db->db_buf == NULL) { /* * This is a special case: we never associated this @@ -2423,7 +2400,7 @@ } else { dbuf_clear(db); } - } else if (db->db_objset->os_evicting || + } else if (db->db_pending_evict || arc_buf_eviction_needed(db->db_buf)) { dbuf_clear(db); } else { @@ -2471,7 +2448,7 @@ { dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake; - db->db_immediate_evict = TRUE; + db->db_user_immediate_evict = TRUE; return (dmu_buf_set_user(db_fake, user)); } diff -Nru zfs-linux-0.6.5.2/module/zfs/dmu_objset.c zfs-linux-0.6.5.3/module/zfs/dmu_objset.c --- zfs-linux-0.6.5.2/module/zfs/dmu_objset.c 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/module/zfs/dmu_objset.c 2015-10-13 22:35:23.000000000 +0000 @@ -726,7 +726,6 @@ if (os->os_sa) sa_tear_down(os); - os->os_evicting = B_TRUE; dmu_objset_evict_dbufs(os); mutex_enter(&os->os_lock); diff -Nru zfs-linux-0.6.5.2/module/zfs/dnode_sync.c zfs-linux-0.6.5.3/module/zfs/dnode_sync.c --- zfs-linux-0.6.5.2/module/zfs/dnode_sync.c 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/module/zfs/dnode_sync.c 2015-10-13 22:35:23.000000000 +0000 @@ -432,6 +432,7 @@ db_next = AVL_NEXT(&dn->dn_dbufs, db_marker); avl_remove(&dn->dn_dbufs, db_marker); } else { + db->db_pending_evict = TRUE; mutex_exit(&db->db_mtx); db_next = AVL_NEXT(&dn->dn_dbufs, db); } @@ -447,10 +448,14 @@ dnode_evict_bonus(dnode_t *dn) { rw_enter(&dn->dn_struct_rwlock, RW_WRITER); - if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) { - mutex_enter(&dn->dn_bonus->db_mtx); - dbuf_evict(dn->dn_bonus); - dn->dn_bonus = NULL; + if (dn->dn_bonus != NULL) { + if (refcount_is_zero(&dn->dn_bonus->db_holds)) { + mutex_enter(&dn->dn_bonus->db_mtx); + dbuf_evict(dn->dn_bonus); + dn->dn_bonus = NULL; + } else { + dn->dn_bonus->db_pending_evict = TRUE; + } } rw_exit(&dn->dn_struct_rwlock); } @@ -502,7 +507,6 @@ dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]); dnode_evict_dbufs(dn); - ASSERT(avl_is_empty(&dn->dn_dbufs)); /* * XXX - It would be nice to assert this, but we may still diff -Nru zfs-linux-0.6.5.2/module/zfs/vdev_disk.c zfs-linux-0.6.5.3/module/zfs/vdev_disk.c --- zfs-linux-0.6.5.2/module/zfs/vdev_disk.c 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/module/zfs/vdev_disk.c 2015-10-13 22:35:23.000000000 +0000 @@ -42,9 +42,9 @@ */ typedef struct dio_request { struct completion dr_comp; /* Completion for sync IO */ - atomic_t dr_ref; /* References */ zio_t *dr_zio; /* Parent ZIO */ - int dr_rw; /* Read/Write */ + atomic_t dr_ref; /* References */ + int dr_wait; /* Wait for IO */ int dr_error; /* Bio error */ int dr_bio_count; /* Count of bio's */ struct bio *dr_bio[0]; /* Attached bio's */ @@ -407,6 +407,7 @@ { dio_request_t *dr = bio->bi_private; int rc; + int wait; if (dr->dr_error == 0) { #ifdef HAVE_1ARG_BIO_END_IO_T @@ -419,11 +420,12 @@ #endif } + wait = dr->dr_wait; /* Drop reference aquired by __vdev_disk_physio */ rc = vdev_disk_dio_put(dr); /* Wake up synchronous waiter this is the last outstanding bio */ - if (rc == 1) + if (wait && rc == 1) complete(&dr->dr_comp); } @@ -496,7 +498,7 @@ dio_request_t *dr; caddr_t bio_ptr; uint64_t bio_offset; - int bio_size, bio_count = 16; + int rw, bio_size, bio_count = 16; int i = 0, error = 0; ASSERT3U(kbuf_offset + kbuf_size, <=, bdev->bd_inode->i_size); @@ -509,8 +511,9 @@ if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) bio_set_flags_failfast(bdev, &flags); + rw = flags; dr->dr_zio = zio; - dr->dr_rw = flags; + dr->dr_wait = wait; /* * When the IO size exceeds the maximum bio size for the request @@ -552,7 +555,7 @@ dr->dr_bio[i]->bi_bdev = bdev; BIO_BI_SECTOR(dr->dr_bio[i]) = bio_offset >> 9; - dr->dr_bio[i]->bi_rw = dr->dr_rw; + dr->dr_bio[i]->bi_rw = rw; dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion; dr->dr_bio[i]->bi_private = dr; @@ -572,7 +575,7 @@ /* Submit all bio's associated with this dio */ for (i = 0; i < dr->dr_bio_count; i++) if (dr->dr_bio[i]) - vdev_submit_bio(dr->dr_rw, dr->dr_bio[i]); + vdev_submit_bio(rw, dr->dr_bio[i]); /* * On synchronous blocking requests we wait for all bio the completion diff -Nru zfs-linux-0.6.5.2/rpm/generic/zfs-kmod.spec.in zfs-linux-0.6.5.3/rpm/generic/zfs-kmod.spec.in --- zfs-linux-0.6.5.2/rpm/generic/zfs-kmod.spec.in 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/rpm/generic/zfs-kmod.spec.in 2015-10-13 22:35:23.000000000 +0000 @@ -185,6 +185,10 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Tue Oct 13 2015 Ned Bass - 0.6.5.3-1 +- Don't import all visible pools in zfs-import init script zfsonlinux/zfs#3777 +- Fix use-after-free in vdev_disk_physio_completion zfsonlinux/zfs#3920 +- Fix avl_is_empty(&dn->dn_dbufs) assertion zfsonlinux/zfs#3865 * Wed Sep 30 2015 Ned Bass - 0.6.5.2-1 - Init script fixes zfsonlinux/zfs#3816 - Fix uioskip crash when skip to end zfsonlinux/zfs#3806 zfsonlinux/zfs#3850 diff -Nru zfs-linux-0.6.5.2/rpm/generic/zfs.spec.in zfs-linux-0.6.5.3/rpm/generic/zfs.spec.in --- zfs-linux-0.6.5.2/rpm/generic/zfs.spec.in 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/rpm/generic/zfs.spec.in 2015-10-13 22:35:23.000000000 +0000 @@ -332,6 +332,10 @@ %endif %changelog +* Tue Oct 13 2015 Ned Bass - 0.6.5.3-1 +- Don't import all visible pools in zfs-import init script zfsonlinux/zfs#3777 +- Fix use-after-free in vdev_disk_physio_completion zfsonlinux/zfs#3920 +- Fix avl_is_empty(&dn->dn_dbufs) assertion zfsonlinux/zfs#3865 * Wed Sep 30 2015 Ned Bass - 0.6.5.2-1 - Init script fixes zfsonlinux/zfs#3816 - Fix uioskip crash when skip to end zfsonlinux/zfs#3806 zfsonlinux/zfs#3850 diff -Nru zfs-linux-0.6.5.2/rpm/redhat/zfs.spec.in zfs-linux-0.6.5.3/rpm/redhat/zfs.spec.in --- zfs-linux-0.6.5.2/rpm/redhat/zfs.spec.in 2015-09-30 16:25:54.000000000 +0000 +++ zfs-linux-0.6.5.3/rpm/redhat/zfs.spec.in 2015-10-13 22:35:23.000000000 +0000 @@ -332,6 +332,10 @@ %endif %changelog +* Tue Oct 13 2015 Ned Bass - 0.6.5.3-1 +- Don't import all visible pools in zfs-import init script zfsonlinux/zfs#3777 +- Fix use-after-free in vdev_disk_physio_completion zfsonlinux/zfs#3920 +- Fix avl_is_empty(&dn->dn_dbufs) assertion zfsonlinux/zfs#3865 * Wed Sep 30 2015 Ned Bass - 0.6.5.2-1 - Init script fixes zfsonlinux/zfs#3816 - Fix uioskip crash when skip to end zfsonlinux/zfs#3806 zfsonlinux/zfs#3850