storage_backend_mpath.c 7.3 KB
Newer Older
D
Dave Allan 已提交
1 2 3
/*
 * storage_backend_mpath.c: storage backend for multipath handling
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2009-2011, 2013 Red Hat, Inc.
D
Dave Allan 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2009-2008 Dave Allan
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
D
Dave Allan 已提交
20 21 22 23 24 25 26 27 28 29 30 31
 *
 * Author: Dave Allan <dallan@redhat.com>
 */

#include <config.h>

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

#include <libdevmapper.h>

32
#include "virerror.h"
D
Dave Allan 已提交
33 34
#include "storage_conf.h"
#include "storage_backend.h"
35
#include "viralloc.h"
36
#include "virlog.h"
E
Eric Blake 已提交
37
#include "virfile.h"
38
#include "virstring.h"
D
Dave Allan 已提交
39 40 41

#define VIR_FROM_THIS VIR_FROM_STORAGE

42 43
VIR_LOG_INIT("storage.storage_backend_mpath");

D
Dave Allan 已提交
44
static int
45
virStorageBackendMpathUpdateVolTargetInfo(virStorageVolTargetPtr target,
D
Dave Allan 已提交
46 47 48
                                          unsigned long long *allocation,
                                          unsigned long long *capacity)
{
49
    int ret = -1;
50
    int fdret, fd = -1;
E
Eric Blake 已提交
51
    struct stat sb;
D
Dave Allan 已提交
52

E
Eric Blake 已提交
53 54
    if ((fdret = virStorageBackendVolOpenCheckMode(target->path, &sb,
                                                   VIR_STORAGE_VOL_OPEN_DEFAULT)) < 0)
D
Dave Allan 已提交
55
        goto out;
56
    fd = fdret;
D
Dave Allan 已提交
57

58
    if (virStorageBackendUpdateVolTargetInfoFD(target,
D
Dave Allan 已提交
59
                                               fd,
E
Eric Blake 已提交
60
                                               &sb,
D
Dave Allan 已提交
61
                                               allocation,
62
                                               capacity) < 0)
D
Dave Allan 已提交
63 64
        goto out;

65
    if (virStorageBackendDetectBlockVolFormatFD(target, fd) < 0)
D
Dave Allan 已提交
66 67
        goto out;

68
    ret = 0;
D
Dave Allan 已提交
69
out:
70
    VIR_FORCE_CLOSE(fd);
D
Dave Allan 已提交
71 72 73 74 75
    return ret;
}


static int
76
virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
77 78 79 80 81 82
                             const int devnum,
                             const char *dev)
{
    virStorageVolDefPtr vol;
    int ret = -1;

83
    if (VIR_ALLOC(vol) < 0)
D
Dave Allan 已提交
84 85 86 87
        goto cleanup;

    vol->type = VIR_STORAGE_VOL_BLOCK;

88
    if (virAsprintf(&(vol->name), "dm-%u", devnum) < 0)
D
Dave Allan 已提交
89 90
        goto cleanup;

91
    if (virAsprintf(&vol->target.path, "/dev/%s", dev) < 0)
D
Dave Allan 已提交
92 93
        goto cleanup;

94
    if (virStorageBackendMpathUpdateVolTargetInfo(&vol->target,
D
Dave Allan 已提交
95 96 97 98 99 100
                                                  &vol->allocation,
                                                  &vol->capacity) < 0) {
        goto cleanup;
    }

    /* XXX should use logical unit's UUID instead */
101
    if (VIR_STRDUP(vol->key, vol->target.path) < 0)
D
Dave Allan 已提交
102 103
        goto cleanup;

104
    if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, vol) < 0)
D
Dave Allan 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
        goto cleanup;
    pool->def->capacity += vol->capacity;
    pool->def->allocation += vol->allocation;
    ret = 0;

cleanup:

    if (ret != 0)
        virStorageVolDefFree(vol);

    return ret;
}


static int
120
virStorageBackendIsMultipath(const char *dev_name)
D
Dave Allan 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134
{
    int ret = 0;
    struct dm_task *dmt = NULL;
    void *next = NULL;
    uint64_t start, length;
    char *target_type = NULL;
    char *params = NULL;

    dmt = dm_task_create(DM_DEVICE_TABLE);
    if (dmt == NULL) {
        ret = -1;
        goto out;
    }

135
    if (dm_task_set_name(dmt, dev_name) == 0) {
D
Dave Allan 已提交
136 137 138 139 140 141 142 143 144 145 146
        ret = -1;
        goto out;
    }

    dm_task_no_open_count(dmt);

    if (!dm_task_run(dmt)) {
        ret = -1;
        goto out;
    }

147
    dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
D
Dave Allan 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

    if (target_type == NULL) {
        ret = -1;
        goto out;
    }

    if (STREQ(target_type, "multipath")) {
        ret = 1;
    }

out:
    if (dmt != NULL) {
        dm_task_destroy(dmt);
    }
    return ret;
}


static int
167
virStorageBackendGetMinorNumber(const char *dev_name, uint32_t *minor)
D
Dave Allan 已提交
168
{
169 170 171
    int ret = -1;
    struct dm_task *dmt;
    struct dm_info info;
D
Dave Allan 已提交
172

173 174 175
    if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
        goto out;
    }
D
Dave Allan 已提交
176

177
    if (!dm_task_set_name(dmt, dev_name)) {
178 179
        goto out;
    }
D
Dave Allan 已提交
180

181 182 183
    if (!dm_task_run(dmt)) {
        goto out;
    }
D
Dave Allan 已提交
184

185 186 187
    if (!dm_task_get_info(dmt, &info)) {
        goto out;
    }
D
Dave Allan 已提交
188

189 190
    *minor = info.minor;
    ret = 0;
D
Dave Allan 已提交
191 192

out:
193 194
    if (dmt != NULL)
        dm_task_destroy(dmt);
D
Dave Allan 已提交
195

196
    return ret;
D
Dave Allan 已提交
197 198 199 200
}


static int
201
virStorageBackendCreateVols(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
202 203
                            struct dm_names *names)
{
204
    int retval = -1, is_mpath = 0;
D
Dave Allan 已提交
205 206
    char *map_device = NULL;
    uint32_t minor = -1;
207
    uint32_t next;
D
Dave Allan 已提交
208 209 210 211 212 213 214 215 216 217

    do {
        is_mpath = virStorageBackendIsMultipath(names->name);

        if (is_mpath < 0) {
            goto out;
        }

        if (is_mpath == 1) {

218
            if (virAsprintf(&map_device, "mapper/%s", names->name) < 0)
D
Dave Allan 已提交
219 220 221
                goto out;

            if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
222 223 224
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to get %s minor number"),
                               names->name);
D
Dave Allan 已提交
225 226 227
                goto out;
            }

228 229 230
            if (virStorageBackendMpathNewVol(pool, minor, map_device) < 0) {
                goto out;
            }
D
Dave Allan 已提交
231 232 233 234 235 236

            VIR_FREE(map_device);
        }

        /* Given the way libdevmapper returns its data, I don't see
         * any way to avoid this series of casts. */
237
        VIR_WARNINGS_NO_CAST_ALIGN
238 239
        next = names->next;
        names = (struct dm_names *)(((char *)names) + next);
240
        VIR_WARNINGS_RESET
D
Dave Allan 已提交
241

242
    } while (next);
D
Dave Allan 已提交
243

244
    retval = 0;
D
Dave Allan 已提交
245 246 247 248 249 250
out:
    return retval;
}


static int
251
virStorageBackendGetMaps(virStoragePoolObjPtr pool)
D
Dave Allan 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
{
    int retval = 0;
    struct dm_task *dmt = NULL;
    struct dm_names *names = NULL;

    if (!(dmt = dm_task_create(DM_DEVICE_LIST))) {
        retval = 1;
        goto out;
    }

    dm_task_no_open_count(dmt);

    if (!dm_task_run(dmt)) {
        retval = 1;
        goto out;
    }

    if (!(names = dm_task_get_names(dmt))) {
        retval = 1;
        goto out;
    }

    if (!names->dev) {
        /* No devices found */
        goto out;
    }

279
    virStorageBackendCreateVols(pool, names);
D
Dave Allan 已提交
280 281 282

out:
    if (dmt != NULL) {
283
        dm_task_destroy(dmt);
D
Dave Allan 已提交
284 285 286 287
    }
    return retval;
}

288 289 290 291 292
static int
virStorageBackendMpathCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                bool *isActive)
{
293
    *isActive = virFileExists("/dev/mpath");
294 295 296 297
    return 0;
}


D
Dave Allan 已提交
298 299

static int
300
virStorageBackendMpathRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
D
Dave Allan 已提交
301 302 303 304
                                  virStoragePoolObjPtr pool)
{
    int retval = 0;

O
Osier Yang 已提交
305
    VIR_DEBUG("conn=%p, pool=%p", conn, pool);
D
Dave Allan 已提交
306 307 308

    pool->def->allocation = pool->def->capacity = pool->def->available = 0;

309
    virFileWaitForDevices();
D
Dave Allan 已提交
310

311
    virStorageBackendGetMaps(pool);
D
Dave Allan 已提交
312 313 314 315 316 317 318 319

    return retval;
}


virStorageBackend virStorageBackendMpath = {
    .type = VIR_STORAGE_POOL_MPATH,

320
    .checkPool = virStorageBackendMpathCheckPool,
D
Dave Allan 已提交
321 322
    .refreshPool = virStorageBackendMpathRefreshPool,
};