diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c index 2ec66e7e3..72fa508c0 100644 --- a/libdm/libdm-common.c +++ b/libdm/libdm-common.c @@ -1073,6 +1073,24 @@ static int _rename_dev_node(const char *old_name, const char *new_name, oldpath, newpath); /* udev may already have renamed the node. Ignore ENOENT. */ + /* FIXME: when renaming to target mangling mode "none" with udev + * while there are some blacklisted characters in the node name, + * udev will remove the old_node, but fails to properly rename + * to new_node. The libdevmapper code tries to call + * rename(old_node,new_node), but that won't do anything + * since the old node is already removed by udev. + * For example renaming 'a\x20b' to 'a b': + * - udev removes 'a\x20b' + * - udev creates 'a' and 'b' (since it considers the ' ' as a delimiter + * - libdevmapper checks udev has done the rename properly + * - libdevmapper calls stat(new_node) and it does not see it + * - libdevmapper calls rename(old_node,new_node) + * - the rename is a NOP since the old_node does not exist anymore + * + * However, this situation is very rare - why would anyone need + * to rename to an unsupported mode??? So a fix for this would be + * just for completeness. + */ if (rename(oldpath, newpath) < 0 && errno != ENOENT) { log_error("Unable to rename device node from '%s' to '%s'", old_name, new_name); diff --git a/test/shell/name-mangling.sh b/test/shell/name-mangling.sh index 2f0752317..cf218fe9c 100644 --- a/test/shell/name-mangling.sh +++ b/test/shell/name-mangling.sh @@ -129,7 +129,7 @@ function check_mangle_cmd() create_dm_dev none "$dm_name" - dmsetup mangle --manglename $mode "${PREFIX}$dm_name" 1>out 2>err || true; + dmsetup mangle --manglename $mode --verifyudev "${PREFIX}$dm_name" 1>out 2>err || true; if [ "$expected" = "OK" ]; then grep "$CORRECT_FORM_STR" out || r=1 @@ -139,7 +139,30 @@ function check_mangle_cmd() grep "$FAIL_MULTI_STR" err || r=1 else rename_expected=1 - grep -F "$RENAMING_STR ${PREFIX}$expected" out || r=1 + if grep -F "$RENAMING_STR ${PREFIX}$expected" out; then + # Check the old node is really renamed. + test -b "$DM_DEV_DIR/mapper/${PREFIX}$dm_name" && r=1 + # FIXME: when renaming to mode=none with udev, udev will + # remove the old_node, but fails to properly rename + # to new_node. The libdevmapper code tries to call + # rename(old_node,new_node), but that won't do anything + # since the old node is already removed by udev. + # For example renaming 'a\x20b' to 'a b': + # - udev removes 'a\x20b' + # - udev creates 'a' and 'b' (since it considers the ' ' as a delimiter) + # - libdevmapper checks udev has done the rename properly + # - libdevmapper calls stat(new_node) and it does not see it + # - libdevmapper calls rename(old_node,new_node) + # - the rename is a NOP since the old_node does not exist anymore + # + # Remove this condition once the problem is fixed in libdevmapper. + # + if [ "$mode" != "none" ]; then + test -b "$DM_DEV_DIR/mapper/${PREFIX}$expected" || r=1 + fi + else + r=1 + fi fi if [ $r = 0 -a $rename_expected = 1 ]; then @@ -149,7 +172,7 @@ function check_mangle_cmd() # failed to rename to expected or renamed when it should not - find the new name new_name=$(sed -e "s/.*: $RENAMING_STR //g" out) # try to remove any of the form - falling back to less probable error scenario - aux dmsetup remove --verifyudev --manglename none "$new_name" || \ + remove_dm_dev none "$new_name" || \ remove_dm_dev none "$dm_name" || remove_dm_dev none "$expected" else # successfuly done nothing