storage_backend_mpath.c 6.4 KB
Newer Older
D
Dave Allan 已提交
1 2 3
/*
 * storage_backend_mpath.c: storage backend for multipath handling
 *
4
 * Copyright (C) 2009-2014 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
virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
46 47 48 49 50 51
                             const int devnum,
                             const char *dev)
{
    virStorageVolDefPtr vol;
    int ret = -1;

52
    if (VIR_ALLOC(vol) < 0)
D
Dave Allan 已提交
53 54 55 56
        goto cleanup;

    vol->type = VIR_STORAGE_VOL_BLOCK;

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

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

63
    if (virStorageBackendUpdateVolInfo(vol, true, true,
64
                                       VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) {
D
Dave Allan 已提交
65 66 67 68
        goto cleanup;
    }

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

72
    if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, vol) < 0)
D
Dave Allan 已提交
73
        goto cleanup;
74 75
    pool->def->capacity += vol->target.capacity;
    pool->def->allocation += vol->target.allocation;
D
Dave Allan 已提交
76 77
    ret = 0;

78
 cleanup:
D
Dave Allan 已提交
79 80 81 82 83 84 85 86 87

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

    return ret;
}


static int
88
virStorageBackendIsMultipath(const char *dev_name)
D
Dave Allan 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102
{
    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;
    }

103
    if (dm_task_set_name(dmt, dev_name) == 0) {
D
Dave Allan 已提交
104 105 106 107 108 109 110 111 112 113 114
        ret = -1;
        goto out;
    }

    dm_task_no_open_count(dmt);

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

115
    dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
D
Dave Allan 已提交
116 117 118 119 120 121 122 123 124 125

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

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

126
 out:
D
Dave Allan 已提交
127 128 129 130 131 132 133 134
    if (dmt != NULL) {
        dm_task_destroy(dmt);
    }
    return ret;
}


static int
135
virStorageBackendGetMinorNumber(const char *dev_name, uint32_t *minor)
D
Dave Allan 已提交
136
{
137 138 139
    int ret = -1;
    struct dm_task *dmt;
    struct dm_info info;
D
Dave Allan 已提交
140

141 142 143
    if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
        goto out;
    }
D
Dave Allan 已提交
144

145
    if (!dm_task_set_name(dmt, dev_name)) {
146 147
        goto out;
    }
D
Dave Allan 已提交
148

149 150 151
    if (!dm_task_run(dmt)) {
        goto out;
    }
D
Dave Allan 已提交
152

153 154 155
    if (!dm_task_get_info(dmt, &info)) {
        goto out;
    }
D
Dave Allan 已提交
156

157 158
    *minor = info.minor;
    ret = 0;
D
Dave Allan 已提交
159

160
 out:
161 162
    if (dmt != NULL)
        dm_task_destroy(dmt);
D
Dave Allan 已提交
163

164
    return ret;
D
Dave Allan 已提交
165 166 167 168
}


static int
169
virStorageBackendCreateVols(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
170 171
                            struct dm_names *names)
{
172
    int retval = -1, is_mpath = 0;
D
Dave Allan 已提交
173 174
    char *map_device = NULL;
    uint32_t minor = -1;
175
    uint32_t next;
D
Dave Allan 已提交
176 177 178 179 180 181 182 183 184 185

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

        if (is_mpath < 0) {
            goto out;
        }

        if (is_mpath == 1) {

186
            if (virAsprintf(&map_device, "mapper/%s", names->name) < 0)
D
Dave Allan 已提交
187 188 189
                goto out;

            if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
190 191 192
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to get %s minor number"),
                               names->name);
D
Dave Allan 已提交
193 194 195
                goto out;
            }

196 197 198
            if (virStorageBackendMpathNewVol(pool, minor, map_device) < 0) {
                goto out;
            }
D
Dave Allan 已提交
199 200 201 202 203 204

            VIR_FREE(map_device);
        }

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

210
    } while (next);
D
Dave Allan 已提交
211

212
    retval = 0;
213
 out:
D
Dave Allan 已提交
214 215 216 217 218
    return retval;
}


static int
219
virStorageBackendGetMaps(virStoragePoolObjPtr pool)
D
Dave Allan 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
{
    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;
    }

247
    virStorageBackendCreateVols(pool, names);
D
Dave Allan 已提交
248

249
 out:
D
Dave Allan 已提交
250
    if (dmt != NULL) {
251
        dm_task_destroy(dmt);
D
Dave Allan 已提交
252 253 254 255
    }
    return retval;
}

256 257 258 259 260
static int
virStorageBackendMpathCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                bool *isActive)
{
261
    *isActive = virFileExists("/dev/mpath");
262 263 264 265
    return 0;
}


D
Dave Allan 已提交
266 267

static int
268
virStorageBackendMpathRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
D
Dave Allan 已提交
269 270 271 272
                                  virStoragePoolObjPtr pool)
{
    int retval = 0;

O
Osier Yang 已提交
273
    VIR_DEBUG("conn=%p, pool=%p", conn, pool);
D
Dave Allan 已提交
274 275 276

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

277
    virFileWaitForDevices();
D
Dave Allan 已提交
278

279
    virStorageBackendGetMaps(pool);
D
Dave Allan 已提交
280 281 282 283 284 285 286 287

    return retval;
}


virStorageBackend virStorageBackendMpath = {
    .type = VIR_STORAGE_POOL_MPATH,

288
    .checkPool = virStorageBackendMpathCheckPool,
D
Dave Allan 已提交
289
    .refreshPool = virStorageBackendMpathRefreshPool,
290 291
    .uploadVol = virStorageBackendVolUploadLocal,
    .downloadVol = virStorageBackendVolDownloadLocal,
D
Dave Allan 已提交
292
};