metadata.c revision 225787
1132332Smarcel/*-
2132332Smarcel * Copyright (c) 2009-2010 The FreeBSD Foundation
3132332Smarcel * All rights reserved.
4132332Smarcel *
5132332Smarcel * This software was developed by Pawel Jakub Dawidek under sponsorship from
6132332Smarcel * the FreeBSD Foundation.
7132332Smarcel *
8132332Smarcel * Redistribution and use in source and binary forms, with or without
9132332Smarcel * modification, are permitted provided that the following conditions
10132332Smarcel * are met:
11132332Smarcel * 1. Redistributions of source code must retain the above copyright
12132332Smarcel *    notice, this list of conditions and the following disclaimer.
13132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright
14132332Smarcel *    notice, this list of conditions and the following disclaimer in the
15132332Smarcel *    documentation and/or other materials provided with the distribution.
16132332Smarcel *
17132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20132332Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26132332Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27132332Smarcel * SUCH DAMAGE.
28132332Smarcel */
29132332Smarcel
30132332Smarcel#include <sys/cdefs.h>
31132332Smarcel__FBSDID("$FreeBSD: head/sbin/hastd/metadata.c 225787 2011-09-27 08:50:37Z pjd $");
32132332Smarcel
33132332Smarcel#include <errno.h>
34177490Sdavidxu#include <fcntl.h>
35181065Smarcel#include <string.h>
36181065Smarcel#include <strings.h>
37177490Sdavidxu#include <unistd.h>
38132332Smarcel
39132332Smarcel#include <ebuf.h>
40132332Smarcel#include <nv.h>
41132332Smarcel#include <pjdlog.h>
42132332Smarcel#include <subr.h>
43132332Smarcel
44132332Smarcel#include "metadata.h"
45132332Smarcel
46132332Smarcelint
47132332Smarcelmetadata_read(struct hast_resource *res, bool openrw)
48177490Sdavidxu{
49132332Smarcel	unsigned char *buf;
50132332Smarcel	struct ebuf *eb;
51132332Smarcel	struct nv *nv;
52132332Smarcel	ssize_t done;
53132332Smarcel	const char *str;
54177490Sdavidxu	int rerrno;
55132332Smarcel	bool opened_here;
56132332Smarcel
57177490Sdavidxu	opened_here = false;
58177490Sdavidxu	rerrno = 0;
59177490Sdavidxu
60177490Sdavidxu	/*
61132332Smarcel	 * Is this first metadata_read() call for this resource?
62132332Smarcel	 */
63132332Smarcel	if (res->hr_localfd == -1) {
64132332Smarcel		if (provinfo(res, openrw) < 0) {
65132332Smarcel			rerrno = errno;
66132332Smarcel			goto fail;
67132332Smarcel		}
68132332Smarcel		opened_here = true;
69132332Smarcel		pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath);
70132332Smarcel		if (openrw) {
71132332Smarcel			if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) < 0) {
72132332Smarcel				rerrno = errno;
73132332Smarcel				if (errno == EOPNOTSUPP) {
74132332Smarcel					pjdlog_warning("Unable to lock %s (operation not supported), but continuing.",
75132332Smarcel					    res->hr_localpath);
76132332Smarcel				} else {
77132332Smarcel					pjdlog_errno(LOG_ERR,
78132332Smarcel					    "Unable to lock %s",
79132332Smarcel					    res->hr_localpath);
80132332Smarcel					goto fail;
81132332Smarcel				}
82132332Smarcel			}
83132332Smarcel			pjdlog_debug(1, "Locked %s.", res->hr_localpath);
84132332Smarcel		}
85132332Smarcel	}
86132332Smarcel
87132332Smarcel	eb = ebuf_alloc(METADATA_SIZE);
88132332Smarcel	if (eb == NULL) {
89132332Smarcel		rerrno = errno;
90132332Smarcel		pjdlog_errno(LOG_ERR,
91132332Smarcel		    "Unable to allocate memory to read metadata");
92132332Smarcel		goto fail;
93132332Smarcel	}
94132332Smarcel	if (ebuf_add_tail(eb, NULL, METADATA_SIZE) < 0) {
95132332Smarcel		rerrno = errno;
96132332Smarcel		pjdlog_errno(LOG_ERR,
97132332Smarcel		    "Unable to allocate memory to read metadata");
98132332Smarcel		ebuf_free(eb);
99132332Smarcel		goto fail;
100132332Smarcel	}
101132332Smarcel	buf = ebuf_data(eb, NULL);
102132332Smarcel	PJDLOG_ASSERT(buf != NULL);
103132332Smarcel	done = pread(res->hr_localfd, buf, METADATA_SIZE, 0);
104132332Smarcel	if (done < 0 || done != METADATA_SIZE) {
105132332Smarcel		rerrno = errno;
106132332Smarcel		pjdlog_errno(LOG_ERR, "Unable to read metadata");
107132332Smarcel		ebuf_free(eb);
108177490Sdavidxu		goto fail;
109132332Smarcel	}
110177490Sdavidxu	nv = nv_ntoh(eb);
111177490Sdavidxu	if (nv == NULL) {
112177490Sdavidxu		rerrno = errno;
113132332Smarcel		pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid",
114177490Sdavidxu		    res->hr_localpath);
115132332Smarcel		ebuf_free(eb);
116132332Smarcel		goto fail;
117132332Smarcel	}
118132332Smarcel
119132332Smarcel	str = nv_get_string(nv, "resource");
120132332Smarcel	if (str != NULL && strcmp(str, res->hr_name) != 0) {
121132332Smarcel		pjdlog_error("Provider %s is not part of resource %s.",
122132332Smarcel		    res->hr_localpath, res->hr_name);
123132332Smarcel		nv_free(nv);
124132332Smarcel		goto fail;
125132332Smarcel	}
126132332Smarcel
127132332Smarcel	res->hr_datasize = nv_get_uint64(nv, "datasize");
128132332Smarcel	res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize");
129132332Smarcel	res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty");
130132332Smarcel	res->hr_localoff = nv_get_uint64(nv, "offset");
131132332Smarcel	res->hr_resuid = nv_get_uint64(nv, "resuid");
132132332Smarcel	if (res->hr_role != HAST_ROLE_PRIMARY) {
133132332Smarcel		/* Secondary or init role. */
134132332Smarcel		res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt");
135132332Smarcel		res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt");
136132332Smarcel	}
137132332Smarcel	if (res->hr_role != HAST_ROLE_SECONDARY) {
138132332Smarcel		/* Primary or init role. */
139132332Smarcel		res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt");
140132332Smarcel		res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt");
141132332Smarcel	}
142132332Smarcel	str = nv_get_string(nv, "prevrole");
143132332Smarcel	if (str != NULL) {
144132332Smarcel		if (strcmp(str, "primary") == 0)
145132332Smarcel			res->hr_previous_role = HAST_ROLE_PRIMARY;
146132332Smarcel		else if (strcmp(str, "secondary") == 0)
147132332Smarcel			res->hr_previous_role = HAST_ROLE_SECONDARY;
148132332Smarcel	}
149132332Smarcel
150132332Smarcel	if (nv_error(nv) != 0) {
151132332Smarcel		errno = rerrno = nv_error(nv);
152132332Smarcel		pjdlog_errno(LOG_ERR, "Unable to read metadata from %s",
153132332Smarcel		    res->hr_localpath);
154132332Smarcel		nv_free(nv);
155132332Smarcel		goto fail;
156132332Smarcel	}
157132332Smarcel	nv_free(nv);
158132332Smarcel	return (0);
159132332Smarcelfail:
160132332Smarcel	if (opened_here) {
161132332Smarcel		close(res->hr_localfd);
162132332Smarcel		res->hr_localfd = -1;
163132332Smarcel	}
164132332Smarcel	errno = rerrno;
165132332Smarcel	return (-1);
166132332Smarcel}
167132332Smarcel
168132332Smarcelint
169132332Smarcelmetadata_write(struct hast_resource *res)
170132332Smarcel{
171132332Smarcel	struct ebuf *eb;
172132332Smarcel	struct nv *nv;
173132332Smarcel	unsigned char *buf, *ptr;
174132332Smarcel	size_t size;
175132332Smarcel	ssize_t done;
176132332Smarcel	int ret;
177132332Smarcel
178132332Smarcel	buf = calloc(1, METADATA_SIZE);
179209689Skib	if (buf == NULL) {
180209689Skib		pjdlog_error("Unable to allocate %zu bytes for metadata.",
181209689Skib		    (size_t)METADATA_SIZE);
182209689Skib		return (-1);
183209689Skib	}
184209689Skib
185209689Skib	ret = -1;
186209689Skib
187132332Smarcel	nv = nv_alloc();
188132332Smarcel	nv_add_string(nv, res->hr_name, "resource");
189132332Smarcel	nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize");
190132332Smarcel	nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize");
191132332Smarcel	nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty");
192132332Smarcel	nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset");
193146818Sdfr	nv_add_uint64(nv, res->hr_resuid, "resuid");
194132332Smarcel	if (res->hr_role == HAST_ROLE_PRIMARY ||
195146818Sdfr	    res->hr_role == HAST_ROLE_INIT) {
196146818Sdfr		nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt");
197146818Sdfr		nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt");
198146818Sdfr	} else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ {
199146818Sdfr		PJDLOG_ASSERT(res->hr_role == HAST_ROLE_SECONDARY);
200146818Sdfr		nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt");
201146818Sdfr		nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt");
202146818Sdfr	}
203146818Sdfr	nv_add_string(nv, role2str(res->hr_role), "prevrole");
204132332Smarcel	if (nv_error(nv) != 0) {
205132332Smarcel		pjdlog_error("Unable to create metadata.");
206132332Smarcel		goto end;
207132332Smarcel	}
208132332Smarcel	res->hr_previous_role = res->hr_role;
209132332Smarcel	eb = nv_hton(nv);
210132332Smarcel	PJDLOG_ASSERT(eb != NULL);
211132332Smarcel	ptr = ebuf_data(eb, &size);
212132332Smarcel	PJDLOG_ASSERT(ptr != NULL);
213132332Smarcel	PJDLOG_ASSERT(size < METADATA_SIZE);
214132332Smarcel	bcopy(ptr, buf, size);
215132332Smarcel	done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0);
216132332Smarcel	if (done < 0 || done != METADATA_SIZE) {
217132332Smarcel		pjdlog_errno(LOG_ERR, "Unable to write metadata");
218132332Smarcel		goto end;
219132332Smarcel	}
220132332Smarcel	ret = 0;
221132332Smarcelend:
222132332Smarcel	free(buf);
223132332Smarcel	nv_free(nv);
224146818Sdfr	return (ret);
225132332Smarcel}
226146818Sdfr