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