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