metadata.c revision 229945
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 229945 2012-01-10 22:39:07Z pjd $");
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) {
64229945Spjd		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) {
71229945Spjd			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	}
94229945Spjd	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);
102225787Spjd	PJDLOG_ASSERT(buf != NULL);
103204076Spjd	done = pread(res->hr_localfd, buf, METADATA_SIZE, 0);
104229945Spjd	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) */ {
199225787Spjd		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);
210225787Spjd	PJDLOG_ASSERT(eb != NULL);
211204076Spjd	ptr = ebuf_data(eb, &size);
212225787Spjd	PJDLOG_ASSERT(ptr != NULL);
213225787Spjd	PJDLOG_ASSERT(size < METADATA_SIZE);
214204076Spjd	bcopy(ptr, buf, size);
215204076Spjd	done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0);
216229945Spjd	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