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