metadata.c revision 207343
1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/metadata.c 207343 2010-04-28 22:23:29Z pjd $"); 32204076Spjd 33204076Spjd#include <assert.h> 34204076Spjd#include <errno.h> 35204076Spjd#include <fcntl.h> 36204076Spjd#include <string.h> 37204076Spjd#include <strings.h> 38204076Spjd#include <unistd.h> 39204076Spjd 40204076Spjd#include <ebuf.h> 41204076Spjd#include <nv.h> 42204076Spjd#include <pjdlog.h> 43204076Spjd#include <subr.h> 44204076Spjd 45204076Spjd#include "metadata.h" 46204076Spjd 47204076Spjdint 48204076Spjdmetadata_read(struct hast_resource *res, bool openrw) 49204076Spjd{ 50204076Spjd unsigned char *buf; 51204076Spjd struct ebuf *eb; 52204076Spjd struct nv *nv; 53204076Spjd ssize_t done; 54204076Spjd const char *str; 55204076Spjd int rerrno; 56204076Spjd bool opened_here; 57204076Spjd 58204076Spjd opened_here = false; 59204076Spjd rerrno = 0; 60204076Spjd 61204076Spjd /* 62204076Spjd * Is this first metadata_read() call for this resource? 63204076Spjd */ 64204076Spjd if (res->hr_localfd == -1) { 65204076Spjd if (provinfo(res, openrw) < 0) { 66204076Spjd rerrno = errno; 67204076Spjd goto fail; 68204076Spjd } 69204076Spjd opened_here = true; 70204076Spjd pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath); 71204076Spjd if (openrw) { 72204076Spjd if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) < 0) { 73204076Spjd rerrno = errno; 74204076Spjd if (errno == EOPNOTSUPP) { 75204076Spjd pjdlog_warning("Unable to lock %s (operation not supported), but continuing.", 76204076Spjd res->hr_localpath); 77204076Spjd } else { 78204076Spjd pjdlog_errno(LOG_ERR, 79204076Spjd "Unable to lock %s", 80204076Spjd res->hr_localpath); 81204076Spjd goto fail; 82204076Spjd } 83204076Spjd } 84204076Spjd pjdlog_debug(1, "Locked %s.", res->hr_localpath); 85204076Spjd } 86204076Spjd } 87204076Spjd 88204076Spjd eb = ebuf_alloc(METADATA_SIZE); 89204076Spjd if (eb == NULL) { 90204076Spjd rerrno = errno; 91204076Spjd pjdlog_errno(LOG_ERR, 92204076Spjd "Unable to allocate memory to read metadata"); 93204076Spjd goto fail; 94204076Spjd } 95204076Spjd if (ebuf_add_tail(eb, NULL, METADATA_SIZE) < 0) { 96204076Spjd rerrno = errno; 97204076Spjd pjdlog_errno(LOG_ERR, 98204076Spjd "Unable to allocate memory to read metadata"); 99204076Spjd goto fail; 100204076Spjd } 101204076Spjd buf = ebuf_data(eb, NULL); 102204076Spjd assert(buf != NULL); 103204076Spjd done = pread(res->hr_localfd, buf, METADATA_SIZE, 0); 104204076Spjd if (done < 0 || done != METADATA_SIZE) { 105204076Spjd rerrno = errno; 106204076Spjd pjdlog_errno(LOG_ERR, "Unable to read metadata"); 107204076Spjd ebuf_free(eb); 108204076Spjd goto fail; 109204076Spjd } 110204076Spjd nv = nv_ntoh(eb); 111204076Spjd if (nv == NULL) { 112204076Spjd rerrno = errno; 113204076Spjd pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid", 114204076Spjd res->hr_localpath); 115204076Spjd ebuf_free(eb); 116204076Spjd goto fail; 117204076Spjd } 118204076Spjd 119204076Spjd str = nv_get_string(nv, "resource"); 120207343Spjd if (str != NULL && strcmp(str, res->hr_name) != 0) { 121204076Spjd pjdlog_error("Provider %s is not part of resource %s.", 122204076Spjd res->hr_localpath, res->hr_name); 123204076Spjd nv_free(nv); 124204076Spjd goto fail; 125204076Spjd } 126204076Spjd 127204076Spjd res->hr_datasize = nv_get_uint64(nv, "datasize"); 128204076Spjd res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize"); 129204076Spjd res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty"); 130204076Spjd res->hr_localoff = nv_get_uint64(nv, "offset"); 131204076Spjd res->hr_resuid = nv_get_uint64(nv, "resuid"); 132204076Spjd if (res->hr_role != HAST_ROLE_PRIMARY) { 133204076Spjd /* Secondary or init role. */ 134204076Spjd res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt"); 135204076Spjd res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt"); 136204076Spjd } 137204076Spjd if (res->hr_role != HAST_ROLE_SECONDARY) { 138204076Spjd /* Primary or init role. */ 139204076Spjd res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt"); 140204076Spjd res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt"); 141204076Spjd } 142204076Spjd str = nv_get_string(nv, "prevrole"); 143204076Spjd if (str != NULL) { 144204076Spjd if (strcmp(str, "primary") == 0) 145204076Spjd res->hr_previous_role = HAST_ROLE_PRIMARY; 146204076Spjd else if (strcmp(str, "secondary") == 0) 147204076Spjd res->hr_previous_role = HAST_ROLE_SECONDARY; 148204076Spjd } 149204076Spjd 150204076Spjd if (nv_error(nv) != 0) { 151204076Spjd errno = rerrno = nv_error(nv); 152204076Spjd pjdlog_errno(LOG_ERR, "Unable to read metadata from %s", 153204076Spjd res->hr_localpath); 154204076Spjd nv_free(nv); 155204076Spjd goto fail; 156204076Spjd } 157204076Spjd return (0); 158204076Spjdfail: 159204076Spjd if (opened_here) { 160204076Spjd close(res->hr_localfd); 161204076Spjd res->hr_localfd = -1; 162204076Spjd } 163204076Spjd errno = rerrno; 164204076Spjd return (-1); 165204076Spjd} 166204076Spjd 167204076Spjdint 168204076Spjdmetadata_write(struct hast_resource *res) 169204076Spjd{ 170204076Spjd struct ebuf *eb; 171204076Spjd struct nv *nv; 172204076Spjd unsigned char *buf, *ptr; 173204076Spjd size_t size; 174204076Spjd ssize_t done; 175204076Spjd 176204076Spjd buf = calloc(1, METADATA_SIZE); 177204076Spjd if (buf == NULL) { 178204076Spjd pjdlog_error("Unable to allocate %zu bytes for metadata.", 179204076Spjd (size_t)METADATA_SIZE); 180204076Spjd return (-1); 181204076Spjd } 182204076Spjd 183204076Spjd nv = nv_alloc(); 184204076Spjd nv_add_string(nv, res->hr_name, "resource"); 185204076Spjd nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize"); 186204076Spjd nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize"); 187204076Spjd nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty"); 188204076Spjd nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset"); 189204076Spjd nv_add_uint64(nv, res->hr_resuid, "resuid"); 190204076Spjd if (res->hr_role == HAST_ROLE_PRIMARY || 191204076Spjd res->hr_role == HAST_ROLE_INIT) { 192204076Spjd nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt"); 193204076Spjd nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt"); 194204076Spjd } else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ { 195204076Spjd assert(res->hr_role == HAST_ROLE_SECONDARY); 196204076Spjd nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt"); 197204076Spjd nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt"); 198204076Spjd } 199204076Spjd nv_add_string(nv, role2str(res->hr_role), "prevrole"); 200204076Spjd if (nv_error(nv) != 0) { 201204076Spjd pjdlog_error("Unable to create metadata."); 202204076Spjd goto fail; 203204076Spjd } 204204076Spjd res->hr_previous_role = res->hr_role; 205204076Spjd eb = nv_hton(nv); 206204076Spjd assert(eb != NULL); 207204076Spjd ptr = ebuf_data(eb, &size); 208204076Spjd assert(ptr != NULL); 209204076Spjd assert(size < METADATA_SIZE); 210204076Spjd bcopy(ptr, buf, size); 211204076Spjd done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0); 212204076Spjd if (done < 0 || done != METADATA_SIZE) { 213204076Spjd pjdlog_errno(LOG_ERR, "Unable to write metadata"); 214204076Spjd goto fail; 215204076Spjd } 216204076Spjd 217204076Spjd return (0); 218204076Spjdfail: 219204076Spjd free(buf); 220204076Spjd nv_free(nv); 221204076Spjd return (-1); 222204076Spjd} 223