hammer2 - error handling 2/N (chain_lookup/chain_next)
[dragonfly.git] / sys / vfs / hammer2 / hammer2_iocom.c
blobf58583e3f03829baf10c4c0802c0f5226f634766
1 /*
2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/nlookup.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
41 #include <sys/fcntl.h>
42 #include <sys/buf.h>
43 #include <sys/uuid.h>
44 #include <sys/vfsops.h>
45 #include <sys/sysctl.h>
46 #include <sys/socket.h>
47 #include <sys/objcache.h>
49 #include <sys/proc.h>
50 #include <sys/namei.h>
51 #include <sys/mountctl.h>
52 #include <sys/dirent.h>
53 #include <sys/uio.h>
55 #include <sys/mutex.h>
56 #include <sys/mutex2.h>
58 #include "hammer2.h"
59 #include "hammer2_disk.h"
60 #include "hammer2_mount.h"
62 static int hammer2_rcvdmsg(kdmsg_msg_t *msg);
63 static void hammer2_autodmsg(kdmsg_msg_t *msg);
64 static int hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg);
66 void
67 hammer2_iocom_init(hammer2_dev_t *hmp)
70 * Automatic LNK_CONN
71 * Automatic LNK_SPAN handling
72 * No automatic LNK_SPAN generation (we generate multiple spans
73 * ourselves).
75 kdmsg_iocom_init(&hmp->iocom, hmp,
76 KDMSG_IOCOMF_AUTOCONN |
77 KDMSG_IOCOMF_AUTORXSPAN,
78 hmp->mchain, hammer2_rcvdmsg);
81 void
82 hammer2_iocom_uninit(hammer2_dev_t *hmp)
84 /* XXX chain depend deadlck? */
85 if (hmp->iocom.mmsg)
86 kdmsg_iocom_uninit(&hmp->iocom);
90 * Reconnect using the passed file pointer. The caller must ref the
91 * fp for us.
93 void
94 hammer2_cluster_reconnect(hammer2_dev_t *hmp, struct file *fp)
97 * Closes old comm descriptor, kills threads, cleans up
98 * states, then installs the new descriptor and creates
99 * new threads.
101 kdmsg_iocom_reconnect(&hmp->iocom, fp, "hammer2");
104 * Setup LNK_CONN fields for autoinitiated state machine. LNK_CONN
105 * does not have to be unique. peer_id can be used to filter incoming
106 * LNK_SPANs automatically if desired (though we still need to check).
107 * peer_label typically identifies who we are and is not a filter.
109 * Since we will be initiating multiple LNK_SPANs we cannot use
110 * AUTOTXSPAN, but we do use AUTORXSPAN so kdmsg tracks received
111 * LNK_SPANs, and we simply monitor those messages.
113 bzero(&hmp->iocom.auto_lnk_conn.peer_id,
114 sizeof(hmp->iocom.auto_lnk_conn.peer_id));
115 /* hmp->iocom.auto_lnk_conn.peer_id = hmp->voldata.fsid; */
116 hmp->iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1;
117 #if 0
118 hmp->iocom.auto_lnk_conn.peer_type = hmp->voldata.peer_type;
119 #endif
120 hmp->iocom.auto_lnk_conn.peer_type = DMSG_PEER_HAMMER2;
123 * We just want to receive LNK_SPANs related to HAMMER2 matching
124 * peer_id.
126 hmp->iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_HAMMER2;
128 #if 0
129 switch (ipdata->meta.pfs_type) {
130 case DMSG_PFSTYPE_CLIENT:
131 hmp->iocom.auto_lnk_conn.peer_mask &=
132 ~(1LLU << DMSG_PFSTYPE_CLIENT);
133 break;
134 default:
135 break;
137 #endif
139 bzero(&hmp->iocom.auto_lnk_conn.peer_label,
140 sizeof(hmp->iocom.auto_lnk_conn.peer_label));
141 ksnprintf(hmp->iocom.auto_lnk_conn.peer_label,
142 sizeof(hmp->iocom.auto_lnk_conn.peer_label),
143 "%s/%s",
144 hostname, "hammer2-mount");
145 kdmsg_iocom_autoinitiate(&hmp->iocom, hammer2_autodmsg);
148 static int
149 hammer2_rcvdmsg(kdmsg_msg_t *msg)
151 kprintf("RCVMSG %08x\n", msg->tcmd);
153 switch(msg->tcmd) {
154 case DMSG_DBG_SHELL:
156 * (non-transaction)
157 * Execute shell command (not supported atm)
159 kdmsg_msg_result(msg, DMSG_ERR_NOSUPP);
160 break;
161 case DMSG_DBG_SHELL | DMSGF_REPLY:
163 * (non-transaction)
165 if (msg->aux_data) {
166 msg->aux_data[msg->aux_size - 1] = 0;
167 kprintf("HAMMER2 DBG: %s\n", msg->aux_data);
169 break;
170 default:
172 * Unsupported message received. We only need to
173 * reply if it's a transaction in order to close our end.
174 * Ignore any one-way messages or any further messages
175 * associated with the transaction.
177 * NOTE: This case also includes DMSG_LNK_ERROR messages
178 * which might be one-way, replying to those would
179 * cause an infinite ping-pong.
181 if (msg->any.head.cmd & DMSGF_CREATE)
182 kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
183 break;
185 return(0);
189 * This function is called after KDMSG has automatically handled processing
190 * of a LNK layer message (typically CONN or SPAN).
192 * We tag off the LNK_CONN to trigger our LNK_VOLCONF messages which
193 * advertises all available hammer2 super-root volumes.
195 * We collect span state
197 static void hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state);
199 static void
200 hammer2_autodmsg(kdmsg_msg_t *msg)
202 hammer2_dev_t *hmp = msg->state->iocom->handle;
203 int copyid;
205 switch(msg->tcmd) {
206 case DMSG_LNK_CONN | DMSGF_CREATE:
207 case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_DELETE:
208 case DMSG_LNK_CONN | DMSGF_DELETE:
210 * NOTE: kern_dmsg will automatically issue a result,
211 * leaving the transaction open, for CREATEs,
212 * and will automatically issue a terminating reply
213 * for DELETEs.
215 break;
216 case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_REPLY:
217 case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_DELETE | DMSGF_REPLY:
219 * Do a volume configuration dump when we receive a reply
220 * to our auto-CONN (typically leaving the transaction open).
222 if (msg->any.head.cmd & DMSGF_CREATE) {
223 kprintf("HAMMER2: VOLDATA DUMP\n");
226 * Dump the configuration stored in the volume header.
227 * This will typically be import/export access rights,
228 * master encryption keys (encrypted), etc.
230 hammer2_voldata_lock(hmp);
231 copyid = 0;
232 while (copyid < HAMMER2_COPYID_COUNT) {
233 if (hmp->voldata.copyinfo[copyid].copyid)
234 hammer2_volconf_update(hmp, copyid);
235 ++copyid;
237 hammer2_voldata_unlock(hmp);
239 kprintf("HAMMER2: INITIATE SPANs\n");
240 hammer2_update_spans(hmp, msg->state);
242 if ((msg->any.head.cmd & DMSGF_DELETE) &&
243 msg->state && (msg->state->txcmd & DMSGF_DELETE) == 0) {
244 kprintf("HAMMER2: CONN WAS TERMINATED\n");
246 break;
247 case DMSG_LNK_SPAN | DMSGF_CREATE:
249 * Monitor SPANs and issue a result, leaving the SPAN open
250 * if it is something we can use now or in the future.
252 if (msg->any.lnk_span.peer_type != DMSG_PEER_HAMMER2) {
253 kdmsg_msg_reply(msg, 0);
254 break;
256 if (msg->any.lnk_span.proto_version != DMSG_SPAN_PROTO_1) {
257 kdmsg_msg_reply(msg, 0);
258 break;
260 DMSG_TERMINATE_STRING(msg->any.lnk_span.peer_label);
261 if (hammer2_debug & 0x0100) {
262 kprintf("H2 +RXSPAN cmd=%08x (%-20s) cl=",
263 msg->any.head.cmd,
264 msg->any.lnk_span.peer_label);
265 printf_uuid(&msg->any.lnk_span.peer_id);
266 kprintf(" fs=");
267 printf_uuid(&msg->any.lnk_span.pfs_id);
268 kprintf(" type=%d\n", msg->any.lnk_span.pfs_type);
270 kdmsg_msg_result(msg, 0);
271 break;
272 case DMSG_LNK_SPAN | DMSGF_DELETE:
274 * NOTE: kern_dmsg will automatically reply to DELETEs.
276 if (hammer2_debug & 0x0100)
277 kprintf("H2 -RXSPAN\n");
278 break;
279 default:
280 break;
285 * Update LNK_SPAN state
287 static void
288 hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state)
290 const hammer2_inode_data_t *ripdata;
291 hammer2_chain_t *parent;
292 hammer2_chain_t *chain;
293 hammer2_pfs_t *spmp;
294 hammer2_key_t key_next;
295 kdmsg_msg_t *rmsg;
296 size_t name_len;
297 int error;
300 * Lookup mount point under the media-localized super-root.
302 * cluster->pmp will incorrectly point to spmp and must be fixed
303 * up later on.
305 spmp = hmp->spmp;
306 hammer2_inode_lock(spmp->iroot, 0);
307 error = 0;
309 parent = hammer2_inode_chain(spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS);
310 chain = NULL;
311 if (parent == NULL)
312 goto done;
313 chain = hammer2_chain_lookup(&parent, &key_next,
314 HAMMER2_KEY_MIN, HAMMER2_KEY_MAX,
315 &error, 0);
316 while (chain) {
317 if (chain->bref.type != HAMMER2_BREF_TYPE_INODE)
318 continue;
319 ripdata = &chain->data->ipdata;
320 kprintf("UPDATE SPANS: %s\n", ripdata->filename);
322 rmsg = kdmsg_msg_alloc(&hmp->iocom.state0,
323 DMSG_LNK_SPAN | DMSGF_CREATE,
324 hammer2_lnk_span_reply, NULL);
325 rmsg->any.lnk_span.peer_id = ripdata->meta.pfs_clid;
326 rmsg->any.lnk_span.pfs_id = ripdata->meta.pfs_fsid;
327 rmsg->any.lnk_span.pfs_type = ripdata->meta.pfs_type;
328 rmsg->any.lnk_span.peer_type = DMSG_PEER_HAMMER2;
329 rmsg->any.lnk_span.proto_version = DMSG_SPAN_PROTO_1;
330 name_len = ripdata->meta.name_len;
331 if (name_len >= sizeof(rmsg->any.lnk_span.peer_label))
332 name_len = sizeof(rmsg->any.lnk_span.peer_label) - 1;
333 bcopy(ripdata->filename,
334 rmsg->any.lnk_span.peer_label,
335 name_len);
337 kdmsg_msg_write(rmsg);
339 chain = hammer2_chain_next(&parent, chain, &key_next,
340 key_next, HAMMER2_KEY_MAX,
341 &error, 0);
343 hammer2_inode_unlock(spmp->iroot);
344 error = hammer2_error_to_errno(error);
345 /* XXX do something with error */
346 done:
347 if (chain) {
348 hammer2_chain_unlock(chain);
349 hammer2_chain_drop(chain);
351 if (parent) {
352 hammer2_chain_unlock(parent);
353 hammer2_chain_drop(parent);
357 static
359 hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg)
361 if ((state->txcmd & DMSGF_DELETE) == 0 &&
362 (msg->any.head.cmd & DMSGF_DELETE)) {
363 kdmsg_msg_reply(msg, 0);
365 return 0;
369 * Volume configuration updates are passed onto the userland service
370 * daemon via the open LNK_CONN transaction.
372 void
373 hammer2_volconf_update(hammer2_dev_t *hmp, int index)
375 kdmsg_msg_t *msg;
377 /* XXX interlock against connection state termination */
378 kprintf("volconf update %p\n", hmp->iocom.conn_state);
379 if (hmp->iocom.conn_state) {
380 kprintf("TRANSMIT VOLCONF VIA OPEN CONN TRANSACTION\n");
381 msg = kdmsg_msg_alloc(hmp->iocom.conn_state,
382 DMSG_LNK_HAMMER2_VOLCONF,
383 NULL, NULL);
384 H2_LNK_VOLCONF(msg)->copy = hmp->voldata.copyinfo[index];
385 H2_LNK_VOLCONF(msg)->mediaid = hmp->voldata.fsid;
386 H2_LNK_VOLCONF(msg)->index = index;
387 kdmsg_msg_write(msg);