1 /* $NetBSD: lvm_vg.c,v 1.1.1.1 2009/12/02 00:26:15 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2008,2009 Red Hat, Inc. All rights reserved. 5 * 6 * This file is part of LVM2. 7 * 8 * This copyrighted material is made available to anyone wishing to use, 9 * modify, copy, or redistribute it subject to the terms and conditions 10 * of the GNU Lesser General Public License v.2.1. 11 * 12 * You should have received a copy of the GNU Lesser General Public License 13 * along with this program; if not, write to the Free Software Foundation, 14 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 */ 16 17 #include "lib.h" 18 #include "lvm2app.h" 19 #include "toolcontext.h" 20 #include "metadata-exported.h" 21 #include "archiver.h" 22 #include "locking.h" 23 #include "lvm-string.h" 24 #include "lvmcache.h" 25 #include "metadata.h" 26 27 #include <errno.h> 28 #include <string.h> 29 30 vg_t lvm_vg_create(lvm_t libh, const char *vg_name) 31 { 32 struct volume_group *vg; 33 34 vg = vg_create((struct cmd_context *)libh, vg_name); 35 /* FIXME: error handling is still TBD */ 36 if (vg_read_error(vg)) { 37 vg_release(vg); 38 return NULL; 39 } 40 vg->open_mode = 'w'; 41 return (vg_t) vg; 42 } 43 44 int lvm_vg_extend(vg_t vg, const char *device) 45 { 46 struct pvcreate_params pp; 47 48 if (vg_read_error(vg)) 49 return -1; 50 51 if (!vg_check_write_mode(vg)) 52 return -1; 53 54 if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) { 55 log_error("Can't get lock for orphan PVs"); 56 return -1; 57 } 58 59 pvcreate_params_set_defaults(&pp); 60 if (!vg_extend(vg, 1, (char **) &device, &pp)) { 61 unlock_vg(vg->cmd, VG_ORPHANS); 62 return -1; 63 } 64 /* 65 * FIXME: Either commit to disk, or keep holding VG_ORPHANS and 66 * release in lvm_vg_close(). 67 */ 68 unlock_vg(vg->cmd, VG_ORPHANS); 69 return 0; 70 } 71 72 int lvm_vg_reduce(vg_t vg, const char *device) 73 { 74 if (vg_read_error(vg)) 75 return -1; 76 if (!vg_check_write_mode(vg)) 77 return -1; 78 79 if (!vg_reduce(vg, (char *)device)) 80 return -1; 81 return 0; 82 } 83 84 int lvm_vg_set_extent_size(vg_t vg, uint32_t new_size) 85 { 86 if (vg_read_error(vg)) 87 return -1; 88 if (!vg_check_write_mode(vg)) 89 return -1; 90 91 if (!vg_set_extent_size(vg, new_size)) 92 return -1; 93 return 0; 94 } 95 96 int lvm_vg_write(vg_t vg) 97 { 98 struct pv_list *pvl; 99 100 if (vg_read_error(vg)) 101 return -1; 102 if (!vg_check_write_mode(vg)) 103 return -1; 104 105 if (dm_list_empty(&vg->pvs)) { 106 if (!vg_remove(vg)) 107 return -1; 108 return 0; 109 } 110 111 if (! dm_list_empty(&vg->removed_pvs)) { 112 if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) { 113 log_error("Can't get lock for orphan PVs"); 114 return 0; 115 } 116 } 117 118 if (!archive(vg)) 119 return -1; 120 121 /* Store VG on disk(s) */ 122 if (!vg_write(vg) || !vg_commit(vg)) 123 return -1; 124 125 if (! dm_list_empty(&vg->removed_pvs)) { 126 dm_list_iterate_items(pvl, &vg->removed_pvs) { 127 pv_write_orphan(vg->cmd, pvl->pv); 128 /* FIXME: do pvremove / label_remove()? */ 129 } 130 dm_list_init(&vg->removed_pvs); 131 unlock_vg(vg->cmd, VG_ORPHANS); 132 } 133 134 return 0; 135 } 136 137 int lvm_vg_close(vg_t vg) 138 { 139 if (vg_read_error(vg) == FAILED_LOCKING) 140 vg_release(vg); 141 else 142 unlock_and_release_vg(vg->cmd, vg, vg->name); 143 return 0; 144 } 145 146 int lvm_vg_remove(vg_t vg) 147 { 148 if (vg_read_error(vg)) 149 return -1; 150 if (!vg_check_write_mode(vg)) 151 return -1; 152 153 if (!vg_remove_check(vg)) 154 return -1; 155 156 return 0; 157 } 158 159 vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode, 160 uint32_t flags) 161 { 162 uint32_t internal_flags = 0; 163 struct volume_group *vg; 164 165 if (!strncmp(mode, "w", 1)) 166 internal_flags |= READ_FOR_UPDATE; 167 else if (strncmp(mode, "r", 1)) { 168 log_errno(EINVAL, "Invalid VG open mode"); 169 return NULL; 170 } 171 172 vg = vg_read((struct cmd_context *)libh, vgname, NULL, internal_flags); 173 if (vg_read_error(vg)) { 174 /* FIXME: use log_errno either here in inside vg_read */ 175 vg_release(vg); 176 return NULL; 177 } 178 /* FIXME: combine this with locking ? */ 179 vg->open_mode = mode[0]; 180 181 return (vg_t) vg; 182 } 183 184 struct dm_list *lvm_vg_list_pvs(vg_t vg) 185 { 186 struct dm_list *list; 187 pv_list_t *pvs; 188 struct pv_list *pvl; 189 190 if (dm_list_empty(&vg->pvs)) 191 return NULL; 192 193 if (!(list = dm_pool_zalloc(vg->vgmem, sizeof(*list)))) { 194 log_errno(ENOMEM, "Memory allocation fail for dm_list."); 195 return NULL; 196 } 197 dm_list_init(list); 198 199 dm_list_iterate_items(pvl, &vg->pvs) { 200 if (!(pvs = dm_pool_zalloc(vg->vgmem, sizeof(*pvs)))) { 201 log_errno(ENOMEM, 202 "Memory allocation fail for lvm_pv_list."); 203 return NULL; 204 } 205 pvs->pv = pvl->pv; 206 dm_list_add(list, &pvs->list); 207 } 208 return list; 209 } 210 211 struct dm_list *lvm_vg_list_lvs(vg_t vg) 212 { 213 struct dm_list *list; 214 lv_list_t *lvs; 215 struct lv_list *lvl; 216 217 if (dm_list_empty(&vg->lvs)) 218 return NULL; 219 220 if (!(list = dm_pool_zalloc(vg->vgmem, sizeof(*list)))) { 221 log_errno(ENOMEM, "Memory allocation fail for dm_list."); 222 return NULL; 223 } 224 dm_list_init(list); 225 226 dm_list_iterate_items(lvl, &vg->lvs) { 227 if (!(lvs = dm_pool_zalloc(vg->vgmem, sizeof(*lvs)))) { 228 log_errno(ENOMEM, 229 "Memory allocation fail for lvm_lv_list."); 230 return NULL; 231 } 232 lvs->lv = lvl->lv; 233 dm_list_add(list, &lvs->list); 234 } 235 return list; 236 } 237 238 uint64_t lvm_vg_get_seqno(const vg_t vg) 239 { 240 return vg_seqno(vg); 241 } 242 243 uint64_t lvm_vg_is_clustered(const vg_t vg) 244 { 245 return vg_is_clustered(vg); 246 } 247 248 uint64_t lvm_vg_is_exported(const vg_t vg) 249 { 250 return vg_is_exported(vg); 251 } 252 253 uint64_t lvm_vg_is_partial(const vg_t vg) 254 { 255 return (vg_missing_pv_count(vg) != 0); 256 } 257 258 /* FIXME: invalid handle? return INTMAX? */ 259 uint64_t lvm_vg_get_size(const vg_t vg) 260 { 261 return vg_size(vg); 262 } 263 264 uint64_t lvm_vg_get_free_size(const vg_t vg) 265 { 266 return vg_free(vg); 267 } 268 269 uint64_t lvm_vg_get_extent_size(const vg_t vg) 270 { 271 return vg_extent_size(vg); 272 } 273 274 uint64_t lvm_vg_get_extent_count(const vg_t vg) 275 { 276 return vg_extent_count(vg); 277 } 278 279 uint64_t lvm_vg_get_free_extent_count(const vg_t vg) 280 { 281 return vg_free_count(vg); 282 } 283 284 uint64_t lvm_vg_get_pv_count(const vg_t vg) 285 { 286 return vg_pv_count(vg); 287 } 288 289 uint64_t lvm_vg_get_max_pv(const vg_t vg) 290 { 291 return vg_max_pv(vg); 292 } 293 294 uint64_t lvm_vg_get_max_lv(const vg_t vg) 295 { 296 return vg_max_lv(vg); 297 } 298 299 char *lvm_vg_get_uuid(const vg_t vg) 300 { 301 char uuid[64] __attribute((aligned(8))); 302 303 if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { 304 log_error("Internal error converting uuid"); 305 return NULL; 306 } 307 return strndup((const char *)uuid, 64); 308 } 309 310 char *lvm_vg_get_name(const vg_t vg) 311 { 312 char *name; 313 314 name = dm_malloc(NAME_LEN + 1); 315 strncpy(name, (const char *)vg->name, NAME_LEN); 316 name[NAME_LEN] = '\0'; 317 return name; 318 } 319 320 /* 321 * FIXME: These functions currently return hidden VGs. We should either filter 322 * these out and not return them in the list, or export something like 323 * is_orphan_vg and tell the caller to filter. 324 */ 325 struct dm_list *lvm_list_vg_names(lvm_t libh) 326 { 327 return get_vgnames((struct cmd_context *)libh, 0); 328 } 329 330 struct dm_list *lvm_list_vg_uuids(lvm_t libh) 331 { 332 return get_vgids((struct cmd_context *)libh, 0); 333 } 334 335 /* 336 * FIXME: Elaborate on when to use, side-effects, .cache file, etc 337 */ 338 int lvm_scan(lvm_t libh) 339 { 340 if (!lvmcache_label_scan((struct cmd_context *)libh, 2)) 341 return -1; 342 return 0; 343 } 344