xref: /freebsd/sbin/hastd/metadata.c (revision 1d386b48)
132115b10SPawel Jakub Dawidek /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
432115b10SPawel Jakub Dawidek  * Copyright (c) 2009-2010 The FreeBSD Foundation
532115b10SPawel Jakub Dawidek  * All rights reserved.
632115b10SPawel Jakub Dawidek  *
732115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
832115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
932115b10SPawel Jakub Dawidek  *
1032115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1132115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1232115b10SPawel Jakub Dawidek  * are met:
1332115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1432115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1532115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1632115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1732115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1832115b10SPawel Jakub Dawidek  *
1932115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
2032115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2132115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2232115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2332115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2432115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2532115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2632115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2732115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2832115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2932115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
3032115b10SPawel Jakub Dawidek  */
3132115b10SPawel Jakub Dawidek 
3232115b10SPawel Jakub Dawidek #include <sys/cdefs.h>
3332115b10SPawel Jakub Dawidek #include <errno.h>
3432115b10SPawel Jakub Dawidek #include <fcntl.h>
3532115b10SPawel Jakub Dawidek #include <string.h>
3632115b10SPawel Jakub Dawidek #include <strings.h>
3732115b10SPawel Jakub Dawidek #include <unistd.h>
3832115b10SPawel Jakub Dawidek 
3932115b10SPawel Jakub Dawidek #include <ebuf.h>
4032115b10SPawel Jakub Dawidek #include <nv.h>
4132115b10SPawel Jakub Dawidek #include <pjdlog.h>
4232115b10SPawel Jakub Dawidek #include <subr.h>
4332115b10SPawel Jakub Dawidek 
4432115b10SPawel Jakub Dawidek #include "metadata.h"
4532115b10SPawel Jakub Dawidek 
4632115b10SPawel Jakub Dawidek int
metadata_read(struct hast_resource * res,bool openrw)4732115b10SPawel Jakub Dawidek metadata_read(struct hast_resource *res, bool openrw)
4832115b10SPawel Jakub Dawidek {
4932115b10SPawel Jakub Dawidek 	unsigned char *buf;
5032115b10SPawel Jakub Dawidek 	struct ebuf *eb;
5132115b10SPawel Jakub Dawidek 	struct nv *nv;
5232115b10SPawel Jakub Dawidek 	ssize_t done;
5332115b10SPawel Jakub Dawidek 	const char *str;
5432115b10SPawel Jakub Dawidek 	int rerrno;
5532115b10SPawel Jakub Dawidek 	bool opened_here;
5632115b10SPawel Jakub Dawidek 
5732115b10SPawel Jakub Dawidek 	opened_here = false;
5832115b10SPawel Jakub Dawidek 	rerrno = 0;
5932115b10SPawel Jakub Dawidek 
6032115b10SPawel Jakub Dawidek 	/*
6132115b10SPawel Jakub Dawidek 	 * Is this first metadata_read() call for this resource?
6232115b10SPawel Jakub Dawidek 	 */
6332115b10SPawel Jakub Dawidek 	if (res->hr_localfd == -1) {
642b1b224dSPawel Jakub Dawidek 		if (provinfo(res, openrw) == -1) {
6532115b10SPawel Jakub Dawidek 			rerrno = errno;
6632115b10SPawel Jakub Dawidek 			goto fail;
6732115b10SPawel Jakub Dawidek 		}
6832115b10SPawel Jakub Dawidek 		opened_here = true;
6932115b10SPawel Jakub Dawidek 		pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath);
7032115b10SPawel Jakub Dawidek 		if (openrw) {
712b1b224dSPawel Jakub Dawidek 			if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) == -1) {
7232115b10SPawel Jakub Dawidek 				rerrno = errno;
7332115b10SPawel Jakub Dawidek 				if (errno == EOPNOTSUPP) {
7432115b10SPawel Jakub Dawidek 					pjdlog_warning("Unable to lock %s (operation not supported), but continuing.",
7532115b10SPawel Jakub Dawidek 					    res->hr_localpath);
7632115b10SPawel Jakub Dawidek 				} else {
7732115b10SPawel Jakub Dawidek 					pjdlog_errno(LOG_ERR,
7832115b10SPawel Jakub Dawidek 					    "Unable to lock %s",
7932115b10SPawel Jakub Dawidek 					    res->hr_localpath);
8032115b10SPawel Jakub Dawidek 					goto fail;
8132115b10SPawel Jakub Dawidek 				}
8232115b10SPawel Jakub Dawidek 			}
8332115b10SPawel Jakub Dawidek 			pjdlog_debug(1, "Locked %s.", res->hr_localpath);
8432115b10SPawel Jakub Dawidek 		}
8532115b10SPawel Jakub Dawidek 	}
8632115b10SPawel Jakub Dawidek 
8732115b10SPawel Jakub Dawidek 	eb = ebuf_alloc(METADATA_SIZE);
8832115b10SPawel Jakub Dawidek 	if (eb == NULL) {
8932115b10SPawel Jakub Dawidek 		rerrno = errno;
9032115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR,
9132115b10SPawel Jakub Dawidek 		    "Unable to allocate memory to read metadata");
9232115b10SPawel Jakub Dawidek 		goto fail;
9332115b10SPawel Jakub Dawidek 	}
942b1b224dSPawel Jakub Dawidek 	if (ebuf_add_tail(eb, NULL, METADATA_SIZE) == -1) {
9532115b10SPawel Jakub Dawidek 		rerrno = errno;
9632115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR,
9732115b10SPawel Jakub Dawidek 		    "Unable to allocate memory to read metadata");
986744284aSPawel Jakub Dawidek 		ebuf_free(eb);
9932115b10SPawel Jakub Dawidek 		goto fail;
10032115b10SPawel Jakub Dawidek 	}
10132115b10SPawel Jakub Dawidek 	buf = ebuf_data(eb, NULL);
102adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(buf != NULL);
10332115b10SPawel Jakub Dawidek 	done = pread(res->hr_localfd, buf, METADATA_SIZE, 0);
1042b1b224dSPawel Jakub Dawidek 	if (done == -1 || done != METADATA_SIZE) {
10532115b10SPawel Jakub Dawidek 		rerrno = errno;
10632115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to read metadata");
10732115b10SPawel Jakub Dawidek 		ebuf_free(eb);
10832115b10SPawel Jakub Dawidek 		goto fail;
10932115b10SPawel Jakub Dawidek 	}
11032115b10SPawel Jakub Dawidek 	nv = nv_ntoh(eb);
11132115b10SPawel Jakub Dawidek 	if (nv == NULL) {
11232115b10SPawel Jakub Dawidek 		rerrno = errno;
11332115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid",
11432115b10SPawel Jakub Dawidek 		    res->hr_localpath);
11532115b10SPawel Jakub Dawidek 		ebuf_free(eb);
11632115b10SPawel Jakub Dawidek 		goto fail;
11732115b10SPawel Jakub Dawidek 	}
11832115b10SPawel Jakub Dawidek 
11932115b10SPawel Jakub Dawidek 	str = nv_get_string(nv, "resource");
1201228041bSPawel Jakub Dawidek 	if (str != NULL && strcmp(str, res->hr_name) != 0) {
12132115b10SPawel Jakub Dawidek 		pjdlog_error("Provider %s is not part of resource %s.",
12232115b10SPawel Jakub Dawidek 		    res->hr_localpath, res->hr_name);
12332115b10SPawel Jakub Dawidek 		nv_free(nv);
12432115b10SPawel Jakub Dawidek 		goto fail;
12532115b10SPawel Jakub Dawidek 	}
12632115b10SPawel Jakub Dawidek 
12732115b10SPawel Jakub Dawidek 	res->hr_datasize = nv_get_uint64(nv, "datasize");
12832115b10SPawel Jakub Dawidek 	res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize");
12932115b10SPawel Jakub Dawidek 	res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty");
13032115b10SPawel Jakub Dawidek 	res->hr_localoff = nv_get_uint64(nv, "offset");
13132115b10SPawel Jakub Dawidek 	res->hr_resuid = nv_get_uint64(nv, "resuid");
13232115b10SPawel Jakub Dawidek 	if (res->hr_role != HAST_ROLE_PRIMARY) {
13332115b10SPawel Jakub Dawidek 		/* Secondary or init role. */
13432115b10SPawel Jakub Dawidek 		res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt");
13532115b10SPawel Jakub Dawidek 		res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt");
13632115b10SPawel Jakub Dawidek 	}
13732115b10SPawel Jakub Dawidek 	if (res->hr_role != HAST_ROLE_SECONDARY) {
13832115b10SPawel Jakub Dawidek 		/* Primary or init role. */
13932115b10SPawel Jakub Dawidek 		res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt");
14032115b10SPawel Jakub Dawidek 		res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt");
14132115b10SPawel Jakub Dawidek 	}
14232115b10SPawel Jakub Dawidek 	str = nv_get_string(nv, "prevrole");
14332115b10SPawel Jakub Dawidek 	if (str != NULL) {
14432115b10SPawel Jakub Dawidek 		if (strcmp(str, "primary") == 0)
14532115b10SPawel Jakub Dawidek 			res->hr_previous_role = HAST_ROLE_PRIMARY;
14632115b10SPawel Jakub Dawidek 		else if (strcmp(str, "secondary") == 0)
14732115b10SPawel Jakub Dawidek 			res->hr_previous_role = HAST_ROLE_SECONDARY;
14832115b10SPawel Jakub Dawidek 	}
14932115b10SPawel Jakub Dawidek 
15032115b10SPawel Jakub Dawidek 	if (nv_error(nv) != 0) {
15132115b10SPawel Jakub Dawidek 		errno = rerrno = nv_error(nv);
15232115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to read metadata from %s",
15332115b10SPawel Jakub Dawidek 		    res->hr_localpath);
15432115b10SPawel Jakub Dawidek 		nv_free(nv);
15532115b10SPawel Jakub Dawidek 		goto fail;
15632115b10SPawel Jakub Dawidek 	}
1576744284aSPawel Jakub Dawidek 	nv_free(nv);
15832115b10SPawel Jakub Dawidek 	return (0);
15932115b10SPawel Jakub Dawidek fail:
16032115b10SPawel Jakub Dawidek 	if (opened_here) {
16132115b10SPawel Jakub Dawidek 		close(res->hr_localfd);
16232115b10SPawel Jakub Dawidek 		res->hr_localfd = -1;
16332115b10SPawel Jakub Dawidek 	}
16432115b10SPawel Jakub Dawidek 	errno = rerrno;
16532115b10SPawel Jakub Dawidek 	return (-1);
16632115b10SPawel Jakub Dawidek }
16732115b10SPawel Jakub Dawidek 
16832115b10SPawel Jakub Dawidek int
metadata_write(struct hast_resource * res)16932115b10SPawel Jakub Dawidek metadata_write(struct hast_resource *res)
17032115b10SPawel Jakub Dawidek {
17132115b10SPawel Jakub Dawidek 	struct ebuf *eb;
17232115b10SPawel Jakub Dawidek 	struct nv *nv;
17332115b10SPawel Jakub Dawidek 	unsigned char *buf, *ptr;
17432115b10SPawel Jakub Dawidek 	size_t size;
17532115b10SPawel Jakub Dawidek 	ssize_t done;
1766744284aSPawel Jakub Dawidek 	int ret;
17732115b10SPawel Jakub Dawidek 
17832115b10SPawel Jakub Dawidek 	buf = calloc(1, METADATA_SIZE);
17932115b10SPawel Jakub Dawidek 	if (buf == NULL) {
18032115b10SPawel Jakub Dawidek 		pjdlog_error("Unable to allocate %zu bytes for metadata.",
18132115b10SPawel Jakub Dawidek 		    (size_t)METADATA_SIZE);
18232115b10SPawel Jakub Dawidek 		return (-1);
18332115b10SPawel Jakub Dawidek 	}
18432115b10SPawel Jakub Dawidek 
1856744284aSPawel Jakub Dawidek 	ret = -1;
1866744284aSPawel Jakub Dawidek 
18732115b10SPawel Jakub Dawidek 	nv = nv_alloc();
18832115b10SPawel Jakub Dawidek 	nv_add_string(nv, res->hr_name, "resource");
18932115b10SPawel Jakub Dawidek 	nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize");
19032115b10SPawel Jakub Dawidek 	nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize");
19132115b10SPawel Jakub Dawidek 	nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty");
19232115b10SPawel Jakub Dawidek 	nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset");
19332115b10SPawel Jakub Dawidek 	nv_add_uint64(nv, res->hr_resuid, "resuid");
19432115b10SPawel Jakub Dawidek 	if (res->hr_role == HAST_ROLE_PRIMARY ||
19532115b10SPawel Jakub Dawidek 	    res->hr_role == HAST_ROLE_INIT) {
19632115b10SPawel Jakub Dawidek 		nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt");
19732115b10SPawel Jakub Dawidek 		nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt");
19832115b10SPawel Jakub Dawidek 	} else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ {
199adf8002bSPawel Jakub Dawidek 		PJDLOG_ASSERT(res->hr_role == HAST_ROLE_SECONDARY);
20032115b10SPawel Jakub Dawidek 		nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt");
20132115b10SPawel Jakub Dawidek 		nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt");
20232115b10SPawel Jakub Dawidek 	}
20332115b10SPawel Jakub Dawidek 	nv_add_string(nv, role2str(res->hr_role), "prevrole");
20432115b10SPawel Jakub Dawidek 	if (nv_error(nv) != 0) {
20532115b10SPawel Jakub Dawidek 		pjdlog_error("Unable to create metadata.");
2066744284aSPawel Jakub Dawidek 		goto end;
20732115b10SPawel Jakub Dawidek 	}
20832115b10SPawel Jakub Dawidek 	res->hr_previous_role = res->hr_role;
20932115b10SPawel Jakub Dawidek 	eb = nv_hton(nv);
210adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(eb != NULL);
21132115b10SPawel Jakub Dawidek 	ptr = ebuf_data(eb, &size);
212adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(ptr != NULL);
213adf8002bSPawel Jakub Dawidek 	PJDLOG_ASSERT(size < METADATA_SIZE);
21432115b10SPawel Jakub Dawidek 	bcopy(ptr, buf, size);
21532115b10SPawel Jakub Dawidek 	done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0);
2162b1b224dSPawel Jakub Dawidek 	if (done == -1 || done != METADATA_SIZE) {
21732115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to write metadata");
2186744284aSPawel Jakub Dawidek 		goto end;
21932115b10SPawel Jakub Dawidek 	}
2206744284aSPawel Jakub Dawidek 	ret = 0;
2216744284aSPawel Jakub Dawidek end:
22232115b10SPawel Jakub Dawidek 	free(buf);
22332115b10SPawel Jakub Dawidek 	nv_free(nv);
2246744284aSPawel Jakub Dawidek 	return (ret);
22532115b10SPawel Jakub Dawidek }
226