multipath: check if a device belongs to multipath
authorBenjamin Marzinski <bmarzins@redhat.com>
Fri, 27 Jul 2012 20:55:24 +0000 (15:55 -0500)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Tue, 21 Aug 2012 17:39:26 +0000 (19:39 +0200)
This patch adds a new multipath option "-c", which checks if a device
belongs to multipath.  This can be done during the add uevent for the
device, before the multipath device has even been created.  This allows
udev to be able to handle multipath path devices differently.  To do
this multipath now keeps track of the wwids of all previously created
multipath devices in /etc/multipath/wwids. The file creating and
editting code from alias.[ch] has been split out into file.[ch]. When a
device is checked to see if it's a multipath path, it's wwid is
compared against the ones in the wwids file. Also, since the
uid_attribute may not have been added to the udev database entry for
the device if this is called in a udev rule, when using the "-c" option,
get_uid will now also check the process' envirionment variables for the
uid_attribute.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
libmultipath/Makefile
libmultipath/alias.c
libmultipath/alias.h
libmultipath/configure.c
libmultipath/defaults.h
libmultipath/discovery.c
libmultipath/file.c [new file with mode: 0644]
libmultipath/file.h [new file with mode: 0644]
libmultipath/wwids.c [new file with mode: 0644]
libmultipath/wwids.h [new file with mode: 0644]
multipath/main.c

index b0513dffba708444b8ed471739ca1d1e9362a88c..039560297c7b8683ea58c68c213ed2d767a06a55 100644 (file)
@@ -15,7 +15,7 @@ OBJS = memory.o parser.o vector.o devmapper.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
        log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
-       lock.o waiter.o
+       lock.o waiter.o file.o wwids.o
 
 LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h)
 
index a6a06ad185be172c39bd3ab49d8625254d970b3c..e1f30736af89545fe826b32babe794c297973f12 100644 (file)
@@ -3,19 +3,16 @@
  * Copyright (c) 2005 Benjamin Marzinski, Redhat
  */
 #include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
 #include <limits.h>
 #include <stdio.h>
-#include <signal.h>
 
 #include "debug.h"
 #include "uxsock.h"
 #include "alias.h"
+#include "file.h"
 
 
 /*
  * See the file COPYING included with this distribution for more details.
  */
 
-static int
-ensure_directories_exist(char *str, mode_t dir_mode)
-{
-       char *pathname;
-       char *end;
-       int err;
-
-       pathname = strdup(str);
-       if (!pathname){
-               condlog(0, "Cannot copy bindings file pathname : %s",
-                       strerror(errno));
-               return -1;
-       }
-       end = pathname;
-       /* skip leading slashes */
-       while (end && *end && (*end == '/'))
-               end++;
-
-       while ((end = strchr(end, '/'))) {
-               /* if there is another slash, make the dir. */
-               *end = '\0';
-               err = mkdir(pathname, dir_mode);
-               if (err && errno != EEXIST) {
-                       condlog(0, "Cannot make directory [%s] : %s",
-                               pathname, strerror(errno));
-                       free(pathname);
-                       return -1;
-               }
-               if (!err)
-                       condlog(3, "Created dir [%s]", pathname);
-               *end = '/';
-               end++;
-       }
-       free(pathname);
-       return 0;
-}
-
-static void
-sigalrm(int sig)
-{
-       /* do nothing */
-}
-
-static int
-lock_bindings_file(int fd)
-{
-       struct sigaction act, oldact;
-       sigset_t set, oldset;
-       struct flock lock;
-       int err;
-
-       memset(&lock, 0, sizeof(lock));
-       lock.l_type = F_WRLCK;
-       lock.l_whence = SEEK_SET;
-
-       act.sa_handler = sigalrm;
-       sigemptyset(&act.sa_mask);
-       act.sa_flags = 0;
-       sigemptyset(&set);
-       sigaddset(&set, SIGALRM);
-
-       sigaction(SIGALRM, &act, &oldact);
-       sigprocmask(SIG_UNBLOCK, &set, &oldset);
-
-       alarm(BINDINGS_FILE_TIMEOUT);
-       err = fcntl(fd, F_SETLKW, &lock);
-       alarm(0);
-
-       if (err) {
-               if (errno != EINTR)
-                       condlog(0, "Cannot lock bindings file : %s",
-                                       strerror(errno));
-               else
-                       condlog(0, "Bindings file is locked. Giving up.");
-       }
-
-       sigprocmask(SIG_SETMASK, &oldset, NULL);
-       sigaction(SIGALRM, &oldact, NULL);
-       return err;
-
-}
-
-
-static int
-open_bindings_file(char *file, int *can_write)
-{
-       int fd;
-       struct stat s;
-
-       if (ensure_directories_exist(file, 0700))
-               return -1;
-       *can_write = 1;
-       fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
-       if (fd < 0) {
-               if (errno == EROFS) {
-                       *can_write = 0;
-                       condlog(3, "Cannot open bindings file [%s] read/write. "
-                               " trying readonly", file);
-                       fd = open(file, O_RDONLY);
-                       if (fd < 0) {
-                               condlog(0, "Cannot open bindings file [%s] "
-                                       "readonly : %s", file, strerror(errno));
-                               return -1;
-                       }
-               }
-               else {
-                       condlog(0, "Cannot open bindings file [%s] : %s", file,
-                               strerror(errno));
-                       return -1;
-               }
-       }
-       if (*can_write && lock_bindings_file(fd) < 0)
-               goto fail;
-
-       memset(&s, 0, sizeof(s));
-       if (fstat(fd, &s) < 0){
-               condlog(0, "Cannot stat bindings file : %s", strerror(errno));
-               goto fail;
-       }
-       if (s.st_size == 0) {
-               if (*can_write == 0)
-                       goto fail;
-               /* If bindings file is empty, write the header */
-               size_t len = strlen(BINDINGS_FILE_HEADER);
-               if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) {
-                       condlog(0,
-                               "Cannot write header to bindings file : %s",
-                               strerror(errno));
-                       /* cleanup partially written header */
-                       if (ftruncate(fd, 0))
-                               condlog(0, "Cannot truncate the header : %s",
-                                       strerror(errno));
-                       goto fail;
-               }
-               fsync(fd);
-               condlog(3, "Initialized new bindings file [%s]", file);
-       }
-
-       return fd;
-
-fail:
-       close(fd);
-       return -1;
-}
 
 static int
 format_devname(char *name, int id, int len, char *prefix)
@@ -370,7 +223,7 @@ get_user_friendly_alias(char *wwid, char *file, char *prefix,
                return NULL;
        }
 
-       fd = open_bindings_file(file, &can_write);
+       fd = open_file(file, &can_write, BINDINGS_FILE_HEADER);
        if (fd < 0)
                return NULL;
 
@@ -414,7 +267,7 @@ get_user_friendly_wwid(char *alias, char *file)
                return NULL;
        }
 
-       fd = open_bindings_file(file, &unused);
+       fd = open_file(file, &unused, BINDINGS_FILE_HEADER);
        if (fd < 0)
                return NULL;
 
index c489a86b44089244ce81211c104fa4ae2b3e6736..c625090f537b0ac2f418d0e64f515ebc75e27520 100644 (file)
@@ -1,4 +1,3 @@
-#define BINDINGS_FILE_TIMEOUT 30
 #define BINDINGS_FILE_HEADER \
 "# Multipath bindings, Version : 1.0\n" \
 "# NOTE: this file is automatically maintained by the multipath program.\n" \
index 99772967af3553510f40f1a70b063fb1e04a36c8..1bb45a378033ae2f60d342cf6a21633cf6a1a187 100644 (file)
@@ -37,6 +37,7 @@
 #include "prio.h"
 #include "util.h"
 #include "uxsock.h"
+#include "wwids.h"
 
 extern int
 setup_map (struct multipath * mpp, char * params, int params_size)
@@ -415,6 +416,8 @@ domap (struct multipath * mpp, char * params)
                 * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
                 * succeeded
                 */
+               if (mpp->action == ACT_CREATE)
+                       remember_wwid(mpp->wwid);
                if (!conf->daemon) {
                        /* multipath client mode */
                        dm_switchgroup(mpp->alias, mpp->bestpg);
index 7697195fea1f189d37429b26cf43d53070c5da99..74b236f1d042643602de8456d94f5c869850ca42 100644 (file)
@@ -24,5 +24,6 @@
 #define DEFAULT_SOCKET         "/var/run/multipathd.sock"
 #define DEFAULT_CONFIGFILE     "/etc/multipath.conf"
 #define DEFAULT_BINDINGS_FILE  "/etc/multipath/bindings"
+#define DEFAULT_WWIDS_FILE     "/etc/multipath/wwids"
 
 char * set_default (char * str);
index abc686f6eb90877f0c7471e9750e6124d53b0ab0..3315b5effa8be1e86e9782492a5c137291f14671 100644 (file)
@@ -810,6 +810,8 @@ get_uid (struct path * pp)
 
        memset(pp->wwid, 0, WWID_SIZE);
        value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
+       if ((!value || strlen(value) == 0) && conf->dry_run == 2)
+               value = getenv(pp->uid_attribute);
        if (value && strlen(value)) {
                size_t len = WWID_SIZE;
 
diff --git a/libmultipath/file.c b/libmultipath/file.c
new file mode 100644 (file)
index 0000000..5ee46dc
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ * Copyright (c) 2005 Benjamin Marzinski, Redhat
+ */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include "file.h"
+#include "debug.h"
+#include "uxsock.h"
+
+
+/*
+ * significant parts of this file were taken from iscsi-bindings.c of the
+ * linux-iscsi project.
+ * Copyright (C) 2002 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * See the file COPYING included with this distribution for more details.
+ */
+
+static int
+ensure_directories_exist(char *str, mode_t dir_mode)
+{
+       char *pathname;
+       char *end;
+       int err;
+
+       pathname = strdup(str);
+       if (!pathname){
+               condlog(0, "Cannot copy file pathname %s : %s",
+                       str, strerror(errno));
+               return -1;
+       }
+       end = pathname;
+       /* skip leading slashes */
+       while (end && *end && (*end == '/'))
+               end++;
+
+       while ((end = strchr(end, '/'))) {
+               /* if there is another slash, make the dir. */
+               *end = '\0';
+               err = mkdir(pathname, dir_mode);
+               if (err && errno != EEXIST) {
+                       condlog(0, "Cannot make directory [%s] : %s",
+                               pathname, strerror(errno));
+                       free(pathname);
+                       return -1;
+               }
+               if (!err)
+                       condlog(3, "Created dir [%s]", pathname);
+               *end = '/';
+               end++;
+       }
+       free(pathname);
+       return 0;
+}
+
+static void
+sigalrm(int sig)
+{
+       /* do nothing */
+}
+
+static int
+lock_file(int fd, char *file_name)
+{
+       struct sigaction act, oldact;
+       sigset_t set, oldset;
+       struct flock lock;
+       int err;
+
+       memset(&lock, 0, sizeof(lock));
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+
+       act.sa_handler = sigalrm;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = 0;
+       sigemptyset(&set);
+       sigaddset(&set, SIGALRM);
+
+       sigaction(SIGALRM, &act, &oldact);
+       sigprocmask(SIG_UNBLOCK, &set, &oldset);
+
+       alarm(FILE_TIMEOUT);
+       err = fcntl(fd, F_SETLKW, &lock);
+       alarm(0);
+
+       if (err) {
+               if (errno != EINTR)
+                       condlog(0, "Cannot lock %s : %s", file_name,
+                               strerror(errno));
+               else
+                       condlog(0, "%s is locked. Giving up.", file_name);
+       }
+
+       sigprocmask(SIG_SETMASK, &oldset, NULL);
+       sigaction(SIGALRM, &oldact, NULL);
+       return err;
+}
+
+int
+open_file(char *file, int *can_write, char *header)
+{
+       int fd;
+       struct stat s;
+
+       if (ensure_directories_exist(file, 0700))
+               return -1;
+       *can_write = 1;
+       fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd < 0) {
+               if (errno == EROFS) {
+                       *can_write = 0;
+                       condlog(3, "Cannot open file [%s] read/write. "
+                               " trying readonly", file);
+                       fd = open(file, O_RDONLY);
+                       if (fd < 0) {
+                               condlog(0, "Cannot open file [%s] "
+                                       "readonly : %s", file, strerror(errno));
+                               return -1;
+                       }
+               }
+               else {
+                       condlog(0, "Cannot open file [%s] : %s", file,
+                               strerror(errno));
+                       return -1;
+               }
+       }
+       if (*can_write && lock_file(fd, file) < 0)
+               goto fail;
+
+       memset(&s, 0, sizeof(s));
+       if (fstat(fd, &s) < 0){
+               condlog(0, "Cannot stat file %s : %s", file, strerror(errno));
+               goto fail;
+       }
+       if (s.st_size == 0) {
+               if (*can_write == 0)
+                       goto fail;
+               /* If file is empty, write the header */
+               size_t len = strlen(header);
+               if (write_all(fd, header, len) != len) {
+                       condlog(0,
+                               "Cannot write header to file %s : %s", file,
+                               strerror(errno));
+                       /* cleanup partially written header */
+                       if (ftruncate(fd, 0))
+                               condlog(0, "Cannot truncate header : %s",
+                                       strerror(errno));
+                       goto fail;
+               }
+               fsync(fd);
+               condlog(3, "Initialized new file [%s]", file);
+       }
+
+       return fd;
+
+fail:
+       close(fd);
+       return -1;
+}
diff --git a/libmultipath/file.h b/libmultipath/file.h
new file mode 100644 (file)
index 0000000..4f96dbf
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
+ */
+
+#ifndef _FILE_H
+#define _FILE_H
+
+#define FILE_TIMEOUT 30
+int open_file(char *file, int *can_write, char *header);
+
+#endif /* _FILE_H */
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
new file mode 100644 (file)
index 0000000..ba1f5a5
--- /dev/null
@@ -0,0 +1,139 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "checkers.h"
+#include "vector.h"
+#include "structs.h"
+#include "debug.h"
+#include "uxsock.h"
+#include "file.h"
+#include "wwids.h"
+#include "defaults.h"
+
+/*
+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
+ */
+
+static int
+lookup_wwid(FILE *f, char *wwid) {
+       int c;
+       char buf[LINE_MAX];
+       int count;
+
+       while ((c = fgetc(f)) != EOF){
+               if (c != '/') {
+                       if (fgets(buf, LINE_MAX, f) == NULL)
+                               return 0;
+                       else
+                               continue;
+               }
+               count = 0;
+               while ((c = fgetc(f)) != '/') {
+                       if (c == EOF)
+                               return 0;
+                       if (count >= WWID_SIZE - 1)
+                               goto next;
+                       if (wwid[count] == '\0')
+                               goto next;
+                       if (c != wwid[count++])
+                               goto next;
+               }
+               if (wwid[count] == '\0')
+                       return 1;
+next:
+               if (fgets(buf, LINE_MAX, f) == NULL)
+                       return 0;
+       }
+       return 0;
+}
+
+static int
+write_out_wwid(int fd, char *wwid) {
+       int ret;
+       off_t offset;
+       char buf[WWID_SIZE + 3];
+
+       ret = snprintf(buf, WWID_SIZE + 3, "/%s/\n", wwid);
+       if (ret >= (WWID_SIZE + 3) || ret < 0){
+               condlog(0, "can't format wwid for writing (%d) : %s",
+                       ret, strerror(errno));
+               return -1;
+       }
+       offset = lseek(fd, 0, SEEK_END);
+       if (offset < 0) {
+               condlog(0, "can't seek to the end of wwids file : %s",
+                       strerror(errno));
+               return -1;
+       }
+       if (write_all(fd, buf, strlen(buf)) != strlen(buf)) {
+               condlog(0, "cannot write wwid to wwids file : %s",
+                       strerror(errno));
+               if (ftruncate(fd, offset))
+                       condlog(0, "cannot truncate failed wwid write : %s",
+                               strerror(errno));
+               return -1;
+       }
+       return 1;
+}
+
+int
+check_wwids_file(char *wwid, int write_wwid)
+{
+       int fd, can_write, found, ret;
+       FILE *f;
+       fd = open_file(DEFAULT_WWIDS_FILE, &can_write, WWIDS_FILE_HEADER);
+       if (fd < 0)
+               return -1;
+
+       f = fdopen(fd, "r");
+       if (!f) {
+               condlog(0,"can't fdopen wwids file : %s", strerror(errno));
+               close(fd);
+               return -1;
+       }
+       found = lookup_wwid(f, wwid);
+       if (found) {
+               ret = 0;
+               goto out;
+       }
+       if (!write_wwid) {
+               ret = -1;
+               goto out;
+       }
+       if (!can_write) {
+               condlog(0, "wwids file is read-only. Can't write wwid");
+               ret = -1;
+               goto out;
+       }
+
+       if (fflush(f) != 0) {
+               condlog(0, "cannot fflush wwids file stream : %s",
+                       strerror(errno));
+               ret = -1;
+               goto out;
+       }
+
+       ret = write_out_wwid(fd, wwid);
+out:
+       fclose(f);
+       return ret;
+}
+
+int
+remember_wwid(char *wwid)
+{
+       int ret = check_wwids_file(wwid, 1);
+       if (ret < 0){
+               condlog(3, "failed writing wwid %s to wwids file", wwid);
+               return -1;
+       }
+       if (ret == 1)
+               condlog(3, "wrote wwid %s to wwids file", wwid);
+       else
+               condlog(4, "wwid %s already in wwids file", wwid);
+       return 0;
+}
diff --git a/libmultipath/wwids.h b/libmultipath/wwids.h
new file mode 100644 (file)
index 0000000..1678f9d
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2010 Benjamin Marzinski, Redhat
+ */
+
+#ifndef _WWIDS_H
+#define _WWIDS_H
+
+#define WWIDS_FILE_HEADER \
+"# Multipath wwids, Version : 1.0\n" \
+"# NOTE: This file is automatically maintained by multipath and multipathd.\n" \
+"# You should not need to edit this file in normal circumstances.\n" \
+"#\n" \
+"# Valid WWIDs:\n"
+
+int remember_wwid(char *wwid);
+int check_wwids_file(char *wwid, int write_wwid);
+
+#endif /* _WWIDS_H */
index 883ef5922d4c39a5e62e5177f460c4a775d29ecc..92e852b652396c4ac15dd30ad1e479fedfd12837 100644 (file)
@@ -53,6 +53,7 @@
 #include <errno.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <wwids.h>
 #include "dev_t.h"
 
 int logsink;
@@ -82,7 +83,7 @@ usage (char * progname)
 {
        fprintf (stderr, VERSION_STRING);
        fprintf (stderr, "Usage:\n");
-       fprintf (stderr, "  %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
+       fprintf (stderr, "  %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
        fprintf (stderr, "  %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
        fprintf (stderr, "  %s -F [-v lvl]\n", progname);
        fprintf (stderr, "  %s -t\n", progname);
@@ -95,6 +96,7 @@ usage (char * progname)
                "  -ll     show multipath topology (maximum info)\n" \
                "  -f      flush a multipath device map\n" \
                "  -F      flush all multipath device maps\n" \
+               "  -c      check if a device should be a path in a multipath device\n" \
                "  -q      allow queue_if_no_path when multipathd is not running\n"\
                "  -d      dry run, do not create or update devmaps\n" \
                "  -t      dump internal hardware table\n" \
@@ -209,6 +211,7 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
 
                if (!conf->dry_run)
                        reinstate_paths(mpp);
+               remember_wwid(mpp->wwid);
        }
        return 0;
 }
@@ -259,9 +262,13 @@ configure (void)
         * if we have a blacklisted device parameter, exit early
         */
        if (dev &&
-           (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0))
-                       goto out;
-
+           (filter_devnode(conf->blist_devnode,
+                           conf->elist_devnode, dev) > 0)) {
+               if (conf->dry_run == 2)
+                       printf("%s is not a valid multipath device path\n",
+                              conf->dev);
+               goto out;
+       }
        /*
         * scope limiting must be translated into a wwid
         * failing the translation is fatal (by policy)
@@ -277,6 +284,15 @@ configure (void)
                if (filter_wwid(conf->blist_wwid, conf->elist_wwid,
                                refwwid) > 0)
                        goto out;
+               if (conf->dry_run == 2) {
+                       if (check_wwids_file(refwwid, 0) == 0){
+                               printf("%s is a valid multipath device path\n", conf->dev);
+                               r = 0;
+                       }
+                       else
+                               printf("%s is not a valid multipath device path\n", conf->dev);
+                       goto out;
+               }
        }
 
        /*
@@ -422,7 +438,7 @@ main (int argc, char *argv[])
        if (load_config(DEFAULT_CONFIGFILE))
                exit(1);
 
-       while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:Brtq")) != EOF ) {
+       while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) {
                switch(arg) {
                case 1: printf("optarg : %s\n",optarg);
                        break;
@@ -444,8 +460,12 @@ main (int argc, char *argv[])
                case 'q':
                        conf->allow_queueing = 1;
                        break;
+               case 'c':
+                       conf->dry_run = 2;
+                       break;
                case 'd':
-                       conf->dry_run = 1;
+                       if (!conf->dry_run)
+                               conf->dry_run = 1;
                        break;
                case 'f':
                        conf->remove = FLUSH_ONE;
@@ -529,6 +549,11 @@ main (int argc, char *argv[])
        }
        dm_init();
 
+       if (conf->dry_run == 2 &&
+           (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
+               condlog(0, "the -c option requires a path to check");
+               goto out;
+       }
        if (conf->remove == FLUSH_ONE) {
                if (conf->dev_type == DEV_DEVMAP)
                        r = dm_flush_map(conf->dev);