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