From: Benjamin Marzinski <bmarzins@redhat.com>
To: mwilck@suse.com
Cc: dm-devel@redhat.com
Subject: Re: [PATCH 08/35] libmultipath: create bitfield abstraction
Date: Thu, 16 Jul 2020 16:17:08 -0500 [thread overview]
Message-ID: <20200716211708.GM11089@octiron.msp.redhat.com> (raw)
In-Reply-To: <20200709101620.6786-9-mwilck@suse.com>
On Thu, Jul 09, 2020 at 12:15:53PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> In e32d521d ("libmultipath: coalesce_paths: fix size mismatch handling"),
> we introduced simple bitmap handling functions. We can do better. This
> patch introduces a bitfield type with overflow detection and a
> find_first_set() method.
>
> Use this in coalesce_paths(), and adapt the unit tests. Also, add
> unit tests for "odd" bitfield sizes; so far we tested only multiples
> of 64.
>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/configure.c | 9 +-
> libmultipath/util.c | 35 ++++++
> libmultipath/util.h | 57 ++++++++-
> tests/util.c | 263 +++++++++++++++++++++++++++++++++++----
> 4 files changed, 327 insertions(+), 37 deletions(-)
>
> diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> index 96c7961..fe590f4 100644
> --- a/libmultipath/configure.c
> +++ b/libmultipath/configure.c
> @@ -1092,7 +1092,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> vector pathvec = vecs->pathvec;
> struct config *conf;
> int allow_queueing;
> - uint64_t *size_mismatch_seen;
> + struct bitfield *size_mismatch_seen;
>
> /* ignore refwwid if it's empty */
> if (refwwid && !strlen(refwwid))
> @@ -1106,8 +1106,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
>
> if (VECTOR_SIZE(pathvec) == 0)
> return CP_OK;
> - size_mismatch_seen = calloc((VECTOR_SIZE(pathvec) - 1) / 64 + 1,
> - sizeof(uint64_t));
> + size_mismatch_seen = alloc_bitfield(VECTOR_SIZE(pathvec));
> if (size_mismatch_seen == NULL)
> return CP_FAIL;
>
> @@ -1131,7 +1130,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> }
>
> /* 2. if path already coalesced, or seen and discarded */
> - if (pp1->mpp || is_bit_set_in_array(k, size_mismatch_seen))
> + if (pp1->mpp || is_bit_set_in_bitfield(k, size_mismatch_seen))
> continue;
>
> /* 3. if path has disappeared */
> @@ -1183,7 +1182,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> "Discard", pp2->dev, pp2->size,
> mpp->size);
> mpp->action = ACT_REJECT;
> - set_bit_in_array(i, size_mismatch_seen);
> + set_bit_in_bitfield(i, size_mismatch_seen);
> }
> }
> verify_paths(mpp, vecs);
> diff --git a/libmultipath/util.c b/libmultipath/util.c
> index 3c43f28..46cacd4 100644
> --- a/libmultipath/util.c
> +++ b/libmultipath/util.c
> @@ -404,3 +404,38 @@ void close_fd(void *arg)
> {
> close((long)arg);
> }
> +
> +struct bitfield *alloc_bitfield(unsigned int maxbit)
> +{
> + unsigned int n;
> + struct bitfield *bf;
> +
> + n = maxbit > 0 ? (maxbit - 1) / bits_per_slot + 1 : 0;
What's the point in accepting 0? That's an empty bitmap.
> + bf = calloc(1, sizeof(struct bitfield) + n * sizeof(bitfield_t));
Need to check that bf got set before dereferencing it.
> + bf->len = maxbit;
> + return bf;
> +}
> +
> +void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len)
> +{
> + condlog(0, "%s: bitfield overflow: %u >= %u", f, bit, len);
> +}
> +
> +unsigned int find_first_set(const struct bitfield *bf)
> +{
> + unsigned int b = 0, i, n;
> +
> + for (i = 0; i < bf->len; i+= bits_per_slot) {
> + b = _ffs(bf->bits[i / bits_per_slot]);
> + if (b != 0)
> + break;
> + };
> + if (b == 0)
> + return 0;
> +
> + n = i + b;
> + if (n <= bf->len)
> + return n;
> +
> + return 0;
> +}
This is neat and all, but what's it for? I didn't see it used in the
rest of the patches. Did I miss it, or do you have a future use for it?
> diff --git a/libmultipath/util.h b/libmultipath/util.h
> index df75c4f..ec6de6d 100644
> --- a/libmultipath/util.h
> +++ b/libmultipath/util.h
> @@ -1,6 +1,9 @@
> #ifndef _UTIL_H
> #define _UTIL_H
>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <limits.h>
> #include <sys/types.h>
> /* for rlim_t */
> #include <sys/resource.h>
> @@ -51,19 +54,61 @@ struct scandir_result {
> };
> void free_scandir_result(struct scandir_result *);
>
> -static inline bool is_bit_set_in_array(unsigned int bit, const uint64_t *arr)
> +/*
> + * ffsll() is also available on glibc < 2.27 if _GNU_SOURCE is defined.
> + * But relying on that would require that every program using this header file
> + * set _GNU_SOURCE during compilation, because otherwise the library and the
> + * program would use different types for bitfield_t, causing errors.
> + * That's too error prone, so if in doubt, use ffs().
> + */
> +#if __GLIBC_PREREQ(2, 27)
> +typedef unsigned long long int bitfield_t;
> +#define _ffs(x) ffsll(x)
> +#else
> +typedef unsigned int bitfield_t;
> +#define _ffs(x) ffs(x)
> +#endif
> +#define bits_per_slot (sizeof(bitfield_t) * CHAR_BIT)
> +
> +struct bitfield {
> + unsigned int len;
> + bitfield_t bits[];
> +};
> +
> +struct bitfield *alloc_bitfield(unsigned int maxbit);
> +
> +void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len);
> +#define log_bitfield_overflow(bit, len) \
> + _log_bitfield_overflow(__func__, bit, len)
> +
> +static inline bool is_bit_set_in_bitfield(unsigned int bit,
> + const struct bitfield *bf)
> {
> - return arr[bit / 64] & (1ULL << (bit % 64)) ? 1 : 0;
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return false;
> + }
> + return !!(bf->bits[bit / bits_per_slot] &
> + (1ULL << (bit % bits_per_slot)));
> }
>
> -static inline void set_bit_in_array(unsigned int bit, uint64_t *arr)
> +static inline void set_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> {
> - arr[bit / 64] |= (1ULL << (bit % 64));
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return;
> + }
> + bf->bits[bit / bits_per_slot] |= (1ULL << (bit % bits_per_slot));
> }
>
> -static inline void clear_bit_in_array(unsigned int bit, uint64_t *arr)
> +static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> {
> - arr[bit / 64] &= ~(1ULL << (bit % 64));
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return;
> + }
> + bf->bits[bit / bits_per_slot] &= ~(1ULL << (bit % bits_per_slot));
> }
>
> +unsigned int find_first_set(const struct bitfield *bf);
> #endif /* _UTIL_H */
> diff --git a/tests/util.c b/tests/util.c
> index 6d12fda..db7c05f 100644
> --- a/tests/util.c
> +++ b/tests/util.c
> @@ -164,19 +164,25 @@ static int test_basenamecpy(void)
>
> static void test_bitmask_1(void **state)
> {
> - uint64_t arr[BITARR_SZ];
> + struct bitfield *bf;
> + uint64_t *arr;
> int i, j, k, m, b;
>
> - memset(arr, 0, sizeof(arr));
> + bf = alloc_bitfield(BITARR_SZ * 64);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, BITARR_SZ * 64);
> + arr = (uint64_t *)bf->bits;
>
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(!is_bit_set_in_array(b, arr));
> - set_bit_in_array(b, arr);
> + assert(!is_bit_set_in_bitfield(b, bf));
> + set_bit_in_bitfield(b, bf);
> for (k = 0; k < BITARR_SZ; k++) {
> +#if 0
> printf("b = %d j = %d k = %d a = %"PRIx64"\n",
> b, j, k, arr[k]);
> +#endif
> if (k == j)
> assert_int_equal(arr[j], 1ULL << i);
> else
> @@ -184,39 +190,46 @@ static void test_bitmask_1(void **state)
> }
> for (m = 0; m < 64; m++)
> if (i == m)
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> - clear_bit_in_array(b, arr);
> - assert(!is_bit_set_in_array(b, arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert_int_equal(find_first_set(bf), b + 1);
> + clear_bit_in_bitfield(b, bf);
> + assert(!is_bit_set_in_bitfield(b, bf));
> for (k = 0; k < BITARR_SZ; k++)
> assert_int_equal(arr[k], 0ULL);
> }
> }
> + free(bf);
> }
>
> static void test_bitmask_2(void **state)
> {
> - uint64_t arr[BITARR_SZ];
> + struct bitfield *bf;
> + uint64_t *arr;
> int i, j, k, m, b;
>
> - memset(arr, 0, sizeof(arr));
> + bf = alloc_bitfield(BITARR_SZ * 64);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, BITARR_SZ * 64);
> + arr = (uint64_t *)bf->bits;
>
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(!is_bit_set_in_array(b, arr));
> - set_bit_in_array(b, arr);
> + assert(!is_bit_set_in_bitfield(b, bf));
> + set_bit_in_bitfield(b, bf);
> for (m = 0; m < 64; m++)
> if (m <= i)
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> - assert(is_bit_set_in_array(b, arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert(is_bit_set_in_bitfield(b, bf));
> + assert_int_equal(find_first_set(bf), 1);
> for (k = 0; k < BITARR_SZ; k++) {
> if (k < j || (k == j && i == 63))
> assert_int_equal(arr[k], ~0ULL);
> @@ -232,16 +245,20 @@ static void test_bitmask_2(void **state)
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(is_bit_set_in_array(b, arr));
> - clear_bit_in_array(b, arr);
> + assert(is_bit_set_in_bitfield(b, bf));
> + clear_bit_in_bitfield(b, bf);
> for (m = 0; m < 64; m++)
> if (m <= i)
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> - assert(!is_bit_set_in_array(b, arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert(!is_bit_set_in_bitfield(b, bf));
> + if (b == 64 * BITARR_SZ - 1)
> + assert_int_equal(find_first_set(bf), 0);
> + else
> + assert_int_equal(find_first_set(bf), b + 2);
> for (k = 0; k < BITARR_SZ; k++) {
> if (k < j || (k == j && i == 63))
> assert_int_equal(arr[k], 0ULL);
> @@ -254,13 +271,207 @@ static void test_bitmask_2(void **state)
> }
> }
> }
> + free(bf);
> }
>
> +/*
> + * Test operations on a 0-length bitfield
> + */
> +static void test_bitmask_len_0(void **state)
> +{
> + struct bitfield *bf;
> +
> + bf = alloc_bitfield(0);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, 0);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + assert_int_equal(is_bit_set_in_bitfield(1, bf), 0);
> + assert_int_equal(find_first_set(bf), 0);
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + assert_int_equal(find_first_set(bf), 0);
> + clear_bit_in_bitfield(0, bf);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + set_bit_in_bitfield(11, bf);
> + assert_int_equal(find_first_set(bf), 0);
> + assert_int_equal(is_bit_set_in_bitfield(11, bf), 0);
> + clear_bit_in_bitfield(11, bf);
> + assert_int_equal(is_bit_set_in_bitfield(11, bf), 0);
> + free(bf);
> +}
> +
> +static void _test_bitmask_small(unsigned int n)
> +{
> + struct bitfield *bf;
> + uint64_t *arr;
> +
> + assert(n <= 64);
> + assert(n >= 1);
> +
> + bf = alloc_bitfield(n);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, n);
> + arr = (uint64_t *)bf->bits;
> +
> + assert_int_equal(*arr, 0);
> +
> + set_bit_in_bitfield(n + 1, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(*arr, 1ULL << (n - 1));
> + assert_int_equal(find_first_set(bf), n);
> +
> + clear_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(*arr, 1);
> + assert_int_equal(find_first_set(bf), 1);
> +
> + free(bf);
> +}
> +
> +static void _test_bitmask_small_2(unsigned int n)
> +{
> + struct bitfield *bf;
> + uint64_t *arr;
> +
> + assert(n <= 128);
> + assert(n >= 65);
> +
> + bf = alloc_bitfield(n);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, n);
> + arr = (uint64_t *)bf->bits;
> +
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> +
> + set_bit_in_bitfield(n + 1, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 1ULL << (n - 65));
> + assert_int_equal(find_first_set(bf), n);
> +
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(arr[0], 1);
> + assert_int_equal(arr[1], 1ULL << (n - 65));
> + assert_int_equal(find_first_set(bf), 1);
> +
> + set_bit_in_bitfield(64, bf);
> + assert_int_equal(arr[0], 1);
> + assert_int_equal(arr[1], (1ULL << (n - 65)) | 1);
> + assert_int_equal(find_first_set(bf), 1);
> +
> + clear_bit_in_bitfield(0, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], (1ULL << (n - 65)) | 1);
> + assert_int_equal(find_first_set(bf), 65);
> +
> + free(bf);
> +}
> +
> +static void test_bitmask_len_1(void **state)
> +{
> + _test_bitmask_small(1);
> +}
> +
> +static void test_bitmask_len_2(void **state)
> +{
> + _test_bitmask_small(2);
> +}
> +
> +static void test_bitmask_len_3(void **state)
> +{
> + _test_bitmask_small(3);
> +}
> +
> +static void test_bitmask_len_23(void **state)
> +{
> + _test_bitmask_small(23);
> +}
> +
> +static void test_bitmask_len_63(void **state)
> +{
> + _test_bitmask_small(63);
> +}
> +
> +static void test_bitmask_len_64(void **state)
> +{
> + _test_bitmask_small(63);
> +}
> +
> +static void test_bitmask_len_65(void **state)
> +{
> + _test_bitmask_small_2(65);
> +}
> +
> +static void test_bitmask_len_66(void **state)
> +{
> + _test_bitmask_small_2(66);
> +}
> +
> +static void test_bitmask_len_67(void **state)
> +{
> + _test_bitmask_small_2(67);
> +}
> +
> +static void test_bitmask_len_103(void **state)
> +{
> + _test_bitmask_small_2(103);
> +}
> +
> +static void test_bitmask_len_126(void **state)
> +{
> + _test_bitmask_small_2(126);
> +}
> +
> +static void test_bitmask_len_127(void **state)
> +{
> + _test_bitmask_small_2(127);
> +}
> +
> +static void test_bitmask_len_128(void **state)
> +{
> + _test_bitmask_small_2(128);
> +}
> +
> +
> static int test_bitmasks(void)
> {
> const struct CMUnitTest tests[] = {
> cmocka_unit_test(test_bitmask_1),
> cmocka_unit_test(test_bitmask_2),
> + cmocka_unit_test(test_bitmask_len_0),
> + cmocka_unit_test(test_bitmask_len_1),
> + cmocka_unit_test(test_bitmask_len_2),
> + cmocka_unit_test(test_bitmask_len_3),
> + cmocka_unit_test(test_bitmask_len_23),
> + cmocka_unit_test(test_bitmask_len_63),
> + cmocka_unit_test(test_bitmask_len_64),
> + cmocka_unit_test(test_bitmask_len_65),
> + cmocka_unit_test(test_bitmask_len_66),
> + cmocka_unit_test(test_bitmask_len_67),
> + cmocka_unit_test(test_bitmask_len_103),
> + cmocka_unit_test(test_bitmask_len_126),
> + cmocka_unit_test(test_bitmask_len_127),
> + cmocka_unit_test(test_bitmask_len_128),
> };
> return cmocka_run_group_tests(tests, NULL, NULL);
> }
> --
> 2.26.2
next prev parent reply other threads:[~2020-07-16 21:17 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-09 10:15 [PATCH 00/35] multipath-tools series part I: minor changes mwilck
2020-07-09 10:15 ` [PATCH 01/35] multipath-tools tests/util: separate group for bitmask tests mwilck
2020-07-09 10:15 ` [PATCH 02/35] multipath-tools tests/directio: fix missing initializers mwilck
2020-07-09 10:15 ` [PATCH 03/35] tests: __wrap_dlog: use check_expected() mwilck
2020-07-09 10:15 ` [PATCH 04/35] multipath tools tests: add strchop() test mwilck
2020-07-09 10:15 ` [PATCH 05/35] libmultipath: improve strchop() mwilck
2020-07-09 10:15 ` [PATCH 06/35] multipath-tools tests: add test for devt2devname mwilck
2020-07-09 10:15 ` [PATCH 07/35] libmultipath: devt2devname(): simplify using libudev mwilck
2020-07-09 10:15 ` [PATCH 08/35] libmultipath: create bitfield abstraction mwilck
2020-07-16 21:17 ` Benjamin Marzinski [this message]
2020-08-04 15:04 ` Martin Wilck
2020-08-04 15:18 ` Martin Wilck
2020-08-04 16:26 ` Benjamin Marzinski
2020-08-04 19:35 ` Martin Wilck
2020-08-10 18:05 ` Benjamin Marzinski
2020-08-10 18:59 ` Martin Wilck
2020-07-09 10:15 ` [PATCH 09/35] libmultipath: use bitfields in group_by_match() mwilck
2020-07-09 10:15 ` [PATCH 10/35] libmultipath: util: constify function arguments mwilck
2020-07-09 10:15 ` [PATCH 11/35] multipath-tools tests: add unit tests for strlcat mwilck
2020-07-09 10:15 ` [PATCH 12/35] libmultipath: strlcpy()/strlcat(): use restrict qualifier mwilck
2020-07-16 22:18 ` Benjamin Marzinski
2020-08-04 15:36 ` Martin Wilck
2020-08-04 17:29 ` Benjamin Marzinski
2020-08-04 20:15 ` Martin Wilck
2020-07-09 10:15 ` [PATCH 13/35] libmultipath: constify blacklist code mwilck
2020-07-09 10:15 ` [PATCH 14/35] libmultipath: rlookup_binding(): remove newline in log message mwilck
2020-07-09 10:16 ` [PATCH 15/35] libmultipath: fix missing initializer warning from clang 3.9 mwilck
2020-07-09 10:16 ` [PATCH 16/35] libmultipath: fix gcc -Wstringop-overflow warning mwilck
2020-07-09 10:16 ` [PATCH 17/35] libmultipath: remove uevent listener failback mwilck
2020-07-09 10:16 ` [PATCH 18/35] libmultipath: uevent: use static linkage where possible mwilck
2020-07-09 10:16 ` [PATCH 19/35] libmultipath: uevent: inline trivial functions mwilck
2020-07-09 10:16 ` [PATCH 20/35] libmultipath: decrease log level of "SCSI target" log message mwilck
2020-07-09 10:16 ` [PATCH 21/35] libmultipath: get_udev_uid(): more appropriate error code mwilck
2020-07-09 10:16 ` [PATCH 22/35] libmultipath: get_uid(): improve log message on udev failure mwilck
2020-07-09 10:16 ` [PATCH 23/35] libmultipath: make sysfs_pathinfo() static and use const mwilck
2020-07-09 10:16 ` [PATCH 24/35] libmultipath: pathinfo(): improve a log message mwilck
2020-07-09 10:16 ` [PATCH 25/35] libmultipath: pathinfo(): don't filter emtpy devnode names mwilck
2020-07-09 10:16 ` [PATCH 26/35] libmultipath: io_err_stat_handle_pathfail(): less error conditions mwilck
2020-07-09 10:16 ` [PATCH 27/35] libmultipath: improve libdm logging mwilck
2020-07-09 10:16 ` [PATCH 28/35] libmultipath: snprint_devices(): use udev_enumerate mwilck
2020-07-09 10:16 ` [PATCH 29/35] libmultipath: snprint_devices(): print hidden/foreign status mwilck
2020-07-09 10:16 ` [PATCH 30/35] libmultipath: alloc_path(): initialize pp->initialized mwilck
2020-07-09 10:16 ` [PATCH 31/35] libmultipath: alloc_path_with_pathinfo(): treat devname overflow as error mwilck
2020-07-09 10:16 ` [PATCH 32/35] libmultipath: log table params in addmap() mwilck
2020-07-09 10:16 ` [PATCH 33/35] multipathd: remove set_multipath_wwid() mwilck
2020-07-09 10:16 ` [PATCH 34/35] kpartx: print an error message if removing a partition fails mwilck
2020-07-09 10:16 ` [PATCH 35/35] kpartx: add missing newline mwilck
2020-07-20 21:09 ` [PATCH 00/35] multipath-tools series part I: minor changes Benjamin Marzinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200716211708.GM11089@octiron.msp.redhat.com \
--to=bmarzins@redhat.com \
--cc=dm-devel@redhat.com \
--cc=mwilck@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.