1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009-2010 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Pawel Jakub Dawidek under sponsorship from 8 * the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <unistd.h> 40 41 #include <ebuf.h> 42 #include <nv.h> 43 #include <pjdlog.h> 44 #include <subr.h> 45 46 #include "metadata.h" 47 48 int 49 metadata_read(struct hast_resource *res, bool openrw) 50 { 51 unsigned char *buf; 52 struct ebuf *eb; 53 struct nv *nv; 54 ssize_t done; 55 const char *str; 56 int rerrno; 57 bool opened_here; 58 59 opened_here = false; 60 rerrno = 0; 61 62 /* 63 * Is this first metadata_read() call for this resource? 64 */ 65 if (res->hr_localfd == -1) { 66 if (provinfo(res, openrw) == -1) { 67 rerrno = errno; 68 goto fail; 69 } 70 opened_here = true; 71 pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath); 72 if (openrw) { 73 if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) == -1) { 74 rerrno = errno; 75 if (errno == EOPNOTSUPP) { 76 pjdlog_warning("Unable to lock %s (operation not supported), but continuing.", 77 res->hr_localpath); 78 } else { 79 pjdlog_errno(LOG_ERR, 80 "Unable to lock %s", 81 res->hr_localpath); 82 goto fail; 83 } 84 } 85 pjdlog_debug(1, "Locked %s.", res->hr_localpath); 86 } 87 } 88 89 eb = ebuf_alloc(METADATA_SIZE); 90 if (eb == NULL) { 91 rerrno = errno; 92 pjdlog_errno(LOG_ERR, 93 "Unable to allocate memory to read metadata"); 94 goto fail; 95 } 96 if (ebuf_add_tail(eb, NULL, METADATA_SIZE) == -1) { 97 rerrno = errno; 98 pjdlog_errno(LOG_ERR, 99 "Unable to allocate memory to read metadata"); 100 ebuf_free(eb); 101 goto fail; 102 } 103 buf = ebuf_data(eb, NULL); 104 PJDLOG_ASSERT(buf != NULL); 105 done = pread(res->hr_localfd, buf, METADATA_SIZE, 0); 106 if (done == -1 || done != METADATA_SIZE) { 107 rerrno = errno; 108 pjdlog_errno(LOG_ERR, "Unable to read metadata"); 109 ebuf_free(eb); 110 goto fail; 111 } 112 nv = nv_ntoh(eb); 113 if (nv == NULL) { 114 rerrno = errno; 115 pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid", 116 res->hr_localpath); 117 ebuf_free(eb); 118 goto fail; 119 } 120 121 str = nv_get_string(nv, "resource"); 122 if (str != NULL && strcmp(str, res->hr_name) != 0) { 123 pjdlog_error("Provider %s is not part of resource %s.", 124 res->hr_localpath, res->hr_name); 125 nv_free(nv); 126 goto fail; 127 } 128 129 res->hr_datasize = nv_get_uint64(nv, "datasize"); 130 res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize"); 131 res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty"); 132 res->hr_localoff = nv_get_uint64(nv, "offset"); 133 res->hr_resuid = nv_get_uint64(nv, "resuid"); 134 if (res->hr_role != HAST_ROLE_PRIMARY) { 135 /* Secondary or init role. */ 136 res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt"); 137 res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt"); 138 } 139 if (res->hr_role != HAST_ROLE_SECONDARY) { 140 /* Primary or init role. */ 141 res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt"); 142 res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt"); 143 } 144 str = nv_get_string(nv, "prevrole"); 145 if (str != NULL) { 146 if (strcmp(str, "primary") == 0) 147 res->hr_previous_role = HAST_ROLE_PRIMARY; 148 else if (strcmp(str, "secondary") == 0) 149 res->hr_previous_role = HAST_ROLE_SECONDARY; 150 } 151 152 if (nv_error(nv) != 0) { 153 errno = rerrno = nv_error(nv); 154 pjdlog_errno(LOG_ERR, "Unable to read metadata from %s", 155 res->hr_localpath); 156 nv_free(nv); 157 goto fail; 158 } 159 nv_free(nv); 160 return (0); 161 fail: 162 if (opened_here) { 163 close(res->hr_localfd); 164 res->hr_localfd = -1; 165 } 166 errno = rerrno; 167 return (-1); 168 } 169 170 int 171 metadata_write(struct hast_resource *res) 172 { 173 struct ebuf *eb; 174 struct nv *nv; 175 unsigned char *buf, *ptr; 176 size_t size; 177 ssize_t done; 178 int ret; 179 180 buf = calloc(1, METADATA_SIZE); 181 if (buf == NULL) { 182 pjdlog_error("Unable to allocate %zu bytes for metadata.", 183 (size_t)METADATA_SIZE); 184 return (-1); 185 } 186 187 ret = -1; 188 189 nv = nv_alloc(); 190 nv_add_string(nv, res->hr_name, "resource"); 191 nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize"); 192 nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize"); 193 nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty"); 194 nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset"); 195 nv_add_uint64(nv, res->hr_resuid, "resuid"); 196 if (res->hr_role == HAST_ROLE_PRIMARY || 197 res->hr_role == HAST_ROLE_INIT) { 198 nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt"); 199 nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt"); 200 } else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ { 201 PJDLOG_ASSERT(res->hr_role == HAST_ROLE_SECONDARY); 202 nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt"); 203 nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt"); 204 } 205 nv_add_string(nv, role2str(res->hr_role), "prevrole"); 206 if (nv_error(nv) != 0) { 207 pjdlog_error("Unable to create metadata."); 208 goto end; 209 } 210 res->hr_previous_role = res->hr_role; 211 eb = nv_hton(nv); 212 PJDLOG_ASSERT(eb != NULL); 213 ptr = ebuf_data(eb, &size); 214 PJDLOG_ASSERT(ptr != NULL); 215 PJDLOG_ASSERT(size < METADATA_SIZE); 216 bcopy(ptr, buf, size); 217 done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0); 218 if (done == -1 || done != METADATA_SIZE) { 219 pjdlog_errno(LOG_ERR, "Unable to write metadata"); 220 goto end; 221 } 222 ret = 0; 223 end: 224 free(buf); 225 nv_free(nv); 226 return (ret); 227 } 228