Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
[platform/upstream/multipath-tools.git] / libmultipath / devmapper.c
index cc01486..fb69ee8 100644 (file)
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <libdevmapper.h>
 #include <ctype.h>
-#include <linux/kdev_t.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -78,7 +77,7 @@ dm_libprereq (void)
 {
        char version[64];
        int v[3];
-       int minv[3] = {1, 2, 8};
+       int minv[3] = {1, 2, 38};
 
        dm_get_library_version(version, sizeof(version));
        condlog(3, "libdevmapper version %s", version);
@@ -142,16 +141,18 @@ out:
 }
 
 extern int
-dm_prereq (char * str)
+dm_prereq (void)
 {
        if (dm_libprereq())
                return 1;
-       return dm_drvprereq(str);
+       return dm_drvprereq(TGT_MPATH);
 }
 
-extern int
-dm_simplecmd (int task, const char *name) {
+static int
+dm_simplecmd (int task, const char *name, int no_flush, int need_sync) {
        int r = 0;
+       int udev_wait_flag = (need_sync && (task == DM_DEVICE_RESUME ||
+                                           task == DM_DEVICE_REMOVE));
        struct dm_task *dmt;
 
        if (!(dmt = dm_task_create (task)))
@@ -161,11 +162,14 @@ dm_simplecmd (int task, const char *name) {
                goto out;
 
        dm_task_no_open_count(dmt);
-       dm_task_skip_lockfs(dmt);       /* for DM_DEVICE_RESUME */
+       dm_task_skip_lockfs(dmt);       /* for DM_DEVICE_RESUME */
 #ifdef LIBDM_API_FLUSH
-       dm_task_no_flush(dmt);          /* for DM_DEVICE_SUSPEND/RESUME */
+       if (no_flush)
+               dm_task_no_flush(dmt);          /* for DM_DEVICE_SUSPEND/RESUME */
 #endif
 
+       if (udev_wait_flag && !dm_task_set_cookie(dmt, &conf->cookie, 0))
+               goto out;
        r = dm_task_run (dmt);
 
        out:
@@ -174,8 +178,18 @@ dm_simplecmd (int task, const char *name) {
 }
 
 extern int
-dm_addmap (int task, const char *name, const char *target,
-          const char *params, unsigned long long size, const char *uuid) {
+dm_simplecmd_flush (int task, const char *name, int needsync) {
+       return dm_simplecmd(task, name, 0, needsync);
+}
+
+extern int
+dm_simplecmd_noflush (int task, const char *name) {
+       return dm_simplecmd(task, name, 1, 1);
+}
+
+extern int
+dm_addmap (int task, const char *target, struct multipath *mpp, int use_uuid,
+          int ro) {
        int r = 0;
        struct dm_task *dmt;
        char *prefixed_uuid = NULL;
@@ -183,39 +197,95 @@ dm_addmap (int task, const char *name, const char *target,
        if (!(dmt = dm_task_create (task)))
                return 0;
 
-       if (!dm_task_set_name (dmt, name))
+       if (!dm_task_set_name (dmt, mpp->alias))
                goto addout;
 
-       if (!dm_task_add_target (dmt, 0, size, target, params))
+       if (!dm_task_add_target (dmt, 0, mpp->size, target, mpp->params))
                goto addout;
 
-       if (uuid){
-               prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
+       if (ro)
+               dm_task_set_ro(dmt);
+
+       if (use_uuid && mpp->wwid){
+               prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(mpp->wwid) + 1);
                if (!prefixed_uuid) {
                        condlog(0, "cannot create prefixed uuid : %s\n",
                                strerror(errno));
                        goto addout;
                }
-               sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
+               sprintf(prefixed_uuid, UUID_PREFIX "%s", mpp->wwid);
                if (!dm_task_set_uuid(dmt, prefixed_uuid))
                        goto freeout;
        }
 
+       if (mpp->attribute_flags & (1 << ATTR_MODE) &&
+           !dm_task_set_mode(dmt, mpp->mode))
+               goto freeout;
+       if (mpp->attribute_flags & (1 << ATTR_UID) &&
+           !dm_task_set_uid(dmt, mpp->uid))
+               goto freeout;
+       if (mpp->attribute_flags & (1 << ATTR_GID) &&
+           !dm_task_set_gid(dmt, mpp->gid))
+               goto freeout;
+
        dm_task_no_open_count(dmt);
 
+       if (task == DM_DEVICE_CREATE &&
+           !dm_task_set_cookie(dmt, &conf->cookie, 0))
+               goto freeout;
        r = dm_task_run (dmt);
 
        freeout:
        if (prefixed_uuid)
-               free(prefixed_uuid);
+               FREE(prefixed_uuid);
 
        addout:
        dm_task_destroy (dmt);
+
        return r;
 }
 
+static int
+_dm_addmap_create (struct multipath *mpp, int ro) {
+       int r;
+       r = dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, 1, ro);
+       /*
+        * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
+        * Failing the second part leaves an empty map. Clean it up.
+        */
+       if (!r && dm_map_present(mpp->alias)) {
+               condlog(3, "%s: failed to load map (a path might be in use)",
+                       mpp->alias);
+               dm_flush_map_nosync(mpp->alias);
+       }
+       return r;
+}
+
+#define ADDMAP_RW 0
+#define ADDMAP_RO 1
+
+extern int
+dm_addmap_create (struct multipath *mpp) {
+       return _dm_addmap_create(mpp, ADDMAP_RW);
+}
+
 extern int
-dm_map_present (char * str)
+dm_addmap_create_ro (struct multipath *mpp) {
+       return _dm_addmap_create(mpp, ADDMAP_RO);
+}
+
+extern int
+dm_addmap_reload (struct multipath *mpp) {
+       return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, 0, ADDMAP_RW);
+}
+
+extern int
+dm_addmap_reload_ro (struct multipath *mpp) {
+       return dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, 0, ADDMAP_RO);
+}
+
+extern int
+dm_map_present (const char * str)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -288,11 +358,11 @@ dm_get_uuid(char *name, char *uuid)
        if (!dmt)
                return 1;
 
-        if (!dm_task_set_name (dmt, name))
-                goto uuidout;
+       if (!dm_task_set_name (dmt, name))
+               goto uuidout;
 
        if (!dm_task_run(dmt))
-                goto uuidout;
+               goto uuidout;
 
        uuidtmp = dm_task_get_uuid(dmt);
        if (uuidtmp) {
@@ -352,7 +422,7 @@ out:
  *   -1 : empty map
  */
 extern int
-dm_type(char * name, char * type)
+dm_type(const char * name, char * type)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -387,7 +457,7 @@ out:
 }
 
 static int
-dm_dev_t (char * mapname, char * dev_t, int len)
+dm_dev_t (const char * mapname, char * dev_t, int len)
 {
        int r = 1;
        struct dm_task *dmt;
@@ -414,9 +484,9 @@ out:
        dm_task_destroy(dmt);
        return r;
 }
-       
+
 int
-dm_get_opencount (char * mapname)
+dm_get_opencount (const char * mapname)
 {
        int r = -1;
        struct dm_task *dmt;
@@ -439,7 +509,7 @@ out:
        dm_task_destroy(dmt);
        return r;
 }
-       
+
 int
 dm_get_minor (char * mapname)
 {
@@ -464,27 +534,27 @@ out:
        dm_task_destroy(dmt);
        return r;
 }
-       
+
 extern int
-dm_flush_map (char * mapname, char * type)
+_dm_flush_map (const char * mapname, int need_sync)
 {
        int r;
 
        if (!dm_map_present(mapname))
                return 0;
 
-       if (dm_type(mapname, type) <= 0)
-               return 1;
+       if (dm_type(mapname, TGT_MPATH) <= 0)
+               return 0; /* nothing to do */
 
-       if (dm_remove_partmaps(mapname))
+       if (dm_remove_partmaps(mapname, need_sync))
                return 1;
 
        if (dm_get_opencount(mapname)) {
                condlog(2, "%s: map in use", mapname);
                return 1;
-       }       
+       }
 
-       r = dm_simplecmd(DM_DEVICE_REMOVE, mapname);
+       r = dm_simplecmd_flush(DM_DEVICE_REMOVE, mapname, need_sync);
 
        if (r) {
                condlog(4, "multipath map %s removed", mapname);
@@ -494,7 +564,7 @@ dm_flush_map (char * mapname, char * type)
 }
 
 extern int
-dm_flush_maps (char * type)
+dm_flush_maps (void)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -516,7 +586,7 @@ dm_flush_maps (char * type)
                goto out;
 
        do {
-               r += dm_flush_map(names->name, type);
+               r |= dm_flush_map(names->name);
                next = names->next;
                names = (void *) names + next;
        } while (next);
@@ -633,7 +703,7 @@ dm_disablegroup(char * mapname, int index)
 }
 
 int
-dm_get_maps (vector mp, char * type)
+dm_get_maps (vector mp)
 {
        struct multipath * mpp;
        int r = 1;
@@ -642,7 +712,7 @@ dm_get_maps (vector mp, char * type)
        struct dm_names *names;
        unsigned next = 0;
 
-       if (!type || !mp)
+       if (!mp)
                return 1;
 
        if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
@@ -662,7 +732,7 @@ dm_get_maps (vector mp, char * type)
        }
 
        do {
-               info = dm_type(names->name, type);
+               info = dm_type(names->name, TGT_MPATH);
 
                if (info <= 0)
                        goto next;
@@ -694,8 +764,8 @@ dm_get_maps (vector mp, char * type)
                vector_set_slot(mp, mpp);
                mpp = NULL;
 next:
-                next = names->next;
-                names = (void *) names + next;
+               next = names->next;
+               names = (void *) names + next;
        } while (next);
 
        r = 0;
@@ -707,33 +777,49 @@ out:
        return r;
 }
 
-extern int
-dm_get_name(char *uuid, char *type, char *name)
+extern char *
+dm_get_name(char *uuid)
 {
-       vector vec;
-       struct multipath *mpp;
-       int i;
-
-       vec = vector_alloc();
+       struct dm_task *dmt;
+       struct dm_info info;
+       char *prefixed_uuid, *name = NULL;
+       const char *nametmp;
 
-       if (!vec)
-               return 0;
+       dmt = dm_task_create(DM_DEVICE_INFO);
+       if (!dmt)
+               return NULL;
 
-       if (dm_get_maps(vec, type)) {
-               vector_free(vec);
-               return 0;
+       prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
+       if (!prefixed_uuid) {
+               condlog(0, "cannot create prefixed uuid : %s\n",
+                       strerror(errno));
+               goto freeout;
        }
+       sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid);
+       if (!dm_task_set_uuid(dmt, prefixed_uuid))
+               goto freeout;
 
-       vector_foreach_slot(vec, mpp, i) {
-               if (!strcmp(uuid, mpp->wwid)) {
-                       vector_free(vec);
-                       strcpy(name, mpp->alias);
-                       return 1;
-               }
+       if (!dm_task_run(dmt))
+               goto freeout;
+
+       if (!dm_task_get_info(dmt, &info) || !info.exists)
+               goto freeout;
+
+       nametmp = dm_task_get_name(dmt);
+       if (nametmp && strlen(nametmp)) {
+               name = MALLOC(strlen(nametmp) + 1);
+               if (name)
+                       strcpy(name, nametmp);
+       } else {
+               condlog(2, "%s: no device-mapper name found", uuid);
        }
 
-       vector_free(vec);
-       return 0;
+freeout:
+       if (prefixed_uuid)
+               FREE(prefixed_uuid);
+       dm_task_destroy(dmt);
+
+       return name;
 }
 
 int
@@ -818,7 +904,7 @@ bad:
 }
 
 int
-dm_remove_partmaps (char * mapname)
+dm_remove_partmaps (const char * mapname, int need_sync)
 {
        struct dm_task *dmt;
        struct dm_names *names;
@@ -852,7 +938,7 @@ dm_remove_partmaps (char * mapname)
                    /*
                     * if devmap target is "linear"
                     */
-                   (dm_type(names->name, "linear") > 0) &&
+                   (dm_type(names->name, TGT_PART) > 0) &&
 
                    /*
                     * and the multipath mapname and the part mapname start
@@ -875,13 +961,13 @@ dm_remove_partmaps (char * mapname)
                     */
                    strstr(params, dev_t)
                   ) {
-                               /*
+                               /*
                                 * then it's a kpartx generated partition.
                                 * remove it.
                                 */
                                condlog(4, "partition map %s removed",
                                        names->name);
-                               dm_simplecmd(DM_DEVICE_REMOVE, names->name);
+                               dm_simplecmd_flush(DM_DEVICE_REMOVE, names->name, need_sync);
                   }
 
                next = names->next;
@@ -905,7 +991,7 @@ dm_get_info (char * mapname, struct dm_info ** dmi)
 {
        int r = 1;
        struct dm_task *dmt = NULL;
-       
+
        if (!mapname)
                return 1;
 
@@ -931,8 +1017,11 @@ dm_get_info (char * mapname, struct dm_info ** dmi)
 
        r = 0;
 out:
-       if (r)
+       if (r) {
                memset(*dmi, 0, sizeof(struct dm_info));
+               FREE(*dmi);
+               *dmi = NULL;
+       }
 
        if (dmt)
                dm_task_destroy(dmt);
@@ -975,7 +1064,7 @@ dm_rename_partmaps (char * old, char * new)
                    /*
                     * if devmap target is "linear"
                     */
-                   (dm_type(names->name, "linear") > 0) &&
+                   (dm_type(names->name, TGT_PART) > 0) &&
 
                    /*
                     * and the multipath mapname and the part mapname start
@@ -993,7 +1082,7 @@ dm_rename_partmaps (char * old, char * new)
                     */
                    strstr(buff, dev_t)
                   ) {
-                               /*
+                               /*
                                 * then it's a kpartx generated partition.
                                 * Rename it.
                                 */
@@ -1031,9 +1120,11 @@ dm_rename (char * old, char * new)
 
        if (!dm_task_set_newname(dmt, new))
                goto out;
-       
+
        dm_task_no_open_count(dmt);
 
+       if (!dm_task_set_cookie(dmt, &conf->cookie, 0))
+               goto out;
        if (!dm_task_run(dmt))
                goto out;