LCOV - code coverage report
Current view: directory - libdm - libdm-deptree.c (source / functions) Found Hit Coverage
Test: unnamed Lines: 1093 0 0.0 %
Date: 2010-04-13 Functions: 75 0 0.0 %

       1                 : /*
       2                 :  * Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
       3                 :  *
       4                 :  * This file is part of the device-mapper userspace tools.
       5                 :  *
       6                 :  * This copyrighted material is made available to anyone wishing to use,
       7                 :  * modify, copy, or redistribute it subject to the terms and conditions
       8                 :  * of the GNU Lesser General Public License v.2.1.
       9                 :  *
      10                 :  * You should have received a copy of the GNU Lesser General Public License
      11                 :  * along with this program; if not, write to the Free Software Foundation,
      12                 :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      13                 :  */
      14                 : 
      15                 : #include "dmlib.h"
      16                 : #include "libdm-targets.h"
      17                 : #include "libdm-common.h"
      18                 : #include "kdev_t.h"
      19                 : #include "dm-ioctl.h"
      20                 : 
      21                 : #include <stdarg.h>
      22                 : #include <sys/param.h>
      23                 : #include <sys/utsname.h>
      24                 : 
      25                 : #define MAX_TARGET_PARAMSIZE 500000
      26                 : 
      27                 : /* FIXME Fix interface so this is used only by LVM */
      28                 : #define UUID_PREFIX "LVM-"
      29                 : 
      30                 : /* Supported segment types */
      31                 : enum {
      32                 :         SEG_CRYPT,
      33                 :         SEG_ERROR,
      34                 :         SEG_LINEAR,
      35                 :         SEG_MIRRORED,
      36                 :         SEG_REPLICATOR,
      37                 :         SEG_REPLICATOR_DEV,
      38                 :         SEG_SNAPSHOT,
      39                 :         SEG_SNAPSHOT_ORIGIN,
      40                 :         SEG_SNAPSHOT_MERGE,
      41                 :         SEG_STRIPED,
      42                 :         SEG_ZERO,
      43                 : };
      44                 : 
      45                 : /* FIXME Add crypt and multipath support */
      46                 : 
      47                 : struct {
      48                 :         unsigned type;
      49                 :         const char *target;
      50                 : } dm_segtypes[] = {
      51                 :         { SEG_CRYPT, "crypt" },
      52                 :         { SEG_ERROR, "error" },
      53                 :         { SEG_LINEAR, "linear" },
      54                 :         { SEG_MIRRORED, "mirror" },
      55                 :         { SEG_REPLICATOR, "replicator" },
      56                 :         { SEG_REPLICATOR_DEV, "replicator-dev" },
      57                 :         { SEG_SNAPSHOT, "snapshot" },
      58                 :         { SEG_SNAPSHOT_ORIGIN, "snapshot-origin" },
      59                 :         { SEG_SNAPSHOT_MERGE, "snapshot-merge" },
      60                 :         { SEG_STRIPED, "striped" },
      61                 :         { SEG_ZERO, "zero"},
      62                 : };
      63                 : 
      64                 : /* Some segment types have a list of areas of other devices attached */
      65                 : struct seg_area {
      66                 :         struct dm_list list;
      67                 : 
      68                 :         struct dm_tree_node *dev_node;
      69                 : 
      70                 :         uint64_t offset;
      71                 : 
      72                 :         unsigned rsite_index;           /* Replicator site index */
      73                 :         struct dm_tree_node *slog;      /* Replicator sync log node */
      74                 :         uint64_t region_size;           /* Replicator sync log size */
      75                 :         uint32_t flags;                 /* Replicator sync log flags */
      76                 : };
      77                 : 
      78                 : /* Replicator-log has a list of sites */
      79                 : /* CHECKME: maybe move to seg_area too? */
      80                 : struct replicator_site {
      81                 :         struct dm_list list;
      82                 : 
      83                 :         unsigned rsite_index;
      84                 :         dm_replicator_mode_t mode;
      85                 :         uint32_t async_timeout;
      86                 :         uint32_t fall_behind_ios;
      87                 :         uint64_t fall_behind_data;
      88                 : };
      89                 : 
      90                 : /* Per-segment properties */
      91                 : struct load_segment {
      92                 :         struct dm_list list;
      93                 : 
      94                 :         unsigned type;
      95                 : 
      96                 :         uint64_t size;
      97                 : 
      98                 :         unsigned area_count;            /* Linear + Striped + Mirrored + Crypt + Replicator */
      99                 :         struct dm_list areas;           /* Linear + Striped + Mirrored + Crypt + Replicator */
     100                 : 
     101                 :         uint32_t stripe_size;           /* Striped */
     102                 : 
     103                 :         int persistent;                 /* Snapshot */
     104                 :         uint32_t chunk_size;            /* Snapshot */
     105                 :         struct dm_tree_node *cow;       /* Snapshot */
     106                 :         struct dm_tree_node *origin;    /* Snapshot + Snapshot origin */
     107                 :         struct dm_tree_node *merge;     /* Snapshot */
     108                 : 
     109                 :         struct dm_tree_node *log;       /* Mirror + Replicator */
     110                 :         uint32_t region_size;           /* Mirror */
     111                 :         unsigned clustered;             /* Mirror */
     112                 :         unsigned mirror_area_count;     /* Mirror */
     113                 :         uint32_t flags;                 /* Mirror log */
     114                 :         char *uuid;                     /* Clustered mirror log */
     115                 : 
     116                 :         const char *cipher;             /* Crypt */
     117                 :         const char *chainmode;          /* Crypt */
     118                 :         const char *iv;                 /* Crypt */
     119                 :         uint64_t iv_offset;             /* Crypt */
     120                 :         const char *key;                /* Crypt */
     121                 : 
     122                 :         const char *rlog_type;          /* Replicator */
     123                 :         struct dm_list rsites;          /* Replicator */
     124                 :         unsigned rsite_count;           /* Replicator */
     125                 :         unsigned rdevice_count;         /* Replicator */
     126                 :         struct dm_tree_node *replicator;/* Replicator-dev */
     127                 :         uint64_t rdevice_index;         /* Replicator-dev */
     128                 : };
     129                 : 
     130                 : /* Per-device properties */
     131                 : struct load_properties {
     132                 :         int read_only;
     133                 :         uint32_t major;
     134                 :         uint32_t minor;
     135                 : 
     136                 :         uint32_t read_ahead;
     137                 :         uint32_t read_ahead_flags;
     138                 : 
     139                 :         unsigned segment_count;
     140                 :         unsigned size_changed;
     141                 :         struct dm_list segs;
     142                 : 
     143                 :         const char *new_name;
     144                 : };
     145                 : 
     146                 : /* Two of these used to join two nodes with uses and used_by. */
     147                 : struct dm_tree_link {
     148                 :         struct dm_list list;
     149                 :         struct dm_tree_node *node;
     150                 : };
     151                 : 
     152                 : struct dm_tree_node {
     153                 :         struct dm_tree *dtree;
     154                 : 
     155                 :         const char *name;
     156                 :         const char *uuid;
     157                 :         struct dm_info info;
     158                 : 
     159                 :         struct dm_list uses;            /* Nodes this node uses */
     160                 :         struct dm_list used_by;         /* Nodes that use this node */
     161                 : 
     162                 :         int activation_priority;        /* 0 gets activated first */
     163                 :         int suspend_priority;           /* 1 gets suspend first */
     164                 : 
     165                 :         uint16_t udev_flags;            /* Udev control flags */
     166                 : 
     167                 :         void *context;                  /* External supplied context */
     168                 : 
     169                 :         struct load_properties props;   /* For creation/table (re)load */
     170                 : };
     171                 : 
     172                 : struct dm_tree {
     173                 :         struct dm_pool *mem;
     174                 :         struct dm_hash_table *devs;
     175                 :         struct dm_hash_table *uuids;
     176                 :         struct dm_tree_node root;
     177                 :         int skip_lockfs;                /* 1 skips lockfs (for non-snapshots) */
     178                 :         int no_flush;           /* 1 sets noflush (mirrors/multipath) */
     179                 :         uint32_t cookie;
     180                 : };
     181                 : 
     182               0 : struct dm_tree *dm_tree_create(void)
     183                 : {
     184                 :         struct dm_tree *dtree;
     185                 : 
     186               0 :         if (!(dtree = dm_malloc(sizeof(*dtree)))) {
     187               0 :                 log_error("dm_tree_create malloc failed");
     188               0 :                 return NULL;
     189                 :         }
     190                 : 
     191               0 :         memset(dtree, 0, sizeof(*dtree));
     192               0 :         dtree->root.dtree = dtree;
     193               0 :         dm_list_init(&dtree->root.uses);
     194               0 :         dm_list_init(&dtree->root.used_by);
     195               0 :         dtree->skip_lockfs = 0;
     196               0 :         dtree->no_flush = 0;
     197                 : 
     198               0 :         if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
     199               0 :                 log_error("dtree pool creation failed");
     200               0 :                 dm_free(dtree);
     201               0 :                 return NULL;
     202                 :         }
     203                 : 
     204               0 :         if (!(dtree->devs = dm_hash_create(8))) {
     205               0 :                 log_error("dtree hash creation failed");
     206               0 :                 dm_pool_destroy(dtree->mem);
     207               0 :                 dm_free(dtree);
     208               0 :                 return NULL;
     209                 :         }
     210                 : 
     211               0 :         if (!(dtree->uuids = dm_hash_create(32))) {
     212               0 :                 log_error("dtree uuid hash creation failed");
     213               0 :                 dm_hash_destroy(dtree->devs);
     214               0 :                 dm_pool_destroy(dtree->mem);
     215               0 :                 dm_free(dtree);
     216               0 :                 return NULL;
     217                 :         }
     218                 : 
     219               0 :         return dtree;
     220                 : }
     221                 : 
     222               0 : void dm_tree_free(struct dm_tree *dtree)
     223                 : {
     224               0 :         if (!dtree)
     225               0 :                 return;
     226                 : 
     227               0 :         dm_hash_destroy(dtree->uuids);
     228               0 :         dm_hash_destroy(dtree->devs);
     229               0 :         dm_pool_destroy(dtree->mem);
     230               0 :         dm_free(dtree);
     231                 : }
     232                 : 
     233               0 : static int _nodes_are_linked(const struct dm_tree_node *parent,
     234                 :                              const struct dm_tree_node *child)
     235                 : {
     236                 :         struct dm_tree_link *dlink;
     237                 : 
     238               0 :         dm_list_iterate_items(dlink, &parent->uses)
     239               0 :                 if (dlink->node == child)
     240               0 :                         return 1;
     241                 : 
     242               0 :         return 0;
     243                 : }
     244                 : 
     245               0 : static int _link(struct dm_list *list, struct dm_tree_node *node)
     246                 : {
     247                 :         struct dm_tree_link *dlink;
     248                 : 
     249               0 :         if (!(dlink = dm_pool_alloc(node->dtree->mem, sizeof(*dlink)))) {
     250               0 :                 log_error("dtree link allocation failed");
     251               0 :                 return 0;
     252                 :         }
     253                 : 
     254               0 :         dlink->node = node;
     255               0 :         dm_list_add(list, &dlink->list);
     256                 : 
     257               0 :         return 1;
     258                 : }
     259                 : 
     260               0 : static int _link_nodes(struct dm_tree_node *parent,
     261                 :                        struct dm_tree_node *child)
     262                 : {
     263               0 :         if (_nodes_are_linked(parent, child))
     264               0 :                 return 1;
     265                 : 
     266               0 :         if (!_link(&parent->uses, child))
     267               0 :                 return 0;
     268                 : 
     269               0 :         if (!_link(&child->used_by, parent))
     270               0 :                 return 0;
     271                 : 
     272               0 :         return 1;
     273                 : }
     274                 : 
     275               0 : static void _unlink(struct dm_list *list, struct dm_tree_node *node)
     276                 : {
     277                 :         struct dm_tree_link *dlink;
     278                 : 
     279               0 :         dm_list_iterate_items(dlink, list)
     280               0 :                 if (dlink->node == node) {
     281               0 :                         dm_list_del(&dlink->list);
     282               0 :                         break;
     283                 :                 }
     284               0 : }
     285                 : 
     286               0 : static void _unlink_nodes(struct dm_tree_node *parent,
     287                 :                           struct dm_tree_node *child)
     288                 : {
     289               0 :         if (!_nodes_are_linked(parent, child))
     290               0 :                 return;
     291                 : 
     292               0 :         _unlink(&parent->uses, child);
     293               0 :         _unlink(&child->used_by, parent);
     294                 : }
     295                 : 
     296               0 : static int _add_to_toplevel(struct dm_tree_node *node)
     297                 : {
     298               0 :         return _link_nodes(&node->dtree->root, node);
     299                 : }
     300                 : 
     301               0 : static void _remove_from_toplevel(struct dm_tree_node *node)
     302                 : {
     303               0 :         _unlink_nodes(&node->dtree->root, node);
     304               0 : }
     305                 : 
     306               0 : static int _add_to_bottomlevel(struct dm_tree_node *node)
     307                 : {
     308               0 :         return _link_nodes(node, &node->dtree->root);
     309                 : }
     310                 : 
     311               0 : static void _remove_from_bottomlevel(struct dm_tree_node *node)
     312                 : {
     313               0 :         _unlink_nodes(node, &node->dtree->root);
     314               0 : }
     315                 : 
     316               0 : static int _link_tree_nodes(struct dm_tree_node *parent, struct dm_tree_node *child)
     317                 : {
     318                 :         /* Don't link to root node if child already has a parent */
     319               0 :         if ((parent == &parent->dtree->root)) {
     320               0 :                 if (dm_tree_node_num_children(child, 1))
     321               0 :                         return 1;
     322                 :         } else
     323               0 :                 _remove_from_toplevel(child);
     324                 : 
     325               0 :         if ((child == &child->dtree->root)) {
     326               0 :                 if (dm_tree_node_num_children(parent, 0))
     327               0 :                         return 1;
     328                 :         } else
     329               0 :                 _remove_from_bottomlevel(parent);
     330                 : 
     331               0 :         return _link_nodes(parent, child);
     332                 : }
     333                 : 
     334               0 : static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
     335                 :                                                  const char *name,
     336                 :                                                  const char *uuid,
     337                 :                                                  struct dm_info *info,
     338                 :                                                  void *context,
     339                 :                                                  uint16_t udev_flags)
     340                 : {
     341                 :         struct dm_tree_node *node;
     342                 :         uint64_t dev;
     343                 : 
     344               0 :         if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node)))) {
     345               0 :                 log_error("_create_dm_tree_node alloc failed");
     346               0 :                 return NULL;
     347                 :         }
     348                 : 
     349               0 :         node->dtree = dtree;
     350                 : 
     351               0 :         node->name = name;
     352               0 :         node->uuid = uuid;
     353               0 :         node->info = *info;
     354               0 :         node->context = context;
     355               0 :         node->udev_flags = udev_flags;
     356               0 :         node->activation_priority = 0;
     357                 : 
     358               0 :         dm_list_init(&node->uses);
     359               0 :         dm_list_init(&node->used_by);
     360               0 :         dm_list_init(&node->props.segs);
     361                 : 
     362               0 :         dev = MKDEV(info->major, info->minor);
     363                 : 
     364               0 :         if (!dm_hash_insert_binary(dtree->devs, (const char *) &dev,
     365                 :                                 sizeof(dev), node)) {
     366               0 :                 log_error("dtree node hash insertion failed");
     367               0 :                 dm_pool_free(dtree->mem, node);
     368               0 :                 return NULL;
     369                 :         }
     370                 : 
     371               0 :         if (uuid && *uuid &&
     372               0 :             !dm_hash_insert(dtree->uuids, uuid, node)) {
     373               0 :                 log_error("dtree uuid hash insertion failed");
     374               0 :                 dm_hash_remove_binary(dtree->devs, (const char *) &dev,
     375                 :                                       sizeof(dev));
     376               0 :                 dm_pool_free(dtree->mem, node);
     377               0 :                 return NULL;
     378                 :         }
     379                 : 
     380               0 :         return node;
     381                 : }
     382                 : 
     383               0 : static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree,
     384                 :                                                uint32_t major, uint32_t minor)
     385                 : {
     386               0 :         uint64_t dev = MKDEV(major, minor);
     387                 : 
     388               0 :         return dm_hash_lookup_binary(dtree->devs, (const char *) &dev,
     389                 :                                   sizeof(dev));
     390                 : }
     391                 : 
     392               0 : static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
     393                 :                                                        const char *uuid)
     394                 : {
     395                 :         struct dm_tree_node *node;
     396                 : 
     397                 :         struct dm_hash_node *n;
     398               0 :         log_verbose("HASHLOOKUP %s", uuid);
     399               0 :         dm_hash_iterate(n, dtree->uuids) {
     400               0 :                 log_verbose("HASH %s  %p", dm_hash_get_key(dtree->uuids, n),
     401                 :                             dm_hash_get_data(dtree->uuids, n));
     402                 :         }
     403                 : 
     404               0 :         if ((node = dm_hash_lookup(dtree->uuids, uuid)))
     405               0 :                 return node;
     406                 : 
     407               0 :         if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
     408               0 :                 return NULL;
     409                 : 
     410               0 :         return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);
     411                 : }
     412                 : 
     413               0 : static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
     414                 :                  const char **name, const char **uuid,
     415                 :                  struct dm_info *info, struct dm_deps **deps)
     416                 : {
     417               0 :         memset(info, 0, sizeof(*info));
     418                 : 
     419               0 :         if (!dm_is_dm_major(major)) {
     420               0 :                 *name = "";
     421               0 :                 *uuid = "";
     422               0 :                 *deps = NULL;
     423               0 :                 info->major = major;
     424               0 :                 info->minor = minor;
     425               0 :                 info->exists = 0;
     426               0 :                 info->live_table = 0;
     427               0 :                 info->inactive_table = 0;
     428               0 :                 info->read_only = 0;
     429               0 :                 return 1;
     430                 :         }
     431                 : 
     432               0 :         if (!(*dmt = dm_task_create(DM_DEVICE_DEPS))) {
     433               0 :                 log_error("deps dm_task creation failed");
     434               0 :                 return 0;
     435                 :         }
     436                 : 
     437               0 :         if (!dm_task_set_major(*dmt, major)) {
     438               0 :                 log_error("_deps: failed to set major for (%" PRIu32 ":%" PRIu32 ")",
     439                 :                           major, minor);
     440               0 :                 goto failed;
     441                 :         }
     442                 : 
     443               0 :         if (!dm_task_set_minor(*dmt, minor)) {
     444               0 :                 log_error("_deps: failed to set minor for (%" PRIu32 ":%" PRIu32 ")",
     445                 :                           major, minor);
     446               0 :                 goto failed;
     447                 :         }
     448                 : 
     449               0 :         if (!dm_task_run(*dmt)) {
     450               0 :                 log_error("_deps: task run failed for (%" PRIu32 ":%" PRIu32 ")",
     451                 :                           major, minor);
     452               0 :                 goto failed;
     453                 :         }
     454                 : 
     455               0 :         if (!dm_task_get_info(*dmt, info)) {
     456               0 :                 log_error("_deps: failed to get info for (%" PRIu32 ":%" PRIu32 ")",
     457                 :                           major, minor);
     458               0 :                 goto failed;
     459                 :         }
     460                 : 
     461               0 :         if (!info->exists) {
     462               0 :                 *name = "";
     463               0 :                 *uuid = "";
     464               0 :                 *deps = NULL;
     465                 :         } else {
     466               0 :                 if (info->major != major) {
     467               0 :                         log_error("Inconsistent dtree major number: %u != %u",
     468                 :                                   major, info->major);
     469               0 :                         goto failed;
     470                 :                 }
     471               0 :                 if (info->minor != minor) {
     472               0 :                         log_error("Inconsistent dtree minor number: %u != %u",
     473                 :                                   minor, info->minor);
     474               0 :                         goto failed;
     475                 :                 }
     476               0 :                 if (!(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {
     477               0 :                         log_error("name pool_strdup failed");
     478               0 :                         goto failed;
     479                 :                 }
     480               0 :                 if (!(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) {
     481               0 :                         log_error("uuid pool_strdup failed");
     482               0 :                         goto failed;
     483                 :                 }
     484               0 :                 *deps = dm_task_get_deps(*dmt);
     485                 :         }
     486                 : 
     487               0 :         return 1;
     488                 : 
     489                 : failed:
     490               0 :         dm_task_destroy(*dmt);
     491               0 :         return 0;
     492                 : }
     493                 : 
     494               0 : static struct dm_tree_node *_add_dev(struct dm_tree *dtree,
     495                 :                                      struct dm_tree_node *parent,
     496                 :                                      uint32_t major, uint32_t minor,
     497                 :                                      uint16_t udev_flags)
     498                 : {
     499               0 :         struct dm_task *dmt = NULL;
     500                 :         struct dm_info info;
     501               0 :         struct dm_deps *deps = NULL;
     502               0 :         const char *name = NULL;
     503               0 :         const char *uuid = NULL;
     504               0 :         struct dm_tree_node *node = NULL;
     505                 :         uint32_t i;
     506               0 :         int new = 0;
     507                 : 
     508                 :         /* Already in tree? */
     509               0 :         if (!(node = _find_dm_tree_node(dtree, major, minor))) {
     510               0 :                 if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, &info, &deps))
     511               0 :                         return_NULL;
     512                 : 
     513               0 :                 if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
     514                 :                                                   NULL, udev_flags)))
     515               0 :                         goto_out;
     516               0 :                 new = 1;
     517                 :         }
     518                 : 
     519               0 :         if (!_link_tree_nodes(parent, node)) {
     520               0 :                 node = NULL;
     521               0 :                 goto_out;
     522                 :         }
     523                 : 
     524                 :         /* If node was already in tree, no need to recurse. */
     525               0 :         if (!new)
     526               0 :                 goto out;
     527                 : 
     528                 :         /* Can't recurse if not a mapped device or there are no dependencies */
     529               0 :         if (!node->info.exists || !deps->count) {
     530               0 :                 if (!_add_to_bottomlevel(node)) {
     531               0 :                         stack;
     532               0 :                         node = NULL;
     533                 :                 }
     534               0 :                 goto out;
     535                 :         }
     536                 : 
     537                 :         /* Add dependencies to tree */
     538               0 :         for (i = 0; i < deps->count; i++)
     539               0 :                 if (!_add_dev(dtree, node, MAJOR(deps->device[i]),
     540               0 :                               MINOR(deps->device[i]), udev_flags)) {
     541               0 :                         node = NULL;
     542               0 :                         goto_out;
     543                 :                 }
     544                 : 
     545                 : out:
     546               0 :         if (dmt)
     547               0 :                 dm_task_destroy(dmt);
     548                 : 
     549               0 :         return node;
     550                 : }
     551                 : 
     552               0 : static int _node_clear_table(struct dm_tree_node *dnode)
     553                 : {
     554                 :         struct dm_task *dmt;
     555                 :         struct dm_info *info;
     556                 :         const char *name;
     557                 :         int r;
     558                 : 
     559               0 :         if (!(info = &dnode->info)) {
     560               0 :                 log_error("_node_clear_table failed: missing info");
     561               0 :                 return 0;
     562                 :         }
     563                 : 
     564               0 :         if (!(name = dm_tree_node_get_name(dnode))) {
     565               0 :                 log_error("_node_clear_table failed: missing name");
     566               0 :                 return 0;
     567                 :         }
     568                 : 
     569                 :         /* Is there a table? */
     570               0 :         if (!info->exists || !info->inactive_table)
     571               0 :                 return 1;
     572                 : 
     573               0 :         log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")",
     574                 :                     name, info->major, info->minor);
     575                 : 
     576               0 :         if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) {
     577               0 :                 dm_task_destroy(dmt);
     578               0 :                 log_error("Table clear dm_task creation failed for %s", name);
     579               0 :                 return 0;
     580                 :         }
     581                 : 
     582               0 :         if (!dm_task_set_major(dmt, info->major) ||
     583               0 :             !dm_task_set_minor(dmt, info->minor)) {
     584               0 :                 log_error("Failed to set device number for %s table clear", name);
     585               0 :                 dm_task_destroy(dmt);
     586               0 :                 return 0;
     587                 :         }
     588                 : 
     589               0 :         r = dm_task_run(dmt);
     590                 : 
     591               0 :         if (!dm_task_get_info(dmt, info)) {
     592               0 :                 log_error("_node_clear_table failed: info missing after running task for %s", name);
     593               0 :                 r = 0;
     594                 :         }
     595                 : 
     596               0 :         dm_task_destroy(dmt);
     597                 : 
     598               0 :         return r;
     599                 : }
     600                 : 
     601               0 : struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree,
     602                 :                                             const char *name,
     603                 :                                             const char *uuid,
     604                 :                                             uint32_t major, uint32_t minor,
     605                 :                                             int read_only,
     606                 :                                             int clear_inactive,
     607                 :                                             void *context)
     608                 : {
     609                 :         struct dm_tree_node *dnode;
     610                 :         struct dm_info info;
     611                 :         const char *name2;
     612                 :         const char *uuid2;
     613                 : 
     614                 :         /* Do we need to add node to tree? */
     615               0 :         if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) {
     616               0 :                 if (!(name2 = dm_pool_strdup(dtree->mem, name))) {
     617               0 :                         log_error("name pool_strdup failed");
     618               0 :                         return NULL;
     619                 :                 }
     620               0 :                 if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) {
     621               0 :                         log_error("uuid pool_strdup failed");
     622               0 :                         return NULL;
     623                 :                 }
     624                 : 
     625               0 :                 info.major = 0;
     626               0 :                 info.minor = 0;
     627               0 :                 info.exists = 0;
     628               0 :                 info.live_table = 0;
     629               0 :                 info.inactive_table = 0;
     630               0 :                 info.read_only = 0;
     631                 : 
     632               0 :                 if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info,
     633                 :                                                    context, 0)))
     634               0 :                         return_NULL;
     635                 : 
     636                 :                 /* Attach to root node until a table is supplied */
     637               0 :                 if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode))
     638               0 :                         return_NULL;
     639                 : 
     640               0 :                 dnode->props.major = major;
     641               0 :                 dnode->props.minor = minor;
     642               0 :                 dnode->props.new_name = NULL;
     643               0 :                 dnode->props.size_changed = 0;
     644               0 :         } else if (strcmp(name, dnode->name)) {
     645                 :                 /* Do we need to rename node? */
     646               0 :                 if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) {
     647               0 :                         log_error("name pool_strdup failed");
     648               0 :                         return 0;
     649                 :                 }
     650                 :         }
     651                 : 
     652               0 :         dnode->props.read_only = read_only ? 1 : 0;
     653               0 :         dnode->props.read_ahead = DM_READ_AHEAD_AUTO;
     654               0 :         dnode->props.read_ahead_flags = 0;
     655                 : 
     656               0 :         if (clear_inactive && !_node_clear_table(dnode))
     657               0 :                 return_NULL;
     658                 : 
     659               0 :         dnode->context = context;
     660               0 :         dnode->udev_flags = 0;
     661                 : 
     662               0 :         return dnode;
     663                 : }
     664                 : 
     665               0 : struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree,
     666                 :                                                          const char *name,
     667                 :                                                          const char *uuid,
     668                 :                                                          uint32_t major,
     669                 :                                                          uint32_t minor,
     670                 :                                                          int read_only,
     671                 :                                                          int clear_inactive,
     672                 :                                                          void *context,
     673                 :                                                          uint16_t udev_flags)
     674                 : {
     675                 :         struct dm_tree_node *node;
     676                 : 
     677               0 :         if ((node = dm_tree_add_new_dev(dtree, name, uuid, major, minor, read_only,
     678                 :                                        clear_inactive, context)))
     679               0 :                 node->udev_flags = udev_flags;
     680                 : 
     681               0 :         return node;
     682                 : }
     683                 : 
     684                 : 
     685               0 : void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
     686                 :                                  uint32_t read_ahead,
     687                 :                                  uint32_t read_ahead_flags)
     688                 : {
     689               0 :         dnode->props.read_ahead = read_ahead;
     690               0 :         dnode->props.read_ahead_flags = read_ahead_flags;
     691               0 : }
     692                 : 
     693               0 : int dm_tree_set_suspend_priority(struct dm_tree *dtree, const char *uuid, int priority)
     694                 : {
     695                 :         struct dm_tree_node *dnode;
     696                 : 
     697               0 :         if ((dnode = dm_tree_find_node_by_uuid(dtree, uuid))) {
     698               0 :                 log_verbose("Setting suspend priority for %s.", dnode->name);
     699               0 :                 dnode->suspend_priority = priority;
     700                 :         }
     701                 : 
     702               0 :         return 1;
     703                 : }
     704                 : 
     705               0 : int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor)
     706                 : {
     707               0 :         return _add_dev(dtree, &dtree->root, major, minor, 0) ? 1 : 0;
     708                 : }
     709                 : 
     710               0 : int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major,
     711                 :                                     uint32_t minor, uint16_t udev_flags)
     712                 : {
     713               0 :         return _add_dev(dtree, &dtree->root, major, minor, udev_flags) ? 1 : 0;
     714                 : }
     715                 : 
     716               0 : const char *dm_tree_node_get_name(const struct dm_tree_node *node)
     717                 : {
     718               0 :         return node->info.exists ? node->name : "";
     719                 : }
     720                 : 
     721               0 : const char *dm_tree_node_get_uuid(const struct dm_tree_node *node)
     722                 : {
     723               0 :         return node->info.exists ? node->uuid : "";
     724                 : }
     725                 : 
     726               0 : const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node)
     727                 : {
     728               0 :         return &node->info;
     729                 : }
     730                 : 
     731               0 : void *dm_tree_node_get_context(const struct dm_tree_node *node)
     732                 : {
     733               0 :         return node->context;
     734                 : }
     735                 : 
     736               0 : int dm_tree_node_size_changed(const struct dm_tree_node *dnode)
     737                 : {
     738               0 :         return dnode->props.size_changed;
     739                 : }
     740                 : 
     741               0 : int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted)
     742                 : {
     743               0 :         if (inverted) {
     744               0 :                 if (_nodes_are_linked(&node->dtree->root, node))
     745               0 :                         return 0;
     746               0 :                 return dm_list_size(&node->used_by);
     747                 :         }
     748                 : 
     749               0 :         if (_nodes_are_linked(node, &node->dtree->root))
     750               0 :                 return 0;
     751                 : 
     752               0 :         return dm_list_size(&node->uses);
     753                 : }
     754                 : 
     755                 : /*
     756                 :  * Returns 1 if no prefix supplied
     757                 :  */
     758               0 : static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
     759                 : {
     760               0 :         if (!uuid_prefix)
     761               0 :                 return 1;
     762                 : 
     763               0 :         if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
     764               0 :                 return 1;
     765                 : 
     766                 :         /* Handle transition: active device uuids might be missing the prefix */
     767               0 :         if (uuid_prefix_len <= 4)
     768               0 :                 return 0;
     769                 : 
     770               0 :         if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
     771               0 :                 return 0;
     772                 : 
     773               0 :         if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
     774               0 :                 return 0;
     775                 : 
     776               0 :         if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1)))
     777               0 :                 return 1;
     778                 : 
     779               0 :         return 0;
     780                 : }
     781                 : 
     782                 : /*
     783                 :  * Returns 1 if no children.
     784                 :  */
     785               0 : static int _children_suspended(struct dm_tree_node *node,
     786                 :                                uint32_t inverted,
     787                 :                                const char *uuid_prefix,
     788                 :                                size_t uuid_prefix_len)
     789                 : {
     790                 :         struct dm_list *list;
     791                 :         struct dm_tree_link *dlink;
     792                 :         const struct dm_info *dinfo;
     793                 :         const char *uuid;
     794                 : 
     795               0 :         if (inverted) {
     796               0 :                 if (_nodes_are_linked(&node->dtree->root, node))
     797               0 :                         return 1;
     798               0 :                 list = &node->used_by;
     799                 :         } else {
     800               0 :                 if (_nodes_are_linked(node, &node->dtree->root))
     801               0 :                         return 1;
     802               0 :                 list = &node->uses;
     803                 :         }
     804                 : 
     805               0 :         dm_list_iterate_items(dlink, list) {
     806               0 :                 if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
     807               0 :                         stack;
     808               0 :                         continue;
     809                 :                 }
     810                 : 
     811                 :                 /* Ignore if it doesn't belong to this VG */
     812               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
     813               0 :                         continue;
     814                 : 
     815               0 :                 if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
     816               0 :                         stack;  /* FIXME Is this normal? */
     817               0 :                         return 0;
     818                 :                 }
     819                 : 
     820               0 :                 if (!dinfo->suspended)
     821               0 :                         return 0;
     822                 :         }
     823                 : 
     824               0 :         return 1;
     825                 : }
     826                 : 
     827                 : /*
     828                 :  * Set major and minor to zero for root of tree.
     829                 :  */
     830               0 : struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
     831                 :                                           uint32_t major,
     832                 :                                           uint32_t minor)
     833                 : {
     834               0 :         if (!major && !minor)
     835               0 :                 return &dtree->root;
     836                 : 
     837               0 :         return _find_dm_tree_node(dtree, major, minor);
     838                 : }
     839                 : 
     840                 : /*
     841                 :  * Set uuid to NULL for root of tree.
     842                 :  */
     843               0 : struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
     844                 :                                                   const char *uuid)
     845                 : {
     846               0 :         if (!uuid || !*uuid)
     847               0 :                 return &dtree->root;
     848                 : 
     849               0 :         return _find_dm_tree_node_by_uuid(dtree, uuid);
     850                 : }
     851                 : 
     852                 : /*
     853                 :  * First time set *handle to NULL.
     854                 :  * Set inverted to invert the tree.
     855                 :  */
     856               0 : struct dm_tree_node *dm_tree_next_child(void **handle,
     857                 :                                         const struct dm_tree_node *parent,
     858                 :                                         uint32_t inverted)
     859                 : {
     860               0 :         struct dm_list **dlink = (struct dm_list **) handle;
     861                 :         const struct dm_list *use_list;
     862                 : 
     863               0 :         if (inverted)
     864               0 :                 use_list = &parent->used_by;
     865                 :         else
     866               0 :                 use_list = &parent->uses;
     867                 : 
     868               0 :         if (!*dlink)
     869               0 :                 *dlink = dm_list_first(use_list);
     870                 :         else
     871               0 :                 *dlink = dm_list_next(use_list, *dlink);
     872                 : 
     873               0 :         return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL;
     874                 : }
     875                 : 
     876                 : /*
     877                 :  * Deactivate a device with its dependencies if the uuid prefix matches.
     878                 :  */
     879               0 : static int _info_by_dev(uint32_t major, uint32_t minor, int with_open_count,
     880                 :                         struct dm_info *info)
     881                 : {
     882                 :         struct dm_task *dmt;
     883                 :         int r;
     884                 : 
     885               0 :         if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
     886               0 :                 log_error("_info_by_dev: dm_task creation failed");
     887               0 :                 return 0;
     888                 :         }
     889                 : 
     890               0 :         if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
     891               0 :                 log_error("_info_by_dev: Failed to set device number");
     892               0 :                 dm_task_destroy(dmt);
     893               0 :                 return 0;
     894                 :         }
     895                 : 
     896               0 :         if (!with_open_count && !dm_task_no_open_count(dmt))
     897               0 :                 log_error("Failed to disable open_count");
     898                 : 
     899               0 :         if ((r = dm_task_run(dmt)))
     900               0 :                 r = dm_task_get_info(dmt, info);
     901                 : 
     902               0 :         dm_task_destroy(dmt);
     903                 : 
     904               0 :         return r;
     905                 : }
     906                 : 
     907               0 : static int _deactivate_node(const char *name, uint32_t major, uint32_t minor,
     908                 :                             uint32_t *cookie, uint16_t udev_flags)
     909                 : {
     910                 :         struct dm_task *dmt;
     911               0 :         int r = 0;
     912                 : 
     913               0 :         log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
     914                 : 
     915               0 :         if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
     916               0 :                 log_error("Deactivation dm_task creation failed for %s", name);
     917               0 :                 return 0;
     918                 :         }
     919                 : 
     920               0 :         if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
     921               0 :                 log_error("Failed to set device number for %s deactivation", name);
     922               0 :                 goto out;
     923                 :         }
     924                 : 
     925               0 :         if (!dm_task_no_open_count(dmt))
     926               0 :                 log_error("Failed to disable open_count");
     927                 : 
     928               0 :         if (!dm_task_set_cookie(dmt, cookie, udev_flags))
     929               0 :                 goto out;
     930                 : 
     931               0 :         r = dm_task_run(dmt);
     932                 : 
     933                 :         /* FIXME Until kernel returns actual name so dm-ioctl.c can handle it */
     934               0 :         rm_dev_node(name, dmt->cookie_set &&
     935               0 :                           !(udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG));
     936                 : 
     937                 :         /* FIXME Remove node from tree or mark invalid? */
     938                 : 
     939                 : out:
     940               0 :         dm_task_destroy(dmt);
     941                 : 
     942               0 :         return r;
     943                 : }
     944                 : 
     945               0 : static int _rename_node(const char *old_name, const char *new_name, uint32_t major,
     946                 :                         uint32_t minor, uint32_t *cookie, uint16_t udev_flags)
     947                 : {
     948                 :         struct dm_task *dmt;
     949               0 :         int r = 0;
     950                 : 
     951               0 :         log_verbose("Renaming %s (%" PRIu32 ":%" PRIu32 ") to %s", old_name, major, minor, new_name);
     952                 : 
     953               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RENAME))) {
     954               0 :                 log_error("Rename dm_task creation failed for %s", old_name);
     955               0 :                 return 0;
     956                 :         }
     957                 : 
     958               0 :         if (!dm_task_set_name(dmt, old_name)) {
     959               0 :                 log_error("Failed to set name for %s rename.", old_name);
     960               0 :                 goto out;
     961                 :         }
     962                 : 
     963               0 :         if (!dm_task_set_newname(dmt, new_name))
     964               0 :                 goto_out;
     965                 : 
     966               0 :         if (!dm_task_no_open_count(dmt))
     967               0 :                 log_error("Failed to disable open_count");
     968                 : 
     969               0 :         if (!dm_task_set_cookie(dmt, cookie, udev_flags))
     970               0 :                 goto out;
     971                 : 
     972               0 :         r = dm_task_run(dmt);
     973                 : 
     974                 : out:
     975               0 :         dm_task_destroy(dmt);
     976                 : 
     977               0 :         return r;
     978                 : }
     979                 : 
     980                 : /* FIXME Merge with _suspend_node? */
     981               0 : static int _resume_node(const char *name, uint32_t major, uint32_t minor,
     982                 :                         uint32_t read_ahead, uint32_t read_ahead_flags,
     983                 :                         struct dm_info *newinfo, uint32_t *cookie,
     984                 :                         uint16_t udev_flags)
     985                 : {
     986                 :         struct dm_task *dmt;
     987               0 :         int r = 0;
     988                 : 
     989               0 :         log_verbose("Resuming %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
     990                 : 
     991               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) {
     992               0 :                 log_error("Suspend dm_task creation failed for %s", name);
     993               0 :                 return 0;
     994                 :         }
     995                 : 
     996                 :         /* FIXME Kernel should fill in name on return instead */
     997               0 :         if (!dm_task_set_name(dmt, name)) {
     998               0 :                 log_error("Failed to set readahead device name for %s", name);
     999               0 :                 goto out;
    1000                 :         }
    1001                 : 
    1002               0 :         if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
    1003               0 :                 log_error("Failed to set device number for %s resumption.", name);
    1004               0 :                 goto out;
    1005                 :         }
    1006                 : 
    1007               0 :         if (!dm_task_no_open_count(dmt))
    1008               0 :                 log_error("Failed to disable open_count");
    1009                 : 
    1010               0 :         if (!dm_task_set_read_ahead(dmt, read_ahead, read_ahead_flags))
    1011               0 :                 log_error("Failed to set read ahead");
    1012                 : 
    1013               0 :         if (!dm_task_set_cookie(dmt, cookie, udev_flags))
    1014               0 :                 goto out;
    1015                 : 
    1016               0 :         if ((r = dm_task_run(dmt)))
    1017               0 :                 r = dm_task_get_info(dmt, newinfo);
    1018                 : 
    1019                 : out:
    1020               0 :         dm_task_destroy(dmt);
    1021                 : 
    1022               0 :         return r;
    1023                 : }
    1024                 : 
    1025               0 : static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
    1026                 :                          int skip_lockfs, int no_flush, struct dm_info *newinfo)
    1027                 : {
    1028                 :         struct dm_task *dmt;
    1029                 :         int r;
    1030                 : 
    1031               0 :         log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s%s",
    1032                 :                     name, major, minor,
    1033                 :                     skip_lockfs ? "" : " with filesystem sync",
    1034                 :                     no_flush ? "" : " with device flush");
    1035                 : 
    1036               0 :         if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
    1037               0 :                 log_error("Suspend dm_task creation failed for %s", name);
    1038               0 :                 return 0;
    1039                 :         }
    1040                 : 
    1041               0 :         if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
    1042               0 :                 log_error("Failed to set device number for %s suspension.", name);
    1043               0 :                 dm_task_destroy(dmt);
    1044               0 :                 return 0;
    1045                 :         }
    1046                 : 
    1047               0 :         if (!dm_task_no_open_count(dmt))
    1048               0 :                 log_error("Failed to disable open_count");
    1049                 : 
    1050               0 :         if (skip_lockfs && !dm_task_skip_lockfs(dmt))
    1051               0 :                 log_error("Failed to set skip_lockfs flag.");
    1052                 : 
    1053               0 :         if (no_flush && !dm_task_no_flush(dmt))
    1054               0 :                 log_error("Failed to set no_flush flag.");
    1055                 : 
    1056               0 :         if ((r = dm_task_run(dmt)))
    1057               0 :                 r = dm_task_get_info(dmt, newinfo);
    1058                 : 
    1059               0 :         dm_task_destroy(dmt);
    1060                 : 
    1061               0 :         return r;
    1062                 : }
    1063                 : 
    1064               0 : static int _suspend_parent(struct dm_tree_node *dnode, const char *uuid_prefix,
    1065                 :                            size_t uuid_prefix_len)
    1066                 : {
    1067                 :         struct dm_info info;
    1068                 :         const struct dm_info *dinfo;
    1069                 :         const char *name;
    1070                 :         const char *uuid;
    1071                 :         struct dm_tree_link *dlink;
    1072                 : 
    1073               0 :         dm_list_iterate_items(dlink, &dnode->uses) {
    1074               0 :                 if (!dlink->node->suspend_priority)
    1075               0 :                         continue;
    1076                 : 
    1077               0 :                 if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
    1078               0 :                         stack;
    1079               0 :                         continue;
    1080                 :                 }
    1081                 :                 /* Ignore if it doesn't belong to this VG */
    1082               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1083               0 :                         continue;
    1084                 : 
    1085               0 :                 if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
    1086               0 :                         stack;
    1087               0 :                         continue;
    1088                 :                 }
    1089                 : 
    1090               0 :                 if (dinfo->suspended)
    1091               0 :                         continue;
    1092                 : 
    1093               0 :                 if (!(name = dm_tree_node_get_name(dlink->node))) {
    1094               0 :                         stack;
    1095               0 :                         continue;
    1096                 :                 }
    1097                 : 
    1098               0 :                 if (!_suspend_node(name, dinfo->major, dinfo->minor,
    1099                 :                                    1, 1, &info)) {
    1100               0 :                         log_error("Unable to suspend %s (%" PRIu32
    1101                 :                                   ":%" PRIu32 ").", name, dinfo->major,
    1102                 :                                   dinfo->minor);
    1103               0 :                         return 0;
    1104                 :                 }
    1105                 :         }
    1106                 : 
    1107               0 :         return 1;
    1108                 : }
    1109                 : 
    1110                 : /*
    1111                 :  * FIXME Don't attempt to deactivate known internal dependencies.
    1112                 :  */
    1113               0 : static int _dm_tree_deactivate_children(struct dm_tree_node *dnode,
    1114                 :                                         const char *uuid_prefix,
    1115                 :                                         size_t uuid_prefix_len,
    1116                 :                                         unsigned level)
    1117                 : {
    1118               0 :         int r = 1;
    1119               0 :         void *handle = NULL;
    1120               0 :         struct dm_tree_node *child = dnode;
    1121                 :         struct dm_info info;
    1122                 :         const struct dm_info *dinfo;
    1123                 :         const char *name;
    1124                 :         const char *uuid;
    1125                 : 
    1126               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1127               0 :                 log_verbose("DEACTIVATECHILDREN %s", child->name);
    1128               0 :                 if (!(dinfo = dm_tree_node_get_info(child))) {
    1129               0 :                         stack;
    1130               0 :                         continue;
    1131                 :                 }
    1132                 : 
    1133               0 :                 if (!(name = dm_tree_node_get_name(child))) {
    1134               0 :                         stack;
    1135               0 :                         continue;
    1136                 :                 }
    1137                 : 
    1138               0 :                 if (!(uuid = dm_tree_node_get_uuid(child))) {
    1139               0 :                         stack;
    1140               0 :                         continue;
    1141                 :                 }
    1142                 : 
    1143                 :                 /* Ignore if it doesn't belong to this VG */
    1144               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1145               0 :                         continue;
    1146                 : 
    1147                 :                 /* Refresh open_count */
    1148               0 :                 if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info) ||
    1149               0 :                     !info.exists)
    1150               0 :                         continue;
    1151                 : 
    1152               0 :                 if (info.open_count) {
    1153                 :                         /* Only report error from (likely non-internal) dependency at top level */
    1154               0 :                         if (!level) {
    1155               0 :                                 log_error("Unable to deactivate open %s (%" PRIu32
    1156                 :                                           ":%" PRIu32 ")", name, info.major,
    1157                 :                                         info.minor);
    1158               0 :                                 r = 0;
    1159                 :                         }
    1160               0 :                         continue;
    1161                 :                 }
    1162                 : 
    1163               0 :                 if (!_suspend_parent(child, uuid_prefix, uuid_prefix_len))
    1164               0 :                         continue;
    1165                 : 
    1166               0 :                 if (!_deactivate_node(name, info.major, info.minor,
    1167               0 :                                       &child->dtree->cookie, child->udev_flags)) {
    1168               0 :                         log_error("Unable to deactivate %s (%" PRIu32
    1169                 :                                   ":%" PRIu32 ")", name, info.major,
    1170                 :                                   info.minor);
    1171               0 :                         r = 0;
    1172               0 :                         continue;
    1173                 :                 }
    1174                 : 
    1175               0 :                 if (dm_tree_node_num_children(child, 0)) {
    1176               0 :                         if (!_dm_tree_deactivate_children(child, uuid_prefix, uuid_prefix_len, level + 1))
    1177               0 :                                 return_0;
    1178                 :                 }
    1179                 :         }
    1180                 : 
    1181               0 :         return r;
    1182                 : }
    1183                 : 
    1184               0 : int dm_tree_deactivate_children(struct dm_tree_node *dnode,
    1185                 :                                    const char *uuid_prefix,
    1186                 :                                    size_t uuid_prefix_len)
    1187                 : {
    1188               0 :         return _dm_tree_deactivate_children(dnode, uuid_prefix, uuid_prefix_len, 0);
    1189                 : }
    1190                 : 
    1191               0 : void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
    1192                 : {
    1193               0 :         dnode->dtree->skip_lockfs = 1;
    1194               0 : }
    1195                 : 
    1196               0 : void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
    1197                 : {
    1198               0 :         dnode->dtree->no_flush = 1;
    1199               0 : }
    1200                 : 
    1201               0 : int dm_tree_suspend_children(struct dm_tree_node *dnode,
    1202                 :                              const char *uuid_prefix,
    1203                 :                              size_t uuid_prefix_len)
    1204                 : {
    1205               0 :         int r = 1;
    1206               0 :         void *handle = NULL;
    1207               0 :         struct dm_tree_node *child = dnode;
    1208                 :         struct dm_info info, newinfo;
    1209                 :         const struct dm_info *dinfo;
    1210                 :         const char *name;
    1211                 :         const char *uuid;
    1212                 : 
    1213                 :         /* Suspend nodes at this level of the tree */
    1214               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1215               0 :                 log_verbose("SUSPENDCHILDREN %s", child->name);
    1216               0 :                 if (!(dinfo = dm_tree_node_get_info(child))) {
    1217               0 :                         stack;
    1218               0 :                         continue;
    1219                 :                 }
    1220                 : 
    1221               0 :                 if (!(name = dm_tree_node_get_name(child))) {
    1222               0 :                         stack;
    1223               0 :                         continue;
    1224                 :                 }
    1225                 : 
    1226               0 :                 if (!(uuid = dm_tree_node_get_uuid(child))) {
    1227               0 :                         stack;
    1228               0 :                         continue;
    1229                 :                 }
    1230                 : 
    1231                 :                 /* Ignore if it doesn't belong to this VG */
    1232               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1233               0 :                         continue;
    1234                 : 
    1235                 :                 /* Ensure immediate parents are already suspended */
    1236               0 :                 if (!_children_suspended(child, 1, uuid_prefix, uuid_prefix_len))
    1237               0 :                         continue;
    1238                 : 
    1239               0 :                 if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info) ||
    1240               0 :                     !info.exists || info.suspended)
    1241               0 :                         continue;
    1242                 : 
    1243               0 :                 if (!_suspend_node(name, info.major, info.minor,
    1244               0 :                                    child->dtree->skip_lockfs,
    1245               0 :                                    child->dtree->no_flush, &newinfo)) {
    1246               0 :                         log_error("Unable to suspend %s (%" PRIu32
    1247                 :                                   ":%" PRIu32 ")", name, info.major,
    1248                 :                                   info.minor);
    1249               0 :                         r = 0;
    1250               0 :                         continue;
    1251                 :                 }
    1252                 : 
    1253                 :                 /* Update cached info */
    1254               0 :                 child->info = newinfo;
    1255                 :         }
    1256                 : 
    1257                 :         /* Then suspend any child nodes */
    1258               0 :         handle = NULL;
    1259                 : 
    1260               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1261               0 :                 if (!(uuid = dm_tree_node_get_uuid(child))) {
    1262               0 :                         stack;
    1263               0 :                         continue;
    1264                 :                 }
    1265                 : 
    1266                 :                 /* Ignore if it doesn't belong to this VG */
    1267               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1268               0 :                         continue;
    1269                 : 
    1270               0 :                 if (dm_tree_node_num_children(child, 0))
    1271               0 :                         if (!dm_tree_suspend_children(child, uuid_prefix, uuid_prefix_len))
    1272               0 :                                 return_0;
    1273                 :         }
    1274                 : 
    1275               0 :         return r;
    1276                 : }
    1277                 : 
    1278               0 : int dm_tree_activate_children(struct dm_tree_node *dnode,
    1279                 :                                  const char *uuid_prefix,
    1280                 :                                  size_t uuid_prefix_len)
    1281                 : {
    1282               0 :         int r = 1;
    1283               0 :         void *handle = NULL;
    1284               0 :         struct dm_tree_node *child = dnode;
    1285                 :         struct dm_info newinfo;
    1286                 :         const char *name;
    1287                 :         const char *uuid;
    1288                 :         int priority;
    1289                 : 
    1290                 :         /* Activate children first */
    1291               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1292               0 :                 if (!(uuid = dm_tree_node_get_uuid(child))) {
    1293               0 :                         stack;
    1294               0 :                         continue;
    1295                 :                 }
    1296                 : 
    1297               0 :                 if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1298               0 :                         continue;
    1299                 : 
    1300               0 :                 if (dm_tree_node_num_children(child, 0))
    1301               0 :                         if (!dm_tree_activate_children(child, uuid_prefix, uuid_prefix_len))
    1302               0 :                                 return_0;
    1303                 :         }
    1304                 : 
    1305               0 :         handle = NULL;
    1306                 : 
    1307               0 :         for (priority = 0; priority < 3; priority++) {
    1308               0 :                 while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1309               0 :                         if (!(uuid = dm_tree_node_get_uuid(child))) {
    1310               0 :                                 stack;
    1311               0 :                                 continue;
    1312                 :                         }
    1313                 : 
    1314               0 :                         if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1315               0 :                                 continue;
    1316                 : 
    1317               0 :                         if (priority != child->activation_priority)
    1318               0 :                                 continue;
    1319                 : 
    1320               0 :                         if (!(name = dm_tree_node_get_name(child))) {
    1321               0 :                                 stack;
    1322               0 :                                 continue;
    1323                 :                         }
    1324                 : 
    1325                 :                         /* Rename? */
    1326               0 :                         if (child->props.new_name) {
    1327               0 :                                 if (!_rename_node(name, child->props.new_name, child->info.major,
    1328               0 :                                                   child->info.minor, &child->dtree->cookie,
    1329               0 :                                                   child->udev_flags)) {
    1330               0 :                                         log_error("Failed to rename %s (%" PRIu32
    1331                 :                                                   ":%" PRIu32 ") to %s", name, child->info.major,
    1332                 :                                                   child->info.minor, child->props.new_name);
    1333               0 :                                         return 0;
    1334                 :                                 }
    1335               0 :                                 child->name = child->props.new_name;
    1336               0 :                                 child->props.new_name = NULL;
    1337                 :                         }
    1338                 : 
    1339               0 :                         if (!child->info.inactive_table && !child->info.suspended)
    1340               0 :                                 continue;
    1341                 : 
    1342               0 :                         log_verbose("ACTIVATERESUME %s", child->name);
    1343               0 :                         if (!_resume_node(child->name, child->info.major, child->info.minor,
    1344                 :                                           child->props.read_ahead, child->props.read_ahead_flags,
    1345               0 :                                           &newinfo, &child->dtree->cookie, child->udev_flags)) {
    1346               0 :                                 log_error("Unable to resume %s (%" PRIu32
    1347                 :                                           ":%" PRIu32 ")", child->name, child->info.major,
    1348                 :                                           child->info.minor);
    1349               0 :                                 r = 0;
    1350               0 :                                 continue;
    1351                 :                         }
    1352                 : 
    1353                 :                         /* Update cached info */
    1354               0 :                         child->info = newinfo;
    1355                 :                 }
    1356                 :         }
    1357                 : 
    1358               0 :         handle = NULL;
    1359                 : 
    1360               0 :         return r;
    1361                 : }
    1362                 : 
    1363               0 : static int _create_node(struct dm_tree_node *dnode)
    1364                 : {
    1365               0 :         int r = 0;
    1366                 :         struct dm_task *dmt;
    1367                 : 
    1368               0 :         log_verbose("Creating %s", dnode->name);
    1369                 : 
    1370               0 :         if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) {
    1371               0 :                 log_error("Create dm_task creation failed for %s", dnode->name);
    1372               0 :                 return 0;
    1373                 :         }
    1374                 : 
    1375               0 :         if (!dm_task_set_name(dmt, dnode->name)) {
    1376               0 :                 log_error("Failed to set device name for %s", dnode->name);
    1377               0 :                 goto out;
    1378                 :         }
    1379                 : 
    1380               0 :         if (!dm_task_set_uuid(dmt, dnode->uuid)) {
    1381               0 :                 log_error("Failed to set uuid for %s", dnode->name);
    1382               0 :                 goto out;
    1383                 :         }
    1384                 : 
    1385               0 :         if (dnode->props.major &&
    1386               0 :             (!dm_task_set_major(dmt, dnode->props.major) ||
    1387               0 :              !dm_task_set_minor(dmt, dnode->props.minor))) {
    1388               0 :                 log_error("Failed to set device number for %s creation.", dnode->name);
    1389               0 :                 goto out;
    1390                 :         }
    1391                 : 
    1392               0 :         if (dnode->props.read_only && !dm_task_set_ro(dmt)) {
    1393               0 :                 log_error("Failed to set read only flag for %s", dnode->name);
    1394               0 :                 goto out;
    1395                 :         }
    1396                 : 
    1397               0 :         if (!dm_task_no_open_count(dmt))
    1398               0 :                 log_error("Failed to disable open_count");
    1399                 : 
    1400               0 :         if ((r = dm_task_run(dmt)))
    1401               0 :                 r = dm_task_get_info(dmt, &dnode->info);
    1402                 : 
    1403                 : out:
    1404               0 :         dm_task_destroy(dmt);
    1405                 : 
    1406               0 :         return r;
    1407                 : }
    1408                 : 
    1409                 : 
    1410               0 : static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
    1411                 : {
    1412               0 :         if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
    1413               0 :                 log_error("Failed to format %s device number for %s as dm "
    1414                 :                           "target (%u,%u)",
    1415                 :                           node->name, node->uuid, node->info.major, node->info.minor);
    1416               0 :                 return 0;
    1417                 :         }
    1418                 : 
    1419               0 :         return 1;
    1420                 : }
    1421                 : 
    1422                 : /* simplify string emiting code */
    1423                 : #define EMIT_PARAMS(p, str...)\
    1424                 : do {\
    1425                 :         int w;\
    1426                 :         if ((w = dm_snprintf(params + p, paramsize - (size_t) p, str)) < 0) {\
    1427                 :                 stack; /* Out of space */\
    1428                 :                 return -1;\
    1429                 :         }\
    1430                 :         p += w;\
    1431                 : } while (0)
    1432                 : 
    1433                 : /*
    1434                 :  * _emit_areas_line
    1435                 :  *
    1436                 :  * Returns: 1 on success, 0 on failure
    1437                 :  */
    1438               0 : static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
    1439                 :                             struct load_segment *seg, char *params,
    1440                 :                             size_t paramsize, int *pos)
    1441                 : {
    1442                 :         struct seg_area *area;
    1443                 :         char devbuf[DM_FORMAT_DEV_BUFSIZE];
    1444               0 :         unsigned first_time = 1;
    1445                 :         const char *logtype;
    1446                 :         unsigned log_parm_count;
    1447                 : 
    1448               0 :         dm_list_iterate_items(area, &seg->areas) {
    1449               0 :                 if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
    1450               0 :                         return_0;
    1451                 : 
    1452               0 :                 switch (seg->type) {
    1453                 :                 case SEG_REPLICATOR_DEV:
    1454               0 :                         EMIT_PARAMS(*pos, " %d 1 %s", area->rsite_index, devbuf);
    1455               0 :                         if (first_time)
    1456               0 :                                 EMIT_PARAMS(*pos, " nolog 0");
    1457                 :                         else {
    1458                 :                                 /* Remote devices */
    1459               0 :                                 log_parm_count = (area->flags &
    1460                 :                                                   (DM_NOSYNC | DM_FORCESYNC)) ? 2 : 1;
    1461                 : 
    1462               0 :                                 if (!area->slog) {
    1463               0 :                                         devbuf[0] = 0;          /* Only core log parameters */
    1464               0 :                                         logtype = "core";
    1465                 :                                 } else {
    1466               0 :                                         devbuf[0] = ' ';        /* Extra space before device name */
    1467               0 :                                         if (!_build_dev_string(devbuf + 1,
    1468                 :                                                                sizeof(devbuf) - 1,
    1469                 :                                                                area->slog))
    1470               0 :                                                 return_0;
    1471               0 :                                         logtype = "disk";
    1472               0 :                                         log_parm_count++;       /* Extra sync log device name parameter */
    1473                 :                                 }
    1474                 : 
    1475               0 :                                 EMIT_PARAMS(*pos, " %s %u%s %" PRIu64, logtype,
    1476                 :                                             log_parm_count, devbuf, area->region_size);
    1477                 : 
    1478               0 :                                 logtype = (area->flags & DM_NOSYNC) ?
    1479               0 :                                         " nosync" : (area->flags & DM_FORCESYNC) ?
    1480                 :                                         " sync" : NULL;
    1481                 : 
    1482               0 :                                 if (logtype)
    1483               0 :                                         EMIT_PARAMS(*pos, logtype);
    1484                 :                         }
    1485               0 :                         break;
    1486                 :                 default:
    1487               0 :                         EMIT_PARAMS(*pos, "%s%s %" PRIu64, first_time ? "" : " ",
    1488                 :                                     devbuf, area->offset);
    1489                 :                 }
    1490                 : 
    1491               0 :                 first_time = 0;
    1492                 :         }
    1493                 : 
    1494               0 :         return 1;
    1495                 : }
    1496                 : 
    1497               0 : static int _replicator_emit_segment_line(const struct load_segment *seg, char *params,
    1498                 :                                          size_t paramsize, int *pos)
    1499                 : {
    1500                 :         const struct load_segment *rlog_seg;
    1501                 :         struct replicator_site *rsite;
    1502                 :         char rlogbuf[DM_FORMAT_DEV_BUFSIZE];
    1503                 :         unsigned parm_count;
    1504                 : 
    1505               0 :         if (!seg->log || !_build_dev_string(rlogbuf, sizeof(rlogbuf), seg->log))
    1506               0 :                 return_0;
    1507                 : 
    1508               0 :         rlog_seg = dm_list_item(dm_list_last(&seg->log->props.segs),
    1509                 :                                 struct load_segment);
    1510                 : 
    1511               0 :         EMIT_PARAMS(*pos, "%s 4 %s 0 auto %" PRIu64,
    1512                 :                     seg->rlog_type, rlogbuf, rlog_seg->size);
    1513                 : 
    1514               0 :         dm_list_iterate_items(rsite, &seg->rsites) {
    1515               0 :                 parm_count = (rsite->fall_behind_data
    1516               0 :                               || rsite->fall_behind_ios
    1517               0 :                               || rsite->async_timeout) ? 4 : 2;
    1518                 : 
    1519               0 :                 EMIT_PARAMS(*pos, " blockdev %u %u %s", parm_count, rsite->rsite_index,
    1520                 :                             (rsite->mode == DM_REPLICATOR_SYNC) ? "synchronous" : "asynchronous");
    1521                 : 
    1522               0 :                 if (rsite->fall_behind_data)
    1523               0 :                         EMIT_PARAMS(*pos, " data %" PRIu64, rsite->fall_behind_data);
    1524               0 :                 else if (rsite->fall_behind_ios)
    1525               0 :                         EMIT_PARAMS(*pos, " ios %" PRIu32, rsite->fall_behind_ios);
    1526               0 :                 else if (rsite->async_timeout)
    1527               0 :                         EMIT_PARAMS(*pos, " timeout %" PRIu32, rsite->async_timeout);
    1528                 :         }
    1529                 : 
    1530               0 :         return 1;
    1531                 : }
    1532                 : 
    1533                 : /*
    1534                 :  * Returns: 1 on success, 0 on failure
    1535                 :  */
    1536               0 : static int _mirror_emit_segment_line(struct dm_task *dmt, uint32_t major,
    1537                 :                                      uint32_t minor, struct load_segment *seg,
    1538                 :                                      uint64_t *seg_start, char *params,
    1539                 :                                      size_t paramsize)
    1540                 : {
    1541                 :         int r;
    1542               0 :         int block_on_error = 0;
    1543               0 :         int handle_errors = 0;
    1544               0 :         int dm_log_userspace = 0;
    1545                 :         struct utsname uts;
    1546                 :         unsigned log_parm_count;
    1547               0 :         int pos = 0;
    1548                 :         char logbuf[DM_FORMAT_DEV_BUFSIZE];
    1549                 :         const char *logtype;
    1550                 : 
    1551               0 :         r = uname(&uts);
    1552               0 :         if (r)
    1553               0 :                 return_0;
    1554                 : 
    1555               0 :         if ((seg->flags & DM_BLOCK_ON_ERROR)) {
    1556                 :                 /*
    1557                 :                  * Originally, block_on_error was an argument to the log
    1558                 :                  * portion of the mirror CTR table.  It was renamed to
    1559                 :                  * "handle_errors" and now resides in the 'features'
    1560                 :                  * section of the mirror CTR table (i.e. at the end).
    1561                 :                  *
    1562                 :                  * We can identify whether to use "block_on_error" or
    1563                 :                  * "handle_errors" by the dm-mirror module's version
    1564                 :                  * number (>= 1.12) or by the kernel version (>= 2.6.22).
    1565                 :                  */
    1566               0 :                 if (strncmp(uts.release, "2.6.22", 6) >= 0)
    1567               0 :                         handle_errors = 1;
    1568                 :                 else
    1569               0 :                         block_on_error = 1;
    1570                 :         }
    1571                 : 
    1572               0 :         if (seg->clustered) {
    1573                 :                 /* Cluster mirrors require a UUID */
    1574               0 :                 if (!seg->uuid)
    1575               0 :                         return_0;
    1576                 : 
    1577                 :                 /*
    1578                 :                  * Cluster mirrors used to have their own log
    1579                 :                  * types.  Now they are accessed through the
    1580                 :                  * userspace log type.
    1581                 :                  *
    1582                 :                  * The dm-log-userspace module was added to the
    1583                 :                  * 2.6.31 kernel.
    1584                 :                  */
    1585               0 :                 if (strncmp(uts.release, "2.6.31", 6) >= 0)
    1586               0 :                         dm_log_userspace = 1;
    1587                 :         }
    1588                 : 
    1589                 :         /* Region size */
    1590               0 :         log_parm_count = 1;
    1591                 : 
    1592                 :         /* [no]sync, block_on_error etc. */
    1593               0 :         log_parm_count += hweight32(seg->flags);
    1594                 : 
    1595                 :         /* "handle_errors" is a feature arg now */
    1596               0 :         if (handle_errors)
    1597               0 :                 log_parm_count--;
    1598                 : 
    1599                 :         /* DM_CORELOG does not count in the param list */
    1600               0 :         if (seg->flags & DM_CORELOG)
    1601               0 :                 log_parm_count--;
    1602                 : 
    1603               0 :         if (seg->clustered) {
    1604               0 :                 log_parm_count++; /* For UUID */
    1605                 : 
    1606               0 :                 if (!dm_log_userspace)
    1607               0 :                         EMIT_PARAMS(pos, "clustered-");
    1608                 :                 else
    1609                 :                         /* For clustered-* type field inserted later */
    1610               0 :                         log_parm_count++;
    1611                 :         }
    1612                 : 
    1613               0 :         if (!seg->log)
    1614               0 :                 logtype = "core";
    1615                 :         else {
    1616               0 :                 logtype = "disk";
    1617               0 :                 log_parm_count++;
    1618               0 :                 if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
    1619               0 :                         return_0;
    1620                 :         }
    1621                 : 
    1622               0 :         if (dm_log_userspace)
    1623               0 :                 EMIT_PARAMS(pos, "userspace %u %s clustered-%s",
    1624                 :                             log_parm_count, seg->uuid, logtype);
    1625                 :         else
    1626               0 :                 EMIT_PARAMS(pos, "%s %u", logtype, log_parm_count);
    1627                 : 
    1628               0 :         if (seg->log)
    1629               0 :                 EMIT_PARAMS(pos, " %s", logbuf);
    1630                 : 
    1631               0 :         EMIT_PARAMS(pos, " %u", seg->region_size);
    1632                 : 
    1633               0 :         if (seg->clustered && !dm_log_userspace)
    1634               0 :                 EMIT_PARAMS(pos, " %s", seg->uuid);
    1635                 : 
    1636               0 :         if ((seg->flags & DM_NOSYNC))
    1637               0 :                 EMIT_PARAMS(pos, " nosync");
    1638               0 :         else if ((seg->flags & DM_FORCESYNC))
    1639               0 :                 EMIT_PARAMS(pos, " sync");
    1640                 : 
    1641               0 :         if (block_on_error)
    1642               0 :                 EMIT_PARAMS(pos, " block_on_error");
    1643                 : 
    1644               0 :         EMIT_PARAMS(pos, " %u ", seg->mirror_area_count);
    1645                 : 
    1646               0 :         if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0)
    1647               0 :                 return_0;
    1648                 : 
    1649               0 :         if (handle_errors)
    1650               0 :                 EMIT_PARAMS(pos, " 1 handle_errors");
    1651                 : 
    1652               0 :         return 1;
    1653                 : }
    1654                 : 
    1655               0 : static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
    1656                 :                               uint32_t minor, struct load_segment *seg,
    1657                 :                               uint64_t *seg_start, char *params,
    1658                 :                               size_t paramsize)
    1659                 : {
    1660               0 :         int pos = 0;
    1661                 :         int r;
    1662                 :         char originbuf[DM_FORMAT_DEV_BUFSIZE], cowbuf[DM_FORMAT_DEV_BUFSIZE];
    1663                 : 
    1664               0 :         switch(seg->type) {
    1665                 :         case SEG_ERROR:
    1666                 :         case SEG_ZERO:
    1667                 :         case SEG_LINEAR:
    1668               0 :                 break;
    1669                 :         case SEG_MIRRORED:
    1670                 :                 /* Mirrors are pretty complicated - now in separate function */
    1671               0 :                 r = _mirror_emit_segment_line(dmt, major, minor, seg, seg_start,
    1672                 :                                               params, paramsize);
    1673               0 :                 if (!r)
    1674               0 :                         return_0;
    1675               0 :                 break;
    1676                 :         case SEG_REPLICATOR:
    1677               0 :                 if ((r = _replicator_emit_segment_line(seg, params, paramsize,
    1678                 :                                                        &pos)) <= 0) {
    1679               0 :                         stack;
    1680               0 :                         return r;
    1681                 :                 }
    1682               0 :                 break;
    1683                 :         case SEG_REPLICATOR_DEV:
    1684               0 :                 if (!seg->replicator || !_build_dev_string(originbuf,
    1685                 :                                                            sizeof(originbuf),
    1686                 :                                                            seg->replicator))
    1687               0 :                         return_0;
    1688                 : 
    1689               0 :                 EMIT_PARAMS(pos, "%s %" PRIu64, originbuf, seg->rdevice_index);
    1690               0 :                 break;
    1691                 :         case SEG_SNAPSHOT:
    1692                 :         case SEG_SNAPSHOT_MERGE:
    1693               0 :                 if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
    1694               0 :                         return_0;
    1695               0 :                 if (!_build_dev_string(cowbuf, sizeof(cowbuf), seg->cow))
    1696               0 :                         return_0;
    1697               0 :                 EMIT_PARAMS(pos, "%s %s %c %d", originbuf, cowbuf,
    1698                 :                             seg->persistent ? 'P' : 'N', seg->chunk_size);
    1699               0 :                 break;
    1700                 :         case SEG_SNAPSHOT_ORIGIN:
    1701               0 :                 if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
    1702               0 :                         return_0;
    1703               0 :                 EMIT_PARAMS(pos, "%s", originbuf);
    1704               0 :                 break;
    1705                 :         case SEG_STRIPED:
    1706               0 :                 EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
    1707               0 :                 break;
    1708                 :         case SEG_CRYPT:
    1709               0 :                 EMIT_PARAMS(pos, "%s%s%s%s%s %s %" PRIu64 " ", seg->cipher,
    1710                 :                             seg->chainmode ? "-" : "", seg->chainmode ?: "",
    1711                 :                             seg->iv ? "-" : "", seg->iv ?: "", seg->key,
    1712                 :                             seg->iv_offset != DM_CRYPT_IV_DEFAULT ?
    1713                 :                             seg->iv_offset : *seg_start);
    1714                 :                 break;
    1715                 :         }
    1716                 : 
    1717               0 :         switch(seg->type) {
    1718                 :         case SEG_ERROR:
    1719                 :         case SEG_REPLICATOR:
    1720                 :         case SEG_SNAPSHOT:
    1721                 :         case SEG_SNAPSHOT_ORIGIN:
    1722                 :         case SEG_SNAPSHOT_MERGE:
    1723                 :         case SEG_ZERO:
    1724               0 :                 break;
    1725                 :         case SEG_CRYPT:
    1726                 :         case SEG_LINEAR:
    1727                 :         case SEG_REPLICATOR_DEV:
    1728                 :         case SEG_STRIPED:
    1729               0 :                 if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) {
    1730               0 :                         stack;
    1731               0 :                         return r;
    1732                 :                 }
    1733                 :                 break;
    1734                 :         }
    1735                 : 
    1736               0 :         log_debug("Adding target to (%" PRIu32 ":%" PRIu32 "): %" PRIu64
    1737                 :                   " %" PRIu64 " %s %s", major, minor,
    1738                 :                   *seg_start, seg->size, dm_segtypes[seg->type].target, params);
    1739                 : 
    1740               0 :         if (!dm_task_add_target(dmt, *seg_start, seg->size, dm_segtypes[seg->type].target, params))
    1741               0 :                 return_0;
    1742                 : 
    1743               0 :         *seg_start += seg->size;
    1744                 : 
    1745               0 :         return 1;
    1746                 : }
    1747                 : 
    1748                 : #undef EMIT_PARAMS
    1749                 : 
    1750               0 : static int _emit_segment(struct dm_task *dmt, uint32_t major, uint32_t minor,
    1751                 :                          struct load_segment *seg, uint64_t *seg_start)
    1752                 : {
    1753                 :         char *params;
    1754               0 :         size_t paramsize = 4096;
    1755                 :         int ret;
    1756                 : 
    1757                 :         do {
    1758               0 :                 if (!(params = dm_malloc(paramsize))) {
    1759               0 :                         log_error("Insufficient space for target parameters.");
    1760               0 :                         return 0;
    1761                 :                 }
    1762                 : 
    1763               0 :                 params[0] = '\0';
    1764               0 :                 ret = _emit_segment_line(dmt, major, minor, seg, seg_start,
    1765                 :                                          params, paramsize);
    1766               0 :                 dm_free(params);
    1767                 : 
    1768               0 :                 if (!ret)
    1769               0 :                         stack;
    1770                 : 
    1771               0 :                 if (ret >= 0)
    1772               0 :                         return ret;
    1773                 : 
    1774               0 :                 log_debug("Insufficient space in params[%" PRIsize_t
    1775                 :                           "] for target parameters.", paramsize);
    1776                 : 
    1777               0 :                 paramsize *= 2;
    1778               0 :         } while (paramsize < MAX_TARGET_PARAMSIZE);
    1779                 : 
    1780               0 :         log_error("Target parameter size too big. Aborting.");
    1781               0 :         return 0;
    1782                 : }
    1783                 : 
    1784               0 : static int _load_node(struct dm_tree_node *dnode)
    1785                 : {
    1786               0 :         int r = 0;
    1787                 :         struct dm_task *dmt;
    1788                 :         struct load_segment *seg;
    1789               0 :         uint64_t seg_start = 0;
    1790                 : 
    1791               0 :         log_verbose("Loading %s table (%" PRIu32 ":%" PRIu32 ")", dnode->name,
    1792                 :                     dnode->info.major, dnode->info.minor);
    1793                 : 
    1794               0 :         if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) {
    1795               0 :                 log_error("Reload dm_task creation failed for %s", dnode->name);
    1796               0 :                 return 0;
    1797                 :         }
    1798                 : 
    1799               0 :         if (!dm_task_set_major(dmt, dnode->info.major) ||
    1800               0 :             !dm_task_set_minor(dmt, dnode->info.minor)) {
    1801               0 :                 log_error("Failed to set device number for %s reload.", dnode->name);
    1802               0 :                 goto out;
    1803                 :         }
    1804                 : 
    1805               0 :         if (dnode->props.read_only && !dm_task_set_ro(dmt)) {
    1806               0 :                 log_error("Failed to set read only flag for %s", dnode->name);
    1807               0 :                 goto out;
    1808                 :         }
    1809                 : 
    1810               0 :         if (!dm_task_no_open_count(dmt))
    1811               0 :                 log_error("Failed to disable open_count");
    1812                 : 
    1813               0 :         dm_list_iterate_items(seg, &dnode->props.segs)
    1814               0 :                 if (!_emit_segment(dmt, dnode->info.major, dnode->info.minor,
    1815                 :                                    seg, &seg_start))
    1816               0 :                         goto_out;
    1817                 : 
    1818               0 :         if (!dm_task_suppress_identical_reload(dmt))
    1819               0 :                 log_error("Failed to suppress reload of identical tables.");
    1820                 : 
    1821               0 :         if ((r = dm_task_run(dmt))) {
    1822               0 :                 r = dm_task_get_info(dmt, &dnode->info);
    1823               0 :                 if (r && !dnode->info.inactive_table)
    1824               0 :                         log_verbose("Suppressed %s identical table reload.",
    1825                 :                                     dnode->name);
    1826                 : 
    1827               0 :                 if ((dnode->props.size_changed =
    1828                 :                      (dm_task_get_existing_table_size(dmt) == seg_start) ? 0 : 1))
    1829               0 :                         log_debug("Table size changed from %" PRIu64 " to %"
    1830                 :                                   PRIu64 " for %s",
    1831                 :                                   dm_task_get_existing_table_size(dmt),
    1832                 :                                   seg_start, dnode->name);
    1833                 :         }
    1834                 : 
    1835               0 :         dnode->props.segment_count = 0;
    1836                 : 
    1837                 : out:
    1838               0 :         dm_task_destroy(dmt);
    1839                 : 
    1840               0 :         return r;
    1841                 : }
    1842                 : 
    1843               0 : int dm_tree_preload_children(struct dm_tree_node *dnode,
    1844                 :                              const char *uuid_prefix,
    1845                 :                              size_t uuid_prefix_len)
    1846                 : {
    1847               0 :         int r = 1;
    1848               0 :         void *handle = NULL;
    1849                 :         struct dm_tree_node *child;
    1850                 :         struct dm_info newinfo;
    1851                 : 
    1852               0 :         log_verbose("PRELOAD %s",  dnode->name);
    1853                 : 
    1854                 :         /* Preload children first */
    1855               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1856                 :                 /* Skip existing non-device-mapper devices */
    1857               0 :                 if (!child->info.exists && child->info.major)
    1858               0 :                         continue;
    1859                 : 
    1860                 :                 /* Ignore if it doesn't belong to this VG */
    1861               0 :                 if (child->info.exists &&
    1862               0 :                     !_uuid_prefix_matches(child->uuid, uuid_prefix, uuid_prefix_len))
    1863               0 :                         continue;
    1864                 : 
    1865               0 :                 log_verbose("CHILDRENS %s   %s  %d  i:%d   prio:%d", dnode->name, child->name, dm_tree_node_num_children(child, 0), dm_tree_node_num_children(child, 1), child->activation_priority);
    1866               0 :                 if (dm_tree_node_num_children(child, 0))
    1867               0 :                         if (!dm_tree_preload_children(child, uuid_prefix, uuid_prefix_len))
    1868               0 :                                 return_0;
    1869                 : 
    1870                 :                 /* FIXME Cope if name exists with no uuid? */
    1871               0 :                 if (!child->info.exists) {
    1872               0 :                         if (!_create_node(child)) {
    1873               0 :                                 stack;
    1874               0 :                                 return 0;
    1875                 :                         }
    1876                 :                 }
    1877                 : 
    1878               0 :                 if (!child->info.inactive_table && child->props.segment_count) {
    1879               0 :                         if (!_load_node(child)) {
    1880               0 :                                 stack;
    1881               0 :                                 return 0;
    1882                 :                         }
    1883                 :                 }
    1884                 : 
    1885               0 :                 if (child->activation_priority != 0)
    1886               0 :                         continue;
    1887                 : 
    1888                 :                 /* Propagate device size change change */
    1889               0 :                 if (child->props.size_changed)
    1890               0 :                         dnode->props.size_changed = 1;
    1891                 : 
    1892                 :                 /* Resume device immediately if it has parents and its size changed */
    1893               0 :                 if (!dm_tree_node_num_children(child, 1) || !child->props.size_changed)
    1894               0 :                         continue;
    1895                 : 
    1896               0 :                 if (!child->info.inactive_table && !child->info.suspended)
    1897               0 :                         continue;
    1898                 : 
    1899               0 :                 log_verbose("PRELOADRESUME %s  %s", dnode->name, child->name);
    1900               0 :                 if (!_resume_node(child->name, child->info.major, child->info.minor,
    1901                 :                                   child->props.read_ahead, child->props.read_ahead_flags,
    1902               0 :                                   &newinfo, &child->dtree->cookie, child->udev_flags)) {
    1903               0 :                         log_error("Unable to resume %s (%" PRIu32
    1904                 :                                   ":%" PRIu32 ")", child->name, child->info.major,
    1905                 :                                   child->info.minor);
    1906               0 :                         r = 0;
    1907               0 :                         continue;
    1908                 :                 }
    1909                 : 
    1910                 :                 /* Update cached info */
    1911               0 :                 child->info = newinfo;
    1912                 :         }
    1913                 : 
    1914               0 :         handle = NULL;
    1915                 : 
    1916               0 :         log_verbose("PRELOADING %s FINISHED",  dnode->name);
    1917               0 :         return r;
    1918                 : }
    1919                 : 
    1920                 : /*
    1921                 :  * Returns 1 if unsure.
    1922                 :  */
    1923               0 : int dm_tree_children_use_uuid(struct dm_tree_node *dnode,
    1924                 :                                  const char *uuid_prefix,
    1925                 :                                  size_t uuid_prefix_len)
    1926                 : {
    1927               0 :         void *handle = NULL;
    1928               0 :         struct dm_tree_node *child = dnode;
    1929                 :         const char *uuid;
    1930                 : 
    1931               0 :         while ((child = dm_tree_next_child(&handle, dnode, 0))) {
    1932               0 :                 if (!(uuid = dm_tree_node_get_uuid(child))) {
    1933               0 :                         log_error("Failed to get uuid for dtree node.");
    1934               0 :                         return 1;
    1935                 :                 }
    1936                 : 
    1937               0 :                 if (_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
    1938               0 :                         return 1;
    1939                 : 
    1940               0 :                 if (dm_tree_node_num_children(child, 0))
    1941               0 :                         dm_tree_children_use_uuid(child, uuid_prefix, uuid_prefix_len);
    1942                 :         }
    1943                 : 
    1944               0 :         return 0;
    1945                 : }
    1946                 : 
    1947                 : /*
    1948                 :  * Target functions
    1949                 :  */
    1950               0 : static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned type, uint64_t size)
    1951                 : {
    1952                 :         struct load_segment *seg;
    1953                 : 
    1954               0 :         if (!(seg = dm_pool_zalloc(dnode->dtree->mem, sizeof(*seg)))) {
    1955               0 :                 log_error("dtree node segment allocation failed");
    1956               0 :                 return NULL;
    1957                 :         }
    1958                 : 
    1959               0 :         seg->type = type;
    1960               0 :         seg->size = size;
    1961               0 :         seg->area_count = 0;
    1962               0 :         dm_list_init(&seg->areas);
    1963               0 :         seg->stripe_size = 0;
    1964               0 :         seg->persistent = 0;
    1965               0 :         seg->chunk_size = 0;
    1966               0 :         seg->cow = NULL;
    1967               0 :         seg->origin = NULL;
    1968               0 :         seg->merge = NULL;
    1969                 : 
    1970               0 :         dm_list_add(&dnode->props.segs, &seg->list);
    1971               0 :         dnode->props.segment_count++;
    1972                 : 
    1973               0 :         return seg;
    1974                 : }
    1975                 : 
    1976               0 : int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
    1977                 :                                                uint64_t size,
    1978                 :                                                const char *origin_uuid)
    1979                 : {
    1980                 :         struct load_segment *seg;
    1981                 :         struct dm_tree_node *origin_node;
    1982                 : 
    1983               0 :         if (!(seg = _add_segment(dnode, SEG_SNAPSHOT_ORIGIN, size)))
    1984               0 :                 return_0;
    1985                 : 
    1986               0 :         if (!(origin_node = dm_tree_find_node_by_uuid(dnode->dtree, origin_uuid))) {
    1987               0 :                 log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
    1988               0 :                 return 0;
    1989                 :         }
    1990                 : 
    1991               0 :         seg->origin = origin_node;
    1992               0 :         if (!_link_tree_nodes(dnode, origin_node))
    1993               0 :                 return_0;
    1994                 : 
    1995                 :         /* Resume snapshot origins after new snapshots */
    1996               0 :         dnode->activation_priority = 1;
    1997                 : 
    1998               0 :         return 1;
    1999                 : }
    2000                 : 
    2001               0 : static int _add_snapshot_target(struct dm_tree_node *node,
    2002                 :                                    uint64_t size,
    2003                 :                                    const char *origin_uuid,
    2004                 :                                    const char *cow_uuid,
    2005                 :                                    const char *merge_uuid,
    2006                 :                                    int persistent,
    2007                 :                                    uint32_t chunk_size)
    2008                 : {
    2009                 :         struct load_segment *seg;
    2010                 :         struct dm_tree_node *origin_node, *cow_node, *merge_node;
    2011                 :         unsigned seg_type;
    2012                 : 
    2013               0 :         seg_type = !merge_uuid ? SEG_SNAPSHOT : SEG_SNAPSHOT_MERGE;
    2014                 : 
    2015               0 :         if (!(seg = _add_segment(node, seg_type, size)))
    2016               0 :                 return_0;
    2017                 : 
    2018               0 :         if (!(origin_node = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
    2019               0 :                 log_error("Couldn't find snapshot origin uuid %s.", origin_uuid);
    2020               0 :                 return 0;
    2021                 :         }
    2022                 : 
    2023               0 :         seg->origin = origin_node;
    2024               0 :         if (!_link_tree_nodes(node, origin_node))
    2025               0 :                 return_0;
    2026                 : 
    2027               0 :         if (!(cow_node = dm_tree_find_node_by_uuid(node->dtree, cow_uuid))) {
    2028               0 :                 log_error("Couldn't find snapshot COW device uuid %s.", cow_uuid);
    2029               0 :                 return 0;
    2030                 :         }
    2031                 : 
    2032               0 :         seg->cow = cow_node;
    2033               0 :         if (!_link_tree_nodes(node, cow_node))
    2034               0 :                 return_0;
    2035                 : 
    2036               0 :         seg->persistent = persistent ? 1 : 0;
    2037               0 :         seg->chunk_size = chunk_size;
    2038                 : 
    2039               0 :         if (merge_uuid) {
    2040               0 :                 if (!(merge_node = dm_tree_find_node_by_uuid(node->dtree, merge_uuid))) {
    2041                 :                         /* not a pure error, merging snapshot may have been deactivated */
    2042               0 :                         log_verbose("Couldn't find merging snapshot uuid %s.", merge_uuid);
    2043                 :                 } else {
    2044               0 :                         seg->merge = merge_node;
    2045                 :                         /* must not link merging snapshot, would undermine activation_priority below */
    2046                 :                 }
    2047                 : 
    2048                 :                 /* Resume snapshot-merge (acting origin) after other snapshots */
    2049               0 :                 node->activation_priority = 1;
    2050               0 :                 if (seg->merge) {
    2051                 :                         /* Resume merging snapshot after snapshot-merge */
    2052               0 :                         seg->merge->activation_priority = 2;
    2053                 :                 }
    2054                 :         }
    2055                 : 
    2056               0 :         return 1;
    2057                 : }
    2058                 : 
    2059                 : 
    2060               0 : int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
    2061                 :                                      uint64_t size,
    2062                 :                                      const char *origin_uuid,
    2063                 :                                      const char *cow_uuid,
    2064                 :                                      int persistent,
    2065                 :                                      uint32_t chunk_size)
    2066                 : {
    2067               0 :         return _add_snapshot_target(node, size, origin_uuid, cow_uuid,
    2068                 :                                     NULL, persistent, chunk_size);
    2069                 : }
    2070                 : 
    2071               0 : int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node,
    2072                 :                                            uint64_t size,
    2073                 :                                            const char *origin_uuid,
    2074                 :                                            const char *cow_uuid,
    2075                 :                                            const char *merge_uuid,
    2076                 :                                            uint32_t chunk_size)
    2077                 : {
    2078               0 :         return _add_snapshot_target(node, size, origin_uuid, cow_uuid,
    2079                 :                                     merge_uuid, 1, chunk_size);
    2080                 : }
    2081                 : 
    2082               0 : int dm_tree_node_add_error_target(struct dm_tree_node *node,
    2083                 :                                      uint64_t size)
    2084                 : {
    2085               0 :         if (!_add_segment(node, SEG_ERROR, size))
    2086               0 :                 return_0;
    2087                 : 
    2088               0 :         return 1;
    2089                 : }
    2090                 : 
    2091               0 : int dm_tree_node_add_zero_target(struct dm_tree_node *node,
    2092                 :                                     uint64_t size)
    2093                 : {
    2094               0 :         if (!_add_segment(node, SEG_ZERO, size))
    2095               0 :                 return_0;
    2096                 : 
    2097               0 :         return 1;
    2098                 : }
    2099                 : 
    2100               0 : int dm_tree_node_add_linear_target(struct dm_tree_node *node,
    2101                 :                                       uint64_t size)
    2102                 : {
    2103               0 :         if (!_add_segment(node, SEG_LINEAR, size))
    2104               0 :                 return_0;
    2105                 : 
    2106               0 :         return 1;
    2107                 : }
    2108                 : 
    2109               0 : int dm_tree_node_add_striped_target(struct dm_tree_node *node,
    2110                 :                                        uint64_t size,
    2111                 :                                        uint32_t stripe_size)
    2112                 : {
    2113                 :         struct load_segment *seg;
    2114                 : 
    2115               0 :         if (!(seg = _add_segment(node, SEG_STRIPED, size)))
    2116               0 :                 return_0;
    2117                 : 
    2118               0 :         seg->stripe_size = stripe_size;
    2119                 : 
    2120               0 :         return 1;
    2121                 : }
    2122                 : 
    2123               0 : int dm_tree_node_add_crypt_target(struct dm_tree_node *node,
    2124                 :                                   uint64_t size,
    2125                 :                                   const char *cipher,
    2126                 :                                   const char *chainmode,
    2127                 :                                   const char *iv,
    2128                 :                                   uint64_t iv_offset,
    2129                 :                                   const char *key)
    2130                 : {
    2131                 :         struct load_segment *seg;
    2132                 : 
    2133               0 :         if (!(seg = _add_segment(node, SEG_CRYPT, size)))
    2134               0 :                 return_0;
    2135                 : 
    2136               0 :         seg->cipher = cipher;
    2137               0 :         seg->chainmode = chainmode;
    2138               0 :         seg->iv = iv;
    2139               0 :         seg->iv_offset = iv_offset;
    2140               0 :         seg->key = key;
    2141                 : 
    2142               0 :         return 1;
    2143                 : }
    2144                 : 
    2145               0 : int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
    2146                 :                                           uint32_t region_size,
    2147                 :                                           unsigned clustered,
    2148                 :                                           const char *log_uuid,
    2149                 :                                           unsigned area_count,
    2150                 :                                           uint32_t flags)
    2151                 : {
    2152               0 :         struct dm_tree_node *log_node = NULL;
    2153                 :         struct load_segment *seg;
    2154                 : 
    2155               0 :         if (!node->props.segment_count) {
    2156               0 :                 log_error(INTERNAL_ERROR "Attempt to add target area to missing segment.");
    2157               0 :                 return 0;
    2158                 :         }
    2159                 : 
    2160               0 :         seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
    2161                 : 
    2162               0 :         if (log_uuid) {
    2163               0 :                 if (!(seg->uuid = dm_pool_strdup(node->dtree->mem, log_uuid))) {
    2164               0 :                         log_error("log uuid pool_strdup failed");
    2165               0 :                         return 0;
    2166                 :                 }
    2167               0 :                 if (!(flags & DM_CORELOG)) {
    2168               0 :                         if (!(log_node = dm_tree_find_node_by_uuid(node->dtree, log_uuid))) {
    2169               0 :                                 log_error("Couldn't find mirror log uuid %s.", log_uuid);
    2170               0 :                                 return 0;
    2171                 :                         }
    2172                 : 
    2173               0 :                         if (!_link_tree_nodes(node, log_node))
    2174               0 :                                 return_0;
    2175                 :                 }
    2176                 :         }
    2177                 : 
    2178               0 :         seg->log = log_node;
    2179               0 :         seg->region_size = region_size;
    2180               0 :         seg->clustered = clustered;
    2181               0 :         seg->mirror_area_count = area_count;
    2182               0 :         seg->flags = flags;
    2183                 : 
    2184               0 :         return 1;
    2185                 : }
    2186                 : 
    2187               0 : int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
    2188                 :                                       uint64_t size)
    2189                 : {
    2190                 :         struct load_segment *seg;
    2191                 : 
    2192               0 :         if (!(seg = _add_segment(node, SEG_MIRRORED, size)))
    2193               0 :                 return_0;
    2194                 : 
    2195               0 :         return 1;
    2196                 : }
    2197                 : 
    2198               0 : int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
    2199                 :                                        uint64_t size,
    2200                 :                                        const char *rlog_uuid,
    2201                 :                                        const char *rlog_type,
    2202                 :                                        unsigned rsite_index,
    2203                 :                                        dm_replicator_mode_t mode,
    2204                 :                                        uint32_t async_timeout,
    2205                 :                                        uint64_t fall_behind_data,
    2206                 :                                        uint32_t fall_behind_ios)
    2207                 : {
    2208                 :         struct load_segment *rseg;
    2209                 :         struct replicator_site *rsite;
    2210                 : 
    2211               0 :         log_verbose("replicator idx:%d  a:%d  t:%d  i:%d  d:%" PRId64, rsite_index, mode, async_timeout, fall_behind_ios, fall_behind_data);
    2212               0 :         log_verbose("add element %d", node->props.segment_count);
    2213                 :         /* Local site0 - adds replicator segment and links rlog device */
    2214               0 :         if (rsite_index == 0) {
    2215               0 :                 if (node->props.segment_count) {
    2216               0 :                         log_error(INTERNAL_ERROR "Attempt to add replicator segment to already used node.");
    2217               0 :                         return 0;
    2218                 :                 }
    2219                 : 
    2220               0 :                 if (!(rseg = _add_segment(node, SEG_REPLICATOR, size)))
    2221               0 :                         return_0;
    2222                 : 
    2223               0 :                 if (!(rseg->log = dm_tree_find_node_by_uuid(node->dtree, rlog_uuid))) {
    2224               0 :                         log_error("Missing replicator log uuid %s.", rlog_uuid);
    2225               0 :                         return 0;
    2226                 :                 }
    2227                 : 
    2228               0 :                 if (!_link_tree_nodes(node, rseg->log))
    2229               0 :                         return_0;
    2230                 : 
    2231               0 :                 if (strcmp(rlog_type, "ringbuffer") != 0) {
    2232               0 :                         log_error("Unsupported rlog type %s.", rlog_type);
    2233               0 :                         return 0;
    2234                 :                 }
    2235                 : 
    2236               0 :                 if (!(rseg->rlog_type = dm_pool_strdup(node->dtree->mem, rlog_type)))
    2237               0 :                         return_0;
    2238                 : 
    2239               0 :                 dm_list_init(&rseg->rsites);
    2240               0 :                 rseg->rdevice_count = 0;
    2241               0 :                 node->activation_priority = 1;
    2242                 :         }
    2243                 : 
    2244                 :         /* Add site to segment */
    2245               0 :         if (mode == DM_REPLICATOR_SYNC
    2246                 :             && (async_timeout || fall_behind_ios || fall_behind_data)) {
    2247               0 :                 log_error("Async parameters passed for synchronnous replicator.");
    2248               0 :                 return 0;
    2249                 :         }
    2250                 : 
    2251               0 :         if (node->props.segment_count != 1) {
    2252               0 :                 log_error(INTERNAL_ERROR "Attempt to add remote site area before setting replog.");
    2253               0 :                 return 0;
    2254                 :         }
    2255                 : 
    2256               0 :         rseg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
    2257               0 :         if (rseg->type != SEG_REPLICATOR) {
    2258               0 :                 log_error(INTERNAL_ERROR "Attempt to use non replicator segment %s.",
    2259                 :                           dm_segtypes[rseg->type].target);
    2260               0 :                 return 0;
    2261                 :         }
    2262                 : 
    2263               0 :         if (!(rsite = dm_pool_zalloc(node->dtree->mem, sizeof(*rsite)))) {
    2264               0 :                 log_error("Failed to allocate remote site segment.");
    2265               0 :                 return 0;
    2266                 :         }
    2267                 : 
    2268               0 :         dm_list_add(&rseg->rsites, &rsite->list);
    2269               0 :         rseg->rsite_count++;
    2270                 : 
    2271               0 :         rsite->mode = mode;
    2272               0 :         rsite->async_timeout = async_timeout;
    2273               0 :         rsite->fall_behind_data = fall_behind_data;
    2274               0 :         rsite->fall_behind_ios = fall_behind_ios;
    2275               0 :         rsite->rsite_index = rsite_index;
    2276                 : 
    2277               0 :         log_verbose("ADDEDSEGLOG %p", rseg->log);
    2278               0 :         return 1;
    2279                 : }
    2280                 : 
    2281                 : /* Appends device node to Replicator */
    2282               0 : int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
    2283                 :                                            uint64_t size,
    2284                 :                                            const char *replicator_uuid,
    2285                 :                                            uint64_t rdevice_index,
    2286                 :                                            const char *rdev_uuid,
    2287                 :                                            unsigned rsite_index,
    2288                 :                                            const char *slog_uuid,
    2289                 :                                            uint32_t slog_flags,
    2290                 :                                            uint32_t slog_region_size)
    2291                 : {
    2292                 :         struct seg_area *area;
    2293                 :         struct load_segment *rseg;
    2294                 :         struct load_segment *rep_seg;
    2295                 : 
    2296               0 :         log_verbose("replicator-dev:%s  device index:%" PRIu64 " uuid:%s  dev:%s",
    2297                 :                     node->name, rdevice_index, node->uuid, rdev_uuid);
    2298               0 :         log_verbose("dev:%s   log:%s", rdev_uuid, slog_uuid);
    2299               0 :         if (rsite_index == 0) {
    2300                 :                 /* Site index for local target */
    2301               0 :                 if (!(rseg = _add_segment(node, SEG_REPLICATOR_DEV, size)))
    2302               0 :                         return_0;
    2303                 : 
    2304               0 :                 if (!(rseg->replicator = dm_tree_find_node_by_uuid(node->dtree, replicator_uuid))) {
    2305               0 :                         log_error("Missing replicator uuid %s.", replicator_uuid);
    2306               0 :                         return 0;
    2307                 :                 }
    2308                 : 
    2309                 :                 /* Local slink 0 for replicator must be always initialized first */
    2310               0 :                 if (rseg->replicator->props.segment_count != 1) {
    2311               0 :                         log_error(INTERNAL_ERROR "Attempt to use non replicator segment.");
    2312               0 :                         return 0;
    2313                 :                 }
    2314                 : 
    2315               0 :                 rep_seg = dm_list_item(dm_list_last(&rseg->replicator->props.segs), struct load_segment);
    2316               0 :                 if (rep_seg->type != SEG_REPLICATOR) {
    2317               0 :                         log_error(INTERNAL_ERROR "Attempt to use non replicator segment %s.",
    2318                 :                                   dm_segtypes[rep_seg->type].target);
    2319               0 :                         return 0;
    2320                 :                 }
    2321               0 :                 rep_seg->rdevice_count++;
    2322                 : 
    2323               0 :                 if (!_link_tree_nodes(node, rseg->replicator))
    2324               0 :                         return_0;
    2325                 : 
    2326               0 :                 rseg->rdevice_index = rdevice_index;
    2327                 :         } else {
    2328               0 :                 if (node->props.segment_count != 1) {
    2329                 :                         /* Local slink 0 for replicator must be always initialized first */
    2330               0 :                         log_error(INTERNAL_ERROR "Attempt to use non replicator-dev segment.");
    2331               0 :                         return 0;
    2332                 :                 }
    2333                 : 
    2334               0 :                 rseg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
    2335               0 :                 if (rseg->type != SEG_REPLICATOR_DEV) {
    2336               0 :                         log_error(INTERNAL_ERROR "Attempt to use non replicator-dev segment %s.",
    2337                 :                                   dm_segtypes[rseg->type].target);
    2338               0 :                         return 0;
    2339                 :                 }
    2340                 :         }
    2341                 : 
    2342               0 :         if (!(slog_flags & DM_CORELOG) && !slog_uuid) {
    2343               0 :                 log_error("Unspecified sync log uuid.");
    2344               0 :                 return 0;
    2345                 :         }
    2346                 : 
    2347               0 :         log_verbose("CREATE CHILDRENS1 %s  %d", node->name, dm_tree_node_num_children(node, 0));
    2348               0 :         if (!dm_tree_node_add_target_area(node, NULL, rdev_uuid, 0))
    2349               0 :                 return_0;
    2350                 : 
    2351               0 :         area = dm_list_item(dm_list_last(&rseg->areas), struct seg_area);
    2352                 : 
    2353               0 :         if (!(slog_flags & DM_CORELOG)) {
    2354               0 :                 if (!(area->slog = dm_tree_find_node_by_uuid(node->dtree, slog_uuid))) {
    2355               0 :                         log_error("Couldn't find sync log uuid %s.", slog_uuid);
    2356               0 :                         return 0;
    2357                 :                 }
    2358                 : 
    2359               0 :                 if (!_link_tree_nodes(node, area->slog))
    2360               0 :                         return_0;
    2361               0 :                 log_verbose("CREATE CHILDRENS2 %s  %d ", node->name, dm_tree_node_num_children(node, 0));
    2362                 :         }
    2363                 : 
    2364               0 :         area->flags = slog_flags;
    2365               0 :         area->region_size = slog_region_size;
    2366               0 :         area->rsite_index = rsite_index;
    2367                 : 
    2368               0 :         return 1;
    2369                 : }
    2370                 : 
    2371               0 : static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
    2372                 : {
    2373                 :         struct seg_area *area;
    2374                 : 
    2375               0 :         if (!(area = dm_pool_zalloc(node->dtree->mem, sizeof (*area)))) {
    2376               0 :                 log_error("Failed to allocate target segment area.");
    2377               0 :                 return 0;
    2378                 :         }
    2379                 : 
    2380               0 :         area->dev_node = dev_node;
    2381               0 :         area->offset = offset;
    2382                 : 
    2383               0 :         dm_list_add(&seg->areas, &area->list);
    2384               0 :         seg->area_count++;
    2385                 : 
    2386               0 :         return 1;
    2387                 : }
    2388                 : 
    2389               0 : int dm_tree_node_add_target_area(struct dm_tree_node *node,
    2390                 :                                     const char *dev_name,
    2391                 :                                     const char *uuid,
    2392                 :                                     uint64_t offset)
    2393                 : {
    2394                 :         struct load_segment *seg;
    2395                 :         struct stat info;
    2396                 :         struct dm_tree_node *dev_node;
    2397                 : 
    2398               0 :         if ((!dev_name || !*dev_name) && (!uuid || !*uuid)) {
    2399               0 :                 log_error("dm_tree_node_add_target_area called without device");
    2400               0 :                 return 0;
    2401                 :         }
    2402                 : 
    2403               0 :         if (uuid) {
    2404               0 :                 if (!(dev_node = dm_tree_find_node_by_uuid(node->dtree, uuid))) {
    2405               0 :                         log_error("Couldn't find area uuid %s.", uuid);
    2406               0 :                         return 0;
    2407                 :                 }
    2408               0 :                 if (!_link_tree_nodes(node, dev_node))
    2409               0 :                         return_0;
    2410                 :         } else {
    2411               0 :                 if (stat(dev_name, &info) < 0) {
    2412               0 :                         log_error("Device %s not found.", dev_name);
    2413               0 :                         return 0;
    2414                 :                 }
    2415                 : 
    2416               0 :                 if (!S_ISBLK(info.st_mode)) {
    2417               0 :                         log_error("Device %s is not a block device.", dev_name);
    2418               0 :                         return 0;
    2419                 :                 }
    2420                 : 
    2421                 :                 /* FIXME Check correct macro use */
    2422               0 :                 if (!(dev_node = _add_dev(node->dtree, node, MAJOR(info.st_rdev),
    2423               0 :                                           MINOR(info.st_rdev), 0)))
    2424               0 :                         return_0;
    2425                 :         }
    2426                 : 
    2427               0 :         if (!node->props.segment_count) {
    2428               0 :                 log_error(INTERNAL_ERROR "Attempt to add target area to missing segment.");
    2429               0 :                 return 0;
    2430                 :         }
    2431                 : 
    2432               0 :         seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
    2433                 : 
    2434               0 :         if (!_add_area(node, seg, dev_node, offset))
    2435               0 :                 return_0;
    2436                 : 
    2437               0 :         return 1;
    2438                 : }
    2439                 : 
    2440               0 : void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie)
    2441                 : {
    2442               0 :         node->dtree->cookie = cookie;
    2443               0 : }
    2444                 : 
    2445               0 : uint32_t dm_tree_get_cookie(struct dm_tree_node *node)
    2446                 : {
    2447               0 :         return node->dtree->cookie;
    2448                 : }

Generated by: LCOV version 1.7