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
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
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
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>
44 #include <sys/vfsops.h>
45 #include <sys/sysctl.h>
46 #include <sys/socket.h>
47 #include <sys/objcache.h>
50 #include <sys/namei.h>
51 #include <sys/mountctl.h>
52 #include <sys/dirent.h>
55 #include <sys/mutex.h>
56 #include <sys/mutex2.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
);
67 hammer2_iocom_init(hammer2_mount_t
*hmp
)
71 * Automatic LNK_SPAN handling
72 * No automatic LNK_SPAN generation (we generate multiple spans
75 kdmsg_iocom_init(&hmp
->iocom
, hmp
,
76 KDMSG_IOCOMF_AUTOCONN
|
77 KDMSG_IOCOMF_AUTORXSPAN
,
78 hmp
->mchain
, hammer2_rcvdmsg
);
82 hammer2_iocom_uninit(hammer2_mount_t
*hmp
)
84 kdmsg_iocom_uninit(&hmp
->iocom
); /* XXX chain depend deadlck? */
88 * Reconnect using the passed file pointer. The caller must ref the
92 hammer2_cluster_reconnect(hammer2_mount_t
*hmp
, struct file
*fp
)
95 * Closes old comm descriptor, kills threads, cleans up
96 * states, then installs the new descriptor and creates
99 kdmsg_iocom_reconnect(&hmp
->iocom
, fp
, "hammer2");
102 * Setup LNK_CONN fields for autoinitiated state machine. LNK_CONN
103 * does not have to be unique. peer_id can be used to filter incoming
104 * LNK_SPANs automatically if desired (though we still need to check).
105 * peer_label typically identifies who we are and is not a filter.
107 * Since we will be initiating multiple LNK_SPANs we cannot use
108 * AUTOTXSPAN, but we do use AUTORXSPAN so kdmsg tracks received
109 * LNK_SPANs, and we simply monitor those messages.
111 bzero(&hmp
->iocom
.auto_lnk_conn
.peer_id
,
112 sizeof(hmp
->iocom
.auto_lnk_conn
.peer_id
));
113 /* hmp->iocom.auto_lnk_conn.peer_id = hmp->voldata.fsid; */
114 hmp
->iocom
.auto_lnk_conn
.proto_version
= DMSG_SPAN_PROTO_1
;
116 hmp
->iocom
.auto_lnk_conn
.peer_type
= hmp
->voldata
.peer_type
;
118 hmp
->iocom
.auto_lnk_conn
.peer_type
= DMSG_PEER_HAMMER2
;
121 * We just want to receive LNK_SPANs related to HAMMER2 matching
124 hmp
->iocom
.auto_lnk_conn
.peer_mask
= 1LLU << DMSG_PEER_HAMMER2
;
127 switch (ipdata
->pfs_type
) {
128 case DMSG_PFSTYPE_CLIENT
:
129 hmp
->iocom
.auto_lnk_conn
.peer_mask
&=
130 ~(1LLU << DMSG_PFSTYPE_CLIENT
);
137 bzero(&hmp
->iocom
.auto_lnk_conn
.peer_label
,
138 sizeof(hmp
->iocom
.auto_lnk_conn
.peer_label
));
139 ksnprintf(hmp
->iocom
.auto_lnk_conn
.peer_label
,
140 sizeof(hmp
->iocom
.auto_lnk_conn
.peer_label
),
142 hostname
, "hammer2-mount");
143 kdmsg_iocom_autoinitiate(&hmp
->iocom
, hammer2_autodmsg
);
147 hammer2_rcvdmsg(kdmsg_msg_t
*msg
)
149 kprintf("RCVMSG %08x\n", msg
->tcmd
);
155 * Execute shell command (not supported atm)
157 kdmsg_msg_result(msg
, DMSG_ERR_NOSUPP
);
159 case DMSG_DBG_SHELL
| DMSGF_REPLY
:
164 msg
->aux_data
[msg
->aux_size
- 1] = 0;
165 kprintf("HAMMER2 DBG: %s\n", msg
->aux_data
);
170 * Unsupported message received. We only need to
171 * reply if it's a transaction in order to close our end.
172 * Ignore any one-way messages or any further messages
173 * associated with the transaction.
175 * NOTE: This case also includes DMSG_LNK_ERROR messages
176 * which might be one-way, replying to those would
177 * cause an infinite ping-pong.
179 if (msg
->any
.head
.cmd
& DMSGF_CREATE
)
180 kdmsg_msg_reply(msg
, DMSG_ERR_NOSUPP
);
187 * This function is called after KDMSG has automatically handled processing
188 * of a LNK layer message (typically CONN or SPAN).
190 * We tag off the LNK_CONN to trigger our LNK_VOLCONF messages which
191 * advertises all available hammer2 super-root volumes.
193 * We collect span state
195 static void hammer2_update_spans(hammer2_mount_t
*hmp
, kdmsg_state_t
*state
);
198 hammer2_autodmsg(kdmsg_msg_t
*msg
)
200 hammer2_mount_t
*hmp
= msg
->state
->iocom
->handle
;
204 case DMSG_LNK_CONN
| DMSGF_CREATE
:
205 case DMSG_LNK_CONN
| DMSGF_CREATE
| DMSGF_DELETE
:
206 case DMSG_LNK_CONN
| DMSGF_DELETE
:
208 * NOTE: kern_dmsg will automatically issue a result,
209 * leaving the transaction open, for CREATEs,
210 * and will automatically issue a terminating reply
214 case DMSG_LNK_CONN
| DMSGF_CREATE
| DMSGF_REPLY
:
215 case DMSG_LNK_CONN
| DMSGF_CREATE
| DMSGF_DELETE
| DMSGF_REPLY
:
217 * Do a volume configuration dump when we receive a reply
218 * to our auto-CONN (typically leaving the transaction open).
220 if (msg
->any
.head
.cmd
& DMSGF_CREATE
) {
221 kprintf("HAMMER2: VOLDATA DUMP\n");
224 * Dump the configuration stored in the volume header.
225 * This will typically be import/export access rights,
226 * master encryption keys (encrypted), etc.
228 hammer2_voldata_lock(hmp
);
230 while (copyid
< HAMMER2_COPYID_COUNT
) {
231 if (hmp
->voldata
.copyinfo
[copyid
].copyid
)
232 hammer2_volconf_update(hmp
, copyid
);
235 hammer2_voldata_unlock(hmp
);
237 kprintf("HAMMER2: INITIATE SPANs\n");
238 hammer2_update_spans(hmp
, msg
->state
);
240 if ((msg
->any
.head
.cmd
& DMSGF_DELETE
) &&
241 msg
->state
&& (msg
->state
->txcmd
& DMSGF_DELETE
) == 0) {
242 kprintf("HAMMER2: CONN WAS TERMINATED\n");
245 case DMSG_LNK_SPAN
| DMSGF_CREATE
:
247 * Monitor SPANs and issue a result, leaving the SPAN open
248 * if it is something we can use now or in the future.
250 if (msg
->any
.lnk_span
.peer_type
!= DMSG_PEER_HAMMER2
) {
251 kdmsg_msg_reply(msg
, 0);
254 if (msg
->any
.lnk_span
.proto_version
!= DMSG_SPAN_PROTO_1
) {
255 kdmsg_msg_reply(msg
, 0);
258 DMSG_TERMINATE_STRING(msg
->any
.lnk_span
.peer_label
);
259 kprintf("H2 +RXSPAN cmd=%08x (%-20s) cl=",
260 msg
->any
.head
.cmd
, msg
->any
.lnk_span
.peer_label
);
261 printf_uuid(&msg
->any
.lnk_span
.peer_id
);
263 printf_uuid(&msg
->any
.lnk_span
.pfs_id
);
264 kprintf(" type=%d\n", msg
->any
.lnk_span
.pfs_type
);
265 kdmsg_msg_result(msg
, 0);
267 case DMSG_LNK_SPAN
| DMSGF_DELETE
:
269 * NOTE: kern_dmsg will automatically reply to DELETEs.
271 kprintf("H2 -RXSPAN\n");
279 * Update LNK_SPAN state
282 hammer2_update_spans(hammer2_mount_t
*hmp
, kdmsg_state_t
*state
)
284 const hammer2_inode_data_t
*ripdata
;
285 hammer2_cluster_t
*cparent
;
286 hammer2_cluster_t
*cluster
;
287 hammer2_pfsmount_t
*spmp
;
288 hammer2_key_t key_next
;
294 * Lookup mount point under the media-localized super-root.
296 * cluster->pmp will incorrectly point to spmp and must be fixed
300 cparent
= hammer2_inode_lock_ex(spmp
->iroot
);
301 cluster
= hammer2_cluster_lookup(cparent
, &key_next
,
306 if (hammer2_cluster_type(cluster
) != HAMMER2_BREF_TYPE_INODE
)
308 ripdata
= &hammer2_cluster_rdata(cluster
)->ipdata
;
309 kprintf("UPDATE SPANS: %s\n", ripdata
->filename
);
311 rmsg
= kdmsg_msg_alloc(&hmp
->iocom
.state0
,
312 DMSG_LNK_SPAN
| DMSGF_CREATE
,
313 hammer2_lnk_span_reply
, NULL
);
314 rmsg
->any
.lnk_span
.peer_id
= ripdata
->pfs_clid
;
315 rmsg
->any
.lnk_span
.pfs_id
= ripdata
->pfs_fsid
;
316 rmsg
->any
.lnk_span
.pfs_type
= ripdata
->pfs_type
;
317 rmsg
->any
.lnk_span
.peer_type
= DMSG_PEER_HAMMER2
;
318 rmsg
->any
.lnk_span
.proto_version
= DMSG_SPAN_PROTO_1
;
319 name_len
= ripdata
->name_len
;
320 if (name_len
>= sizeof(rmsg
->any
.lnk_span
.peer_label
))
321 name_len
= sizeof(rmsg
->any
.lnk_span
.peer_label
) - 1;
322 bcopy(ripdata
->filename
,
323 rmsg
->any
.lnk_span
.peer_label
,
326 kdmsg_msg_write(rmsg
);
328 cluster
= hammer2_cluster_next(cparent
, cluster
,
334 hammer2_inode_unlock_ex(spmp
->iroot
, cparent
);
339 hammer2_lnk_span_reply(kdmsg_state_t
*state
, kdmsg_msg_t
*msg
)
341 if ((state
->txcmd
& DMSGF_DELETE
) == 0 &&
342 (msg
->any
.head
.cmd
& DMSGF_DELETE
)) {
343 kdmsg_msg_reply(msg
, 0);
349 * Volume configuration updates are passed onto the userland service
350 * daemon via the open LNK_CONN transaction.
353 hammer2_volconf_update(hammer2_mount_t
*hmp
, int index
)
357 /* XXX interlock against connection state termination */
358 kprintf("volconf update %p\n", hmp
->iocom
.conn_state
);
359 if (hmp
->iocom
.conn_state
) {
360 kprintf("TRANSMIT VOLCONF VIA OPEN CONN TRANSACTION\n");
361 msg
= kdmsg_msg_alloc(hmp
->iocom
.conn_state
,
362 DMSG_LNK_HAMMER2_VOLCONF
,
364 H2_LNK_VOLCONF(msg
)->copy
= hmp
->voldata
.copyinfo
[index
];
365 H2_LNK_VOLCONF(msg
)->mediaid
= hmp
->voldata
.fsid
;
366 H2_LNK_VOLCONF(msg
)->index
= index
;
367 kdmsg_msg_write(msg
);