storage_backend_mpath.c 7.1 KB
Newer Older
D
Dave Allan 已提交
1 2 3
/*
 * storage_backend_mpath.c: storage backend for multipath handling
 *
4
 * Copyright (C) 2009-2010 Red Hat, Inc.
D
Dave Allan 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Dave Allan <dallan@redhat.com>
 */

#include <config.h>

#include <unistd.h>
#include <stdio.h>
#include <dirent.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"

#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;
D
Dave Allan 已提交
47 48 49
    int fd = -1;

    if ((fd = open(target->path, O_RDONLY)) < 0) {
50
        virReportSystemError(errno,
D
Dave Allan 已提交
51 52 53 54 55
                             _("cannot open volume '%s'"),
                             target->path);
        goto out;
    }

56
    if (virStorageBackendUpdateVolTargetInfoFD(target,
D
Dave Allan 已提交
57 58
                                               fd,
                                               allocation,
59
                                               capacity) < 0)
D
Dave Allan 已提交
60 61
        goto out;

62
    if (virStorageBackendDetectBlockVolFormatFD(target, fd) < 0)
D
Dave Allan 已提交
63 64
        goto out;

65
    ret = 0;
D
Dave Allan 已提交
66 67 68 69 70 71 72 73 74
out:
    if (fd != -1) {
        close(fd);
    }
    return ret;
}


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

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

    vol->type = VIR_STORAGE_VOL_BLOCK;

    if (virAsprintf(&(vol->name), "dm-%u", devnum) < 0) {
90
        virReportOOMError();
D
Dave Allan 已提交
91 92 93 94
        goto cleanup;
    }

    if (virAsprintf(&vol->target.path, "/dev/%s", dev) < 0) {
95
        virReportOOMError();
D
Dave Allan 已提交
96 97 98
        goto cleanup;
    }

99
    if (virStorageBackendMpathUpdateVolTargetInfo(&vol->target,
D
Dave Allan 已提交
100 101 102 103 104 105 106 107
                                                  &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) {
108
        virReportOOMError();
D
Dave Allan 已提交
109 110 111 112 113
        goto cleanup;
    }

    if (VIR_REALLOC_N(pool->volumes.objs,
                      pool->volumes.count + 1) < 0) {
114
        virReportOOMError();
D
Dave Allan 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
        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
virStorageBackendIsMultipath(const char *devname)
{
    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;
    }

    if (dm_task_set_name(dmt, devname) == 0) {
        ret = -1;
        goto out;
    }

    dm_task_no_open_count(dmt);

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

159
    dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
D
Dave Allan 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

    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
virStorageBackendGetMinorNumber(const char *devname, uint32_t *minor)
{
181 182 183
    int ret = -1;
    struct dm_task *dmt;
    struct dm_info info;
D
Dave Allan 已提交
184

185 186 187
    if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
        goto out;
    }
D
Dave Allan 已提交
188

189 190 191
    if (!dm_task_set_name(dmt, devname)) {
        goto out;
    }
D
Dave Allan 已提交
192

193 194 195
    if (!dm_task_run(dmt)) {
        goto out;
    }
D
Dave Allan 已提交
196

197 198 199
    if (!dm_task_get_info(dmt, &info)) {
        goto out;
    }
D
Dave Allan 已提交
200

201 202
    *minor = info.minor;
    ret = 0;
D
Dave Allan 已提交
203 204

out:
205 206
    if (dmt != NULL)
        dm_task_destroy(dmt);
D
Dave Allan 已提交
207

208
    return ret;
D
Dave Allan 已提交
209 210 211 212
}


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

    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) {
230
                virReportOOMError();
D
Dave Allan 已提交
231 232 233 234
                goto out;
            }

            if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
235 236 237
                virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                      _("Failed to get %s minor number"),
                                      names->name);
D
Dave Allan 已提交
238 239 240
                goto out;
            }

241 242 243
            if (virStorageBackendMpathNewVol(pool, minor, map_device) < 0) {
                goto out;
            }
D
Dave Allan 已提交
244 245 246 247 248 249 250 251 252 253

            VIR_FREE(map_device);
        }

        /* Given the way libdevmapper returns its data, I don't see
         * any way to avoid this series of casts. */
        names = (struct dm_names *)(((char *)names) + names->next);

    } while (names->next);

254
    retval = 0;
D
Dave Allan 已提交
255 256 257 258 259 260
out:
    return retval;
}


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

289
    virStorageBackendCreateVols(pool, names);
D
Dave Allan 已提交
290 291 292 293 294 295 296 297 298 299

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


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

305
    VIR_DEBUG("in %s", __func__);
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 320 321

    return retval;
}


virStorageBackend virStorageBackendMpath = {
    .type = VIR_STORAGE_POOL_MPATH,

    .refreshPool = virStorageBackendMpathRefreshPool,
};