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 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 32 33 34 35 36
 *
 * Author: Dave Allan <dallan@redhat.com>
 */

#include <config.h>

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

#include <libdevmapper.h>

#include "virterror_internal.h"
#include "storage_conf.h"
#include "storage_backend.h"
#include "memory.h"
#include "logging.h"
E
Eric Blake 已提交
37
#include "virfile.h"
D
Dave Allan 已提交
38 39 40 41

#define VIR_FROM_THIS VIR_FROM_STORAGE

static int
42
virStorageBackendMpathUpdateVolTargetInfo(virStorageVolTargetPtr target,
D
Dave Allan 已提交
43 44 45
                                          unsigned long long *allocation,
                                          unsigned long long *capacity)
{
46
    int ret = -1;
47
    int fdret, fd = -1;
D
Dave Allan 已提交
48

49
    if ((fdret = virStorageBackendVolOpen(target->path)) < 0)
D
Dave Allan 已提交
50
        goto out;
51
    fd = fdret;
D
Dave Allan 已提交
52

53
    if (virStorageBackendUpdateVolTargetInfoFD(target,
D
Dave Allan 已提交
54 55
                                               fd,
                                               allocation,
56
                                               capacity) < 0)
D
Dave Allan 已提交
57 58
        goto out;

59
    if (virStorageBackendDetectBlockVolFormatFD(target, fd) < 0)
D
Dave Allan 已提交
60 61
        goto out;

62
    ret = 0;
D
Dave Allan 已提交
63
out:
64
    VIR_FORCE_CLOSE(fd);
D
Dave Allan 已提交
65 66 67 68 69
    return ret;
}


static int
70
virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
71 72 73 74 75 76 77
                             const int devnum,
                             const char *dev)
{
    virStorageVolDefPtr vol;
    int ret = -1;

    if (VIR_ALLOC(vol) < 0) {
78
        virReportOOMError();
D
Dave Allan 已提交
79 80 81 82 83 84
        goto cleanup;
    }

    vol->type = VIR_STORAGE_VOL_BLOCK;

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

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

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

    /* XXX should use logical unit's UUID instead */
    vol->key = strdup(vol->target.path);
    if (vol->key == NULL) {
103
        virReportOOMError();
D
Dave Allan 已提交
104 105 106 107 108
        goto cleanup;
    }

    if (VIR_REALLOC_N(pool->volumes.objs,
                      pool->volumes.count + 1) < 0) {
109
        virReportOOMError();
D
Dave Allan 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
        goto cleanup;
    }
    pool->volumes.objs[pool->volumes.count++] = vol;
    pool->def->capacity += vol->capacity;
    pool->def->allocation += vol->allocation;
    ret = 0;

cleanup:

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

    return ret;
}


static int
127
virStorageBackendIsMultipath(const char *dev_name)
D
Dave Allan 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
    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;
    }

142
    if (dm_task_set_name(dmt, dev_name) == 0) {
D
Dave Allan 已提交
143 144 145 146 147 148 149 150 151 152 153
        ret = -1;
        goto out;
    }

    dm_task_no_open_count(dmt);

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

154
    dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
D
Dave Allan 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

    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
174
virStorageBackendGetMinorNumber(const char *dev_name, uint32_t *minor)
D
Dave Allan 已提交
175
{
176 177 178
    int ret = -1;
    struct dm_task *dmt;
    struct dm_info info;
D
Dave Allan 已提交
179

180 181 182
    if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
        goto out;
    }
D
Dave Allan 已提交
183

184
    if (!dm_task_set_name(dmt, dev_name)) {
185 186
        goto out;
    }
D
Dave Allan 已提交
187

188 189 190
    if (!dm_task_run(dmt)) {
        goto out;
    }
D
Dave Allan 已提交
191

192 193 194
    if (!dm_task_get_info(dmt, &info)) {
        goto out;
    }
D
Dave Allan 已提交
195

196 197
    *minor = info.minor;
    ret = 0;
D
Dave Allan 已提交
198 199

out:
200 201
    if (dmt != NULL)
        dm_task_destroy(dmt);
D
Dave Allan 已提交
202

203
    return ret;
D
Dave Allan 已提交
204 205 206 207
}


static int
208
virStorageBackendCreateVols(virStoragePoolObjPtr pool,
D
Dave Allan 已提交
209 210
                            struct dm_names *names)
{
211
    int retval = -1, is_mpath = 0;
D
Dave Allan 已提交
212 213
    char *map_device = NULL;
    uint32_t minor = -1;
214
    uint32_t next;
D
Dave Allan 已提交
215 216 217 218 219 220 221 222 223 224 225

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

        if (is_mpath < 0) {
            goto out;
        }

        if (is_mpath == 1) {

            if (virAsprintf(&map_device, "mapper/%s", names->name) < 0) {
226
                virReportOOMError();
D
Dave Allan 已提交
227 228 229 230
                goto out;
            }

            if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
231 232 233
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to get %s minor number"),
                               names->name);
D
Dave Allan 已提交
234 235 236
                goto out;
            }

237 238 239
            if (virStorageBackendMpathNewVol(pool, minor, map_device) < 0) {
                goto out;
            }
D
Dave Allan 已提交
240 241 242 243 244 245

            VIR_FREE(map_device);
        }

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

249
    } while (next);
D
Dave Allan 已提交
250

251
    retval = 0;
D
Dave Allan 已提交
252 253 254 255 256 257
out:
    return retval;
}


static int
258
virStorageBackendGetMaps(virStoragePoolObjPtr pool)
D
Dave Allan 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
{
    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;
    }

286
    virStorageBackendCreateVols(pool, names);
D
Dave Allan 已提交
287 288 289

out:
    if (dmt != NULL) {
290
        dm_task_destroy(dmt);
D
Dave Allan 已提交
291 292 293 294
    }
    return retval;
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
static int
virStorageBackendMpathCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                bool *isActive)
{
    const char *path = "/dev/mpath";

    *isActive = false;

    if (access(path, F_OK) == 0)
        *isActive = true;

    return 0;
}


D
Dave Allan 已提交
311 312

static int
313
virStorageBackendMpathRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
D
Dave Allan 已提交
314 315 316 317
                                  virStoragePoolObjPtr pool)
{
    int retval = 0;

O
Osier Yang 已提交
318
    VIR_DEBUG("conn=%p, pool=%p", conn, pool);
D
Dave Allan 已提交
319 320 321

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

322
    virFileWaitForDevices();
D
Dave Allan 已提交
323

324
    virStorageBackendGetMaps(pool);
D
Dave Allan 已提交
325 326 327 328 329 330 331 332

    return retval;
}


virStorageBackend virStorageBackendMpath = {
    .type = VIR_STORAGE_POOL_MPATH,

333
    .checkPool = virStorageBackendMpathCheckPool,
D
Dave Allan 已提交
334 335
    .refreshPool = virStorageBackendMpathRefreshPool,
};