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$"); 32204076Spjd 33204076Spjd#include <errno.h> 34204076Spjd#include <fcntl.h> 35204076Spjd#include <string.h> 36204076Spjd#include <strings.h> 37204076Spjd#include <unistd.h> 38204076Spjd 39204076Spjd#include <ebuf.h> 40204076Spjd#include <nv.h> 41204076Spjd#include <pjdlog.h> 42204076Spjd#include <subr.h> 43204076Spjd 44204076Spjd#include "metadata.h" 45204076Spjd 46204076Spjdint 47204076Spjdmetadata_read(struct hast_resource *res, bool openrw) 48204076Spjd{ 49204076Spjd unsigned char *buf; 50204076Spjd struct ebuf *eb; 51204076Spjd struct nv *nv; 52204076Spjd ssize_t done; 53204076Spjd const char *str; 54204076Spjd int rerrno; 55204076Spjd bool opened_here; 56204076Spjd 57204076Spjd opened_here = false; 58204076Spjd rerrno = 0; 59204076Spjd 60204076Spjd /* 61204076Spjd * Is this first metadata_read() call for this resource? 62204076Spjd */ 63204076Spjd if (res->hr_localfd == -1) { 64231017Strociny if (provinfo(res, openrw) == -1) { 65204076Spjd rerrno = errno; 66204076Spjd goto fail; 67204076Spjd } 68204076Spjd opened_here = true; 69204076Spjd pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath); 70204076Spjd if (openrw) { 71231017Strociny if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) == -1) { 72204076Spjd rerrno = errno; 73204076Spjd if (errno == EOPNOTSUPP) { 74204076Spjd pjdlog_warning("Unable to lock %s (operation not supported), but continuing.", 75204076Spjd res->hr_localpath); 76204076Spjd } else { 77204076Spjd pjdlog_errno(LOG_ERR, 78204076Spjd "Unable to lock %s", 79204076Spjd res->hr_localpath); 80204076Spjd goto fail; 81204076Spjd } 82204076Spjd } 83204076Spjd pjdlog_debug(1, "Locked %s.", res->hr_localpath); 84204076Spjd } 85204076Spjd } 86204076Spjd 87204076Spjd eb = ebuf_alloc(METADATA_SIZE); 88204076Spjd if (eb == NULL) { 89204076Spjd rerrno = errno; 90204076Spjd pjdlog_errno(LOG_ERR, 91204076Spjd "Unable to allocate memory to read metadata"); 92204076Spjd goto fail; 93204076Spjd } 94231017Strociny if (ebuf_add_tail(eb, NULL, METADATA_SIZE) == -1) { 95204076Spjd rerrno = errno; 96204076Spjd pjdlog_errno(LOG_ERR, 97204076Spjd "Unable to allocate memory to read metadata"); 98209179Spjd ebuf_free(eb); 99204076Spjd goto fail; 100204076Spjd } 101204076Spjd buf = ebuf_data(eb, NULL); 102229509Strociny PJDLOG_ASSERT(buf != NULL); 103204076Spjd done = pread(res->hr_localfd, buf, METADATA_SIZE, 0); 104231017Strociny if (done == -1 || 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 } 157209179Spjd nv_free(nv); 158204076Spjd return (0); 159204076Spjdfail: 160204076Spjd if (opened_here) { 161204076Spjd close(res->hr_localfd); 162204076Spjd res->hr_localfd = -1; 163204076Spjd } 164204076Spjd errno = rerrno; 165204076Spjd return (-1); 166204076Spjd} 167204076Spjd 168204076Spjdint 169204076Spjdmetadata_write(struct hast_resource *res) 170204076Spjd{ 171204076Spjd struct ebuf *eb; 172204076Spjd struct nv *nv; 173204076Spjd unsigned char *buf, *ptr; 174204076Spjd size_t size; 175204076Spjd ssize_t done; 176209179Spjd int ret; 177204076Spjd 178204076Spjd buf = calloc(1, METADATA_SIZE); 179204076Spjd if (buf == NULL) { 180204076Spjd pjdlog_error("Unable to allocate %zu bytes for metadata.", 181204076Spjd (size_t)METADATA_SIZE); 182204076Spjd return (-1); 183204076Spjd } 184204076Spjd 185209179Spjd ret = -1; 186209179Spjd 187204076Spjd nv = nv_alloc(); 188204076Spjd nv_add_string(nv, res->hr_name, "resource"); 189204076Spjd nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize"); 190204076Spjd nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize"); 191204076Spjd nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty"); 192204076Spjd nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset"); 193204076Spjd nv_add_uint64(nv, res->hr_resuid, "resuid"); 194204076Spjd if (res->hr_role == HAST_ROLE_PRIMARY || 195204076Spjd res->hr_role == HAST_ROLE_INIT) { 196204076Spjd nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt"); 197204076Spjd nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt"); 198204076Spjd } else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ { 199229509Strociny PJDLOG_ASSERT(res->hr_role == HAST_ROLE_SECONDARY); 200204076Spjd nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt"); 201204076Spjd nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt"); 202204076Spjd } 203204076Spjd nv_add_string(nv, role2str(res->hr_role), "prevrole"); 204204076Spjd if (nv_error(nv) != 0) { 205204076Spjd pjdlog_error("Unable to create metadata."); 206209179Spjd goto end; 207204076Spjd } 208204076Spjd res->hr_previous_role = res->hr_role; 209204076Spjd eb = nv_hton(nv); 210229509Strociny PJDLOG_ASSERT(eb != NULL); 211204076Spjd ptr = ebuf_data(eb, &size); 212229509Strociny PJDLOG_ASSERT(ptr != NULL); 213229509Strociny PJDLOG_ASSERT(size < METADATA_SIZE); 214204076Spjd bcopy(ptr, buf, size); 215204076Spjd done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0); 216231017Strociny if (done == -1 || done != METADATA_SIZE) { 217204076Spjd pjdlog_errno(LOG_ERR, "Unable to write metadata"); 218209179Spjd goto end; 219204076Spjd } 220209179Spjd ret = 0; 221209179Spjdend: 222204076Spjd free(buf); 223204076Spjd nv_free(nv); 224209179Spjd return (ret); 225204076Spjd} 226