commit 8aa13d867d8c707450bb1de1479e18a3bbbc324a Author: Peter Rajnoha Date: Tue Dec 1 13:10:31 2015 +0100 bz1274676 --- lib/activate/dev_manager.c | 11 ++++-- libdm/.exported_symbols.Base | 1 - libdm/.exported_symbols.DM_1_02_107 | 1 + libdm/libdevmapper.h | 5 +++ libdm/libdm-deptree.c | 25 ++++++++++++-- test/shell/lvextend-thin-bz1274676.sh | 63 +++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 6 deletions(-) diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index c8e9589..e1f547f 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -3277,7 +3277,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv, break; case SUSPEND: dm_tree_skip_lockfs(root); - if (!dm->flush_required && lv_is_mirror(lv) && !lv_is_pvmove(lv)) + if (!dm->flush_required && !lv_is_pvmove(lv)) dm_tree_use_no_flush_suspend(root); /* Fall through */ case SUSPEND_WITH_LOCKFS: @@ -3296,7 +3296,14 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv, if (!dm_tree_preload_children(root, dlid, DLID_SIZE)) goto_out; - if (dm_tree_node_size_changed(root)) + if ((dm_tree_node_size_changed(root) < 0)) + dm->flush_required = 1; + + /* Currently keep the code require flush for any + * non 'thin pool/volume, mirror' or with any size change */ + if (!lv_is_thin_volume(lv) && + !lv_is_thin_pool(lv) && + (!lv_is_mirror(lv) || dm_tree_node_size_changed(root))) dm->flush_required = 1; if (action == ACTIVATE) { diff --git a/libdm/.exported_symbols.Base b/libdm/.exported_symbols.Base index f9c3cb1..27fef53 100644 --- a/libdm/.exported_symbols.Base +++ b/libdm/.exported_symbols.Base @@ -262,7 +262,6 @@ dm_tree_node_set_thin_external_origin dm_tree_node_set_thin_pool_discard dm_tree_node_set_thin_pool_error_if_no_space dm_tree_node_set_udev_flags -dm_tree_node_size_changed dm_tree_preload_children dm_tree_retry_remove dm_tree_set_cookie diff --git a/libdm/.exported_symbols.DM_1_02_107 b/libdm/.exported_symbols.DM_1_02_107 index 89d3464..0c7b7af 100644 --- a/libdm/.exported_symbols.DM_1_02_107 +++ b/libdm/.exported_symbols.DM_1_02_107 @@ -13,3 +13,4 @@ dm_stats_create_region dm_stats_driver_supports_histogram dm_stats_get_histogram dm_stats_get_region_nr_histogram_bins +dm_tree_node_size_changed diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 098fa85..8d4b096 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1252,6 +1252,11 @@ const char *dm_tree_node_get_name(const struct dm_tree_node *node); const char *dm_tree_node_get_uuid(const struct dm_tree_node *node); const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node); void *dm_tree_node_get_context(const struct dm_tree_node *node); +/* + * Returns 0 when node size and its children is unchanged. + * Returns 1 when node or any of its children has increased size. + * Rerurns -1 when node or any of its children has reduced size. + */ int dm_tree_node_size_changed(const struct dm_tree_node *dnode); /* diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c index fc79e33..0584079 100644 --- a/libdm/libdm-deptree.c +++ b/libdm/libdm-deptree.c @@ -220,7 +220,7 @@ struct load_properties { uint32_t read_ahead_flags; unsigned segment_count; - unsigned size_changed; + int size_changed; struct dm_list segs; const char *new_name; @@ -2768,7 +2768,8 @@ static int _load_node(struct dm_tree_node *dnode) existing_table_size = dm_task_get_existing_table_size(dmt); if ((dnode->props.size_changed = - (existing_table_size == seg_start) ? 0 : 1)) { + (existing_table_size == seg_start) ? 0 : + (existing_table_size > seg_start) ? -1 : 1)) { /* * Kernel usually skips size validation on zero-length devices * now so no need to preload them. @@ -2864,8 +2865,10 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, } /* Propagate device size change change */ - if (child->props.size_changed) + if (child->props.size_changed > 0 && !dnode->props.size_changed) dnode->props.size_changed = 1; + else if (child->props.size_changed < 0) + dnode->props.size_changed = -1; /* Resume device immediately if it has parents and its size changed */ if (!dm_tree_node_num_children(child, 1) || !child->props.size_changed) @@ -4190,3 +4193,19 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode, dnode->callback = cb; dnode->callback_data = data; } + +/* + * Backward compatible dm_tree_node_size_changed() implementations. + * + * Keep these at the end of the file to avoid adding clutter around the + * current dm_tree_node_size_changed() version. + */ +#if defined(__GNUC__) +int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode); +DM_EXPORT_SYMBOL_BASE(dm_tree_node_size_changed); +int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode) +{ + /* Base does not make difference between smaller and bigger */ + return dm_tree_node_size_changed(dnode) ? 1 : 0; +} +#endif diff --git a/test/shell/lvextend-thin-bz1274676.sh b/test/shell/lvextend-thin-bz1274676.sh new file mode 100644 index 0000000..facace0 --- /dev/null +++ b/test/shell/lvextend-thin-bz1274676.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Copyright (C) 2015 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# ensure there is no data loss during thin-pool resize + +export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false} + +. lib/inittest + +test -e LOCAL_LVMPOLLD && skip + +which md5sum || skip + +aux have_thin 1 0 0 || skip + +aux prepare_pvs 2 20 + +vgcreate -s 512K $vg $(< DEVICES) + +lvcreate -L1M -V2M -n $lv1 -T $vg/pool + +# just ensure we check what we need to check +check lv_field $vg/pool size "1.00m" +check lv_field $vg/$lv1 size "2.00m" + +# prepare 2097152 file content +seq 0 315465 > 2M +md5sum 2M | cut -f 1 -d ' ' | tee MD5 +dd if=2M of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=512K conv=fdatasync 2>&1 >log & +#dd if=2M of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=2M oflag=direct & + +# give it some time to fill thin-volume +# eventually loop to wait for 100% full pool... +sleep .1 +lvs -a $vg + +# this must not 'block & wait' on suspending flush +# if it waits on thin-pool's target timeout +# it will harm queued data +lvextend -L+512k $vg/pool +lvextend -L+512k $vg/pool + +# collect 'dd' result +wait +cat log + +lvs -a $vg + +dd if="$DM_DEV_DIR/mapper/$vg-$lv1" of=2M-2 iflag=direct +md5sum 2M-2 | cut -f 1 -d ' ' | tee MD5-2 + +# these 2 are supposed to match +diff MD5 MD5-2 + +vgremove -f $vg