From d157d4dc34bc87ae70888ac92a8fbf1ea662eabd Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 14 Mar 2015 21:31:23 -0700 Subject: [PATCH] hammer2 - Misc cluster protocol work * Adjust debugging a bit so hammer2 -d bumps DMsgDebugOpt to sucessively higher values. * mount_hammer2 now connects the hammer2 service daemon to the mount via localhost instead of via 0 (0 does not bind to localhost if the machine has an IP address). Allows differentiation between remote connections and local connections. * Begin splitting the dmsg iocom stuff off from vfsops.c in the hammer2 VFS and test. * Issue SPANs relative to state0 rather than the LNK_CONN state in the hammer2 VFS, to match how SPANs are implemented in the service demon. * Recognize remote HAMMER2 filesystem SPANs (but don't do anything with them yet). * Fix a brace bug in hammer2_bulkscan.c (from swildner). --- lib/libdmsg/msg_lnk.c | 2 + sbin/hammer2/main.c | 2 +- sbin/mount_hammer2/mount_hammer2.c | 2 +- sys/sys/dmsg.h | 3 + sys/vfs/hammer2/Makefile | 2 +- sys/vfs/hammer2/hammer2.h | 8 +- sys/vfs/hammer2/hammer2_bulkscan.c | 3 +- sys/vfs/hammer2/hammer2_iocom.c | 371 +++++++++++++++++++++++++++++ sys/vfs/hammer2/hammer2_vfsops.c | 271 +-------------------- 9 files changed, 395 insertions(+), 269 deletions(-) create mode 100644 sys/vfs/hammer2/hammer2_iocom.c diff --git a/lib/libdmsg/msg_lnk.c b/lib/libdmsg/msg_lnk.c index 7b09f442d7..0243c94370 100644 --- a/lib/libdmsg/msg_lnk.c +++ b/lib/libdmsg/msg_lnk.c @@ -534,6 +534,8 @@ dmsg_lnk_span(dmsg_msg_t *msg) char *alloc = NULL; /* + * XXX + * * Ignore reply to LNK_SPAN. The reply is expected and will commands * to flow in both directions on the open transaction. This will also * ignore DMSGF_REPLY|DMSGF_DELETE messages. Since we take no action diff --git a/sbin/hammer2/main.c b/sbin/hammer2/main.c index dcb9eaf628..ba70dbb33d 100644 --- a/sbin/hammer2/main.c +++ b/sbin/hammer2/main.c @@ -69,7 +69,7 @@ main(int ac, char **av) break; case 'd': if (DebugOpt) - DMsgDebugOpt = 1; + ++DMsgDebugOpt; DebugOpt = 1; break; case 'f': diff --git a/sbin/mount_hammer2/mount_hammer2.c b/sbin/mount_hammer2/mount_hammer2.c index 865fb8d6da..8ab725a10b 100644 --- a/sbin/mount_hammer2/mount_hammer2.c +++ b/sbin/mount_hammer2/mount_hammer2.c @@ -142,7 +142,7 @@ cluster_connect(const char *volume __unused) } bzero(&lsin, sizeof(lsin)); lsin.sin_family = AF_INET; - lsin.sin_addr.s_addr = 0; + lsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); lsin.sin_port = htons(DMSG_LISTEN_PORT); if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { diff --git a/sys/sys/dmsg.h b/sys/sys/dmsg.h index a0858c1c15..e293a342ff 100644 --- a/sys/sys/dmsg.h +++ b/sys/sys/dmsg.h @@ -202,6 +202,9 @@ * may be negotiated away later. */ +#define DMSG_TERMINATE_STRING(ary) \ + do { (ary)[sizeof(ary) - 1] = 0; } while (0) + /* * dmsg_hdr must be 64 bytes */ diff --git a/sys/vfs/hammer2/Makefile b/sys/vfs/hammer2/Makefile index ac33bb1bc2..a06504cfe3 100644 --- a/sys/vfs/hammer2/Makefile +++ b/sys/vfs/hammer2/Makefile @@ -8,7 +8,7 @@ KMOD= hammer2 SRCS= hammer2_vfsops.c hammer2_vnops.c hammer2_inode.c hammer2_ccms.c SRCS+= hammer2_chain.c hammer2_flush.c hammer2_freemap.c hammer2_cluster.c SRCS+= hammer2_ioctl.c hammer2_msgops.c hammer2_subr.c hammer2_bulkscan.c -SRCS+= hammer2_lz4.c hammer2_io.c +SRCS+= hammer2_lz4.c hammer2_io.c hammer2_iocom.c SRCS+= hammer2_zlib_adler32.c hammer2_zlib_deflate.c SRCS+= hammer2_zlib_inffast.c hammer2_zlib_inflate.c SRCS+= hammer2_zlib_inftrees.c hammer2_zlib_trees.c diff --git a/sys/vfs/hammer2/hammer2.h b/sys/vfs/hammer2/hammer2.h index 8225173d99..33d5a7c577 100644 --- a/sys/vfs/hammer2/hammer2.h +++ b/sys/vfs/hammer2/hammer2.h @@ -989,7 +989,6 @@ int hammer2_msg_adhoc_input(kdmsg_msg_t *msg); */ void hammer2_clusterctl_wakeup(kdmsg_iocom_t *iocom); void hammer2_volconf_update(hammer2_mount_t *hmp, int index); -void hammer2_cluster_reconnect(hammer2_mount_t *hmp, struct file *fp); void hammer2_dump_chain(hammer2_chain_t *chain, int tab, int *countp, char pfx); void hammer2_bioq_sync(hammer2_pfsmount_t *pmp); int hammer2_vfs_sync(struct mount *mp, int waitflags); @@ -1076,5 +1075,12 @@ int hammer2_bulk_scan(hammer2_trans_t *trans, hammer2_chain_t *parent, int hammer2_bulkfree_pass(hammer2_mount_t *hmp, struct hammer2_ioc_bulkfree *bfi); +/* + * hammer2_iocom.c + */ +void hammer2_iocom_init(hammer2_mount_t *hmp); +void hammer2_iocom_uninit(hammer2_mount_t *hmp); +void hammer2_cluster_reconnect(hammer2_mount_t *hmp, struct file *fp); + #endif /* !_KERNEL */ #endif /* !_VFS_HAMMER2_HAMMER2_H_ */ diff --git a/sys/vfs/hammer2/hammer2_bulkscan.c b/sys/vfs/hammer2/hammer2_bulkscan.c index aac27bb538..c9af4a44fe 100644 --- a/sys/vfs/hammer2/hammer2_bulkscan.c +++ b/sys/vfs/hammer2/hammer2_bulkscan.c @@ -627,9 +627,10 @@ h2_bulkfree_sync_adjust(hammer2_bulkfree_info_t *cbinfo, ++cbinfo->count_l0cleans; } else if (bindex < 7) { ++bindex; - if (live->linear > bindex * HAMMER2_FREEMAP_BLOCK_SIZE) + if (live->linear > bindex * HAMMER2_FREEMAP_BLOCK_SIZE) { live->linear = bindex * HAMMER2_FREEMAP_BLOCK_SIZE; ++cbinfo->count_linadjusts; + } } #if 0 diff --git a/sys/vfs/hammer2/hammer2_iocom.c b/sys/vfs/hammer2/hammer2_iocom.c new file mode 100644 index 0000000000..0c11a80efa --- /dev/null +++ b/sys/vfs/hammer2/hammer2_iocom.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "hammer2.h" +#include "hammer2_disk.h" +#include "hammer2_mount.h" + +static int hammer2_rcvdmsg(kdmsg_msg_t *msg); +static void hammer2_autodmsg(kdmsg_msg_t *msg); +static int hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg); + +void +hammer2_iocom_init(hammer2_mount_t *hmp) +{ + /* + * Automatic LNK_CONN + * Automatic LNK_SPAN handling + * No automatic LNK_SPAN generation (we generate multiple spans + * ourselves). + */ + kdmsg_iocom_init(&hmp->iocom, hmp, + KDMSG_IOCOMF_AUTOCONN | + KDMSG_IOCOMF_AUTORXSPAN, + hmp->mchain, hammer2_rcvdmsg); +} + +void +hammer2_iocom_uninit(hammer2_mount_t *hmp) +{ + kdmsg_iocom_uninit(&hmp->iocom); /* XXX chain depend deadlck? */ +} + +/* + * Reconnect using the passed file pointer. The caller must ref the + * fp for us. + */ +void +hammer2_cluster_reconnect(hammer2_mount_t *hmp, struct file *fp) +{ + size_t name_len; + const char *name = "disk-volume"; + + /* + * Closes old comm descriptor, kills threads, cleans up + * states, then installs the new descriptor and creates + * new threads. + */ + kdmsg_iocom_reconnect(&hmp->iocom, fp, "hammer2"); + + /* + * Setup LNK_CONN fields for autoinitiated state machine. We + * will use SPANs to advertise multiple PFSs so only pass the + * fsid and HAMMER2_PFSTYPE_SUPROOT for the AUTOCONN. + * + * Since we will be initiating multiple LNK_SPANs we cannot + * use AUTOTXSPAN, but we do use AUTORXSPAN so kdmsg tracks + * received LNK_SPANs, and we simply monitor those messages. + */ + bzero(&hmp->iocom.auto_lnk_conn.pfs_clid, + sizeof(hmp->iocom.auto_lnk_conn.pfs_clid)); + hmp->iocom.auto_lnk_conn.pfs_fsid = hmp->voldata.fsid; + hmp->iocom.auto_lnk_conn.pfs_type = HAMMER2_PFSTYPE_SUPROOT; + hmp->iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1; +#if 0 + hmp->iocom.auto_lnk_conn.peer_type = hmp->voldata.peer_type; +#endif + hmp->iocom.auto_lnk_conn.peer_type = DMSG_PEER_HAMMER2; + + /* + * Filter adjustment. Clients do not need visibility into other + * clients (otherwise millions of clients would present a serious + * problem). The fs_label also serves to restrict the namespace. + */ + hmp->iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_HAMMER2; + hmp->iocom.auto_lnk_conn.pfs_mask = (uint64_t)-1; + +#if 0 + switch (ipdata->pfs_type) { + case DMSG_PFSTYPE_CLIENT: + hmp->iocom.auto_lnk_conn.peer_mask &= + ~(1LLU << DMSG_PFSTYPE_CLIENT); + break; + default: + break; + } +#endif + + name_len = strlen(name); + if (name_len >= sizeof(hmp->iocom.auto_lnk_conn.fs_label)) + name_len = sizeof(hmp->iocom.auto_lnk_conn.fs_label) - 1; + bcopy(name, hmp->iocom.auto_lnk_conn.fs_label, name_len); + hmp->iocom.auto_lnk_conn.fs_label[name_len] = 0; + + kdmsg_iocom_autoinitiate(&hmp->iocom, hammer2_autodmsg); +} + +static int +hammer2_rcvdmsg(kdmsg_msg_t *msg) +{ + kprintf("RCVMSG %08x\n", msg->tcmd); + + switch(msg->tcmd) { + case DMSG_DBG_SHELL: + /* + * (non-transaction) + * Execute shell command (not supported atm) + */ + kdmsg_msg_result(msg, DMSG_ERR_NOSUPP); + break; + case DMSG_DBG_SHELL | DMSGF_REPLY: + /* + * (non-transaction) + */ + if (msg->aux_data) { + msg->aux_data[msg->aux_size - 1] = 0; + kprintf("HAMMER2 DBG: %s\n", msg->aux_data); + } + break; + default: + /* + * Unsupported message received. We only need to + * reply if it's a transaction in order to close our end. + * Ignore any one-way messages or any further messages + * associated with the transaction. + * + * NOTE: This case also includes DMSG_LNK_ERROR messages + * which might be one-way, replying to those would + * cause an infinite ping-pong. + */ + if (msg->any.head.cmd & DMSGF_CREATE) + kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP); + break; + } + return(0); +} + +/* + * This function is called after KDMSG has automatically handled processing + * of a LNK layer message (typically CONN or SPAN). + * + * We tag off the LNK_CONN to trigger our LNK_VOLCONF messages which + * advertises all available hammer2 super-root volumes. + * + * We collect span state + */ +static void hammer2_update_spans(hammer2_mount_t *hmp, kdmsg_state_t *state); + +static void +hammer2_autodmsg(kdmsg_msg_t *msg) +{ + hammer2_mount_t *hmp = msg->state->iocom->handle; + int copyid; + + switch(msg->tcmd) { + case DMSG_LNK_CONN | DMSGF_CREATE: + case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_DELETE: + case DMSG_LNK_CONN | DMSGF_DELETE: + /* + * NOTE: kern_dmsg will automatically issue a result, + * leaving the transaction open, for CREATEs, + * and will automatically issue a terminating reply + * for DELETEs. + */ + break; + case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_REPLY: + case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_DELETE | DMSGF_REPLY: + /* + * Do a volume configuration dump when we receive a reply + * to our auto-CONN (typically leaving the transaction open). + */ + if (msg->any.head.cmd & DMSGF_CREATE) { + kprintf("HAMMER2: VOLDATA DUMP\n"); + + /* + * Dump the configuration stored in the volume header. + * This will typically be import/export access rights, + * master encryption keys (encrypted), etc. + */ + hammer2_voldata_lock(hmp); + copyid = 0; + while (copyid < HAMMER2_COPYID_COUNT) { + if (hmp->voldata.copyinfo[copyid].copyid) + hammer2_volconf_update(hmp, copyid); + ++copyid; + } + hammer2_voldata_unlock(hmp); + + kprintf("HAMMER2: INITIATE SPANs\n"); + hammer2_update_spans(hmp, msg->state); + } + if ((msg->any.head.cmd & DMSGF_DELETE) && + msg->state && (msg->state->txcmd & DMSGF_DELETE) == 0) { + kprintf("HAMMER2: CONN WAS TERMINATED\n"); + } + break; + case DMSG_LNK_SPAN | DMSGF_CREATE: + /* + * Monitor SPANs and issue a result, leaving the SPAN open + * if it is something we can use now or in the future. + */ + if (msg->any.lnk_span.peer_type != DMSG_PEER_HAMMER2) { + kdmsg_msg_reply(msg, 0); + break; + } + if (msg->any.lnk_span.proto_version != DMSG_SPAN_PROTO_1) { + kdmsg_msg_reply(msg, 0); + break; + } + DMSG_TERMINATE_STRING(msg->any.lnk_span.fs_label); + kprintf("H2 +RXSPAN cmd=%08x (%-20s) cl=", msg->any.head.cmd, msg->any.lnk_span.fs_label); + printf_uuid(&msg->any.lnk_span.pfs_clid); + kprintf(" fs="); + printf_uuid(&msg->any.lnk_span.pfs_fsid); + kprintf(" type=%d\n", msg->any.lnk_span.pfs_type); + kdmsg_msg_result(msg, 0); + break; + case DMSG_LNK_SPAN | DMSGF_DELETE: + /* + * NOTE: kern_dmsg will automatically reply to DELETEs. + */ + kprintf("H2 -RXSPAN\n"); + break; + default: + break; + } +} + +/* + * Update LNK_SPAN state + */ +static void +hammer2_update_spans(hammer2_mount_t *hmp, kdmsg_state_t *state) +{ + const hammer2_inode_data_t *ripdata; + hammer2_cluster_t *cparent; + hammer2_cluster_t *cluster; + hammer2_pfsmount_t *spmp; + hammer2_key_t key_next; + kdmsg_msg_t *rmsg; + size_t name_len; + int ddflag; + + /* + * Lookup mount point under the media-localized super-root. + * + * cluster->pmp will incorrectly point to spmp and must be fixed + * up later on. + */ + spmp = hmp->spmp; + cparent = hammer2_inode_lock_ex(spmp->iroot); + cluster = hammer2_cluster_lookup(cparent, &key_next, + HAMMER2_KEY_MIN, + HAMMER2_KEY_MAX, + 0, &ddflag); + while (cluster) { + if (hammer2_cluster_type(cluster) != HAMMER2_BREF_TYPE_INODE) + continue; + ripdata = &hammer2_cluster_rdata(cluster)->ipdata; + kprintf("UPDATE SPANS: %s\n", ripdata->filename); + + rmsg = kdmsg_msg_alloc(&hmp->iocom.state0, + DMSG_LNK_SPAN | DMSGF_CREATE, + hammer2_lnk_span_reply, NULL); + rmsg->any.lnk_span.pfs_clid = ripdata->pfs_clid; + rmsg->any.lnk_span.pfs_fsid = ripdata->pfs_fsid; + rmsg->any.lnk_span.pfs_type = ripdata->pfs_type; + rmsg->any.lnk_span.peer_type = DMSG_PEER_HAMMER2; + rmsg->any.lnk_span.proto_version = DMSG_SPAN_PROTO_1; + name_len = ripdata->name_len; + if (name_len >= sizeof(rmsg->any.lnk_span.fs_label)) + name_len = sizeof(rmsg->any.lnk_span.fs_label) - 1; + bcopy(ripdata->filename, rmsg->any.lnk_span.fs_label, name_len); + + kdmsg_msg_write(rmsg); + + cluster = hammer2_cluster_next(cparent, cluster, + &key_next, + key_next, + HAMMER2_KEY_MAX, + 0); + } + hammer2_inode_unlock_ex(spmp->iroot, cparent); +} + +static +int +hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg) +{ + if ((state->txcmd & DMSGF_DELETE) == 0 && + (msg->any.head.cmd & DMSGF_DELETE)) { + kdmsg_msg_reply(msg, 0); + } + return 0; +} + +/* + * Volume configuration updates are passed onto the userland service + * daemon via the open LNK_CONN transaction. + */ +void +hammer2_volconf_update(hammer2_mount_t *hmp, int index) +{ + kdmsg_msg_t *msg; + + /* XXX interlock against connection state termination */ + kprintf("volconf update %p\n", hmp->iocom.conn_state); + if (hmp->iocom.conn_state) { + kprintf("TRANSMIT VOLCONF VIA OPEN CONN TRANSACTION\n"); + msg = kdmsg_msg_alloc(hmp->iocom.conn_state, + DMSG_LNK_HAMMER2_VOLCONF, + NULL, NULL); + H2_LNK_VOLCONF(msg)->copy = hmp->voldata.copyinfo[index]; + H2_LNK_VOLCONF(msg)->mediaid = hmp->voldata.fsid; + H2_LNK_VOLCONF(msg)->index = index; + kdmsg_msg_write(msg); + } +} diff --git a/sys/vfs/hammer2/hammer2_vfsops.c b/sys/vfs/hammer2/hammer2_vfsops.c index 3b7cd2f5ab..7b2cbb3f7c 100644 --- a/sys/vfs/hammer2/hammer2_vfsops.c +++ b/sys/vfs/hammer2/hammer2_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014 The DragonFly Project. All rights reserved. + * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon @@ -58,8 +58,6 @@ #include "hammer2.h" #include "hammer2_disk.h" #include "hammer2_mount.h" - -#include "hammer2.h" #include "hammer2_lz4.h" #include "zlib/hammer2_zlib.h" @@ -239,11 +237,6 @@ static void hammer2_write_bp(hammer2_cluster_t *cluster, struct buf *bp, int ioflag, int pblksize, int *errorp, int check_algo); -static int hammer2_rcvdmsg(kdmsg_msg_t *msg); -static void hammer2_autodmsg(kdmsg_msg_t *msg); -static int hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg); - - /* * HAMMER2 vfs operations. */ @@ -651,17 +644,7 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data, } ++hmp->pmp_count; - /* - * XXX RDONLY stuff is totally broken FIXME XXX - * - * Automatic LNK_CONN - * Automatic handling of received LNK_SPAN - * No automatic LNK_SPAN generation - we do this ourselves - */ - kdmsg_iocom_init(&hmp->iocom, hmp, - KDMSG_IOCOMF_AUTOCONN | - KDMSG_IOCOMF_AUTORXSPAN, - hmp->mchain, hammer2_rcvdmsg); + hammer2_iocom_init(hmp); /* * Ref the cluster management messaging descriptor. The mount @@ -1692,8 +1675,6 @@ hammer2_vfs_unmount_hmp1(struct mount *mp, hammer2_mount_t *hmp) kprintf("hammer2_unmount hmp=%p pmpcnt=%d\n", hmp, hmp->pmp_count); - kdmsg_iocom_uninit(&hmp->iocom); /* XXX chain depend deadlck? */ - /* * Cycle the volume data lock as a safety (probably not needed any * more). To ensure everything is out we need to flush at least @@ -1712,6 +1693,11 @@ hammer2_vfs_unmount_hmp1(struct mount *mp, hammer2_mount_t *hmp) hammer2_vfs_sync(mp, MNT_WAIT); } + /* + * XXX chain depend deadlock? + */ + hammer2_iocom_uninit(hmp); + if (hmp->pmp_count == 0) { if ((hmp->vchain.flags | hmp->fchain.flags) & HAMMER2_CHAIN_FLUSH_MASK) { @@ -2536,249 +2522,6 @@ hammer2_install_volume_header(hammer2_mount_t *hmp) return (error); } -/* - * Reconnect using the passed file pointer. The caller must ref the - * fp for us. - */ -void -hammer2_cluster_reconnect(hammer2_mount_t *hmp, struct file *fp) -{ - size_t name_len; - const char *name = "disk-volume"; - - /* - * Closes old comm descriptor, kills threads, cleans up - * states, then installs the new descriptor and creates - * new threads. - */ - kdmsg_iocom_reconnect(&hmp->iocom, fp, "hammer2"); - - /* - * Setup LNK_CONN fields for autoinitiated state machine. We - * will use SPANs to advertise multiple PFSs so only pass the - * fsid and HAMMER2_PFSTYPE_SUPROOT for the AUTOCONN. - * - * We are not initiating a LNK_SPAN so we do not have to set-up - * iocom.auto_lnk_span. - */ - bzero(&hmp->iocom.auto_lnk_conn.pfs_clid, - sizeof(hmp->iocom.auto_lnk_conn.pfs_clid)); - hmp->iocom.auto_lnk_conn.pfs_fsid = hmp->voldata.fsid; - hmp->iocom.auto_lnk_conn.pfs_type = HAMMER2_PFSTYPE_SUPROOT; - hmp->iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1; -#if 0 - hmp->iocom.auto_lnk_conn.peer_type = hmp->voldata.peer_type; -#endif - hmp->iocom.auto_lnk_conn.peer_type = DMSG_PEER_HAMMER2; - - /* - * Filter adjustment. Clients do not need visibility into other - * clients (otherwise millions of clients would present a serious - * problem). The fs_label also serves to restrict the namespace. - */ - hmp->iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_HAMMER2; - hmp->iocom.auto_lnk_conn.pfs_mask = (uint64_t)-1; - -#if 0 - switch (ipdata->pfs_type) { - case DMSG_PFSTYPE_CLIENT: - hmp->iocom.auto_lnk_conn.peer_mask &= - ~(1LLU << DMSG_PFSTYPE_CLIENT); - break; - default: - break; - } -#endif - - name_len = strlen(name); - if (name_len >= sizeof(hmp->iocom.auto_lnk_conn.fs_label)) - name_len = sizeof(hmp->iocom.auto_lnk_conn.fs_label) - 1; - bcopy(name, hmp->iocom.auto_lnk_conn.fs_label, name_len); - hmp->iocom.auto_lnk_conn.fs_label[name_len] = 0; - - kdmsg_iocom_autoinitiate(&hmp->iocom, hammer2_autodmsg); -} - -static int -hammer2_rcvdmsg(kdmsg_msg_t *msg) -{ - kprintf("RCVMSG %08x\n", msg->tcmd); - - switch(msg->tcmd) { - case DMSG_DBG_SHELL: - /* - * (non-transaction) - * Execute shell command (not supported atm) - */ - kdmsg_msg_result(msg, DMSG_ERR_NOSUPP); - break; - case DMSG_DBG_SHELL | DMSGF_REPLY: - /* - * (non-transaction) - */ - if (msg->aux_data) { - msg->aux_data[msg->aux_size - 1] = 0; - kprintf("HAMMER2 DBG: %s\n", msg->aux_data); - } - break; - default: - /* - * Unsupported message received. We only need to - * reply if it's a transaction in order to close our end. - * Ignore any one-way messages or any further messages - * associated with the transaction. - * - * NOTE: This case also includes DMSG_LNK_ERROR messages - * which might be one-way, replying to those would - * cause an infinite ping-pong. - */ - if (msg->any.head.cmd & DMSGF_CREATE) - kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP); - break; - } - return(0); -} - -/* - * This function is called after KDMSG has automatically handled processing - * of a LNK layer message (typically CONN, SPAN, or CIRC). - * - * We tag off the LNK_CONN to trigger our LNK_VOLCONF messages which - * advertises all available hammer2 super-root volumes. - */ -static void hammer2_update_spans(hammer2_mount_t *hmp, kdmsg_state_t *state); - -static void -hammer2_autodmsg(kdmsg_msg_t *msg) -{ - hammer2_mount_t *hmp = msg->state->iocom->handle; - int copyid; - - kprintf("RCAMSG %08x\n", msg->tcmd); - - switch(msg->tcmd) { - case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_REPLY: - case DMSG_LNK_CONN | DMSGF_CREATE | DMSGF_DELETE | DMSGF_REPLY: - if (msg->any.head.cmd & DMSGF_CREATE) { - kprintf("HAMMER2: VOLDATA DUMP\n"); - - /* - * Dump the configuration stored in the volume header. - * This will typically be import/export access rights, - * master encryption keys (encrypted), etc. - */ - hammer2_voldata_lock(hmp); - copyid = 0; - while (copyid < HAMMER2_COPYID_COUNT) { - if (hmp->voldata.copyinfo[copyid].copyid) - hammer2_volconf_update(hmp, copyid); - ++copyid; - } - hammer2_voldata_unlock(hmp); - - kprintf("HAMMER2: INITIATE SPANs\n"); - hammer2_update_spans(hmp, msg->state); - } - if ((msg->any.head.cmd & DMSGF_DELETE) && - msg->state && (msg->state->txcmd & DMSGF_DELETE) == 0) { - kprintf("HAMMER2: CONN WAS TERMINATED\n"); - } - break; - default: - break; - } -} - -/* - * Update LNK_SPAN state - */ -static void -hammer2_update_spans(hammer2_mount_t *hmp, kdmsg_state_t *state) -{ - const hammer2_inode_data_t *ripdata; - hammer2_cluster_t *cparent; - hammer2_cluster_t *cluster; - hammer2_pfsmount_t *spmp; - hammer2_key_t key_next; - kdmsg_msg_t *rmsg; - size_t name_len; - int ddflag; - - /* - * Lookup mount point under the media-localized super-root. - * - * cluster->pmp will incorrectly point to spmp and must be fixed - * up later on. - */ - spmp = hmp->spmp; - cparent = hammer2_inode_lock_ex(spmp->iroot); - cluster = hammer2_cluster_lookup(cparent, &key_next, - HAMMER2_KEY_MIN, - HAMMER2_KEY_MAX, - 0, &ddflag); - while (cluster) { - if (hammer2_cluster_type(cluster) != HAMMER2_BREF_TYPE_INODE) - continue; - ripdata = &hammer2_cluster_rdata(cluster)->ipdata; - kprintf("UPDATE SPANS: %s\n", ripdata->filename); - - rmsg = kdmsg_msg_alloc(state, DMSG_LNK_SPAN | DMSGF_CREATE, - hammer2_lnk_span_reply, NULL); - rmsg->any.lnk_span.pfs_clid = ripdata->pfs_clid; - rmsg->any.lnk_span.pfs_fsid = ripdata->pfs_fsid; - rmsg->any.lnk_span.pfs_type = ripdata->pfs_type; - rmsg->any.lnk_span.peer_type = DMSG_PEER_HAMMER2; - rmsg->any.lnk_span.proto_version = DMSG_SPAN_PROTO_1; - name_len = ripdata->name_len; - if (name_len >= sizeof(rmsg->any.lnk_span.fs_label)) - name_len = sizeof(rmsg->any.lnk_span.fs_label) - 1; - bcopy(ripdata->filename, rmsg->any.lnk_span.fs_label, name_len); - - kdmsg_msg_write(rmsg); - - cluster = hammer2_cluster_next(cparent, cluster, - &key_next, - key_next, - HAMMER2_KEY_MAX, - 0); - } - hammer2_inode_unlock_ex(spmp->iroot, cparent); -} - -static -int -hammer2_lnk_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg) -{ - if ((state->txcmd & DMSGF_DELETE) == 0 && - (msg->any.head.cmd & DMSGF_DELETE)) { - kdmsg_msg_reply(msg, 0); - } - return 0; -} - -/* - * Volume configuration updates are passed onto the userland service - * daemon via the open LNK_CONN transaction. - */ -void -hammer2_volconf_update(hammer2_mount_t *hmp, int index) -{ - kdmsg_msg_t *msg; - - /* XXX interlock against connection state termination */ - kprintf("volconf update %p\n", hmp->iocom.conn_state); - if (hmp->iocom.conn_state) { - kprintf("TRANSMIT VOLCONF VIA OPEN CONN TRANSACTION\n"); - msg = kdmsg_msg_alloc(hmp->iocom.conn_state, - DMSG_LNK_HAMMER2_VOLCONF, - NULL, NULL); - H2_LNK_VOLCONF(msg)->copy = hmp->voldata.copyinfo[index]; - H2_LNK_VOLCONF(msg)->mediaid = hmp->voldata.fsid; - H2_LNK_VOLCONF(msg)->index = index; - kdmsg_msg_write(msg); - } -} - /* * This handles hysteresis on regular file flushes. Because the BIOs are * routed to a thread it is possible for an excessive number to build up -- 2.41.0