From b5b8aa49e102e57e834c62422ea6cfb2baf62b76 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 28 Jul 2009 19:43:06 +0000 Subject: [PATCH] b=19856 i=adilger i=rread LustreNetLink (LNL) kernel<->userspace communications path HSM copytool llapi based on lnl (commit added files) --- libcfs/ChangeLog | 14 +- libcfs/include/libcfs/libcfs_kernelcomm.h | 115 ++++++++++++++ libcfs/include/libcfs/posix/posix-kernelcomm.h | 59 +++++++ libcfs/libcfs/linux/linux-kernelcomm.c | 206 +++++++++++++++++++++++++ libcfs/libcfs/ulinux/Makefile.am | 2 + libcfs/libcfs/ulinux/ulinux-kernelcomm.c | 180 +++++++++++++++++++++ lustre/ChangeLog | 4 + lustre/tests/copytool.c | 108 +++++++++++++ 8 files changed, 686 insertions(+), 2 deletions(-) create mode 100644 libcfs/include/libcfs/libcfs_kernelcomm.h create mode 100644 libcfs/include/libcfs/posix/posix-kernelcomm.h create mode 100644 libcfs/libcfs/linux/linux-kernelcomm.c create mode 100644 libcfs/libcfs/ulinux/Makefile.am create mode 100644 libcfs/libcfs/ulinux/ulinux-kernelcomm.c create mode 100644 lustre/tests/copytool.c diff --git a/libcfs/ChangeLog b/libcfs/ChangeLog index a783bef..a7b9e08 100644 --- a/libcfs/ChangeLog +++ b/libcfs/ChangeLog @@ -1,4 +1,14 @@ -2008-07-15 Robert Read +tbd Sun Microsystems, Inc. + * version 2.0.0 - * new libcfs module +Severity : enhancement +Bugzilla : 19856 +Description: Add LustreNetLink, a kernel-userspace communcation path. Add + ulinux dir for Linux userspace tools. +------------------------------------------------------------------------------- + +2008-07-15 Sun Microsystems, Inc. + * version 1.8.0 + +new libcfs module diff --git a/libcfs/include/libcfs/libcfs_kernelcomm.h b/libcfs/include/libcfs/libcfs_kernelcomm.h new file mode 100644 index 0000000..8da8c96 --- /dev/null +++ b/libcfs/include/libcfs/libcfs_kernelcomm.h @@ -0,0 +1,115 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Nathan Rutman + * + * libcfs/include/libcfs/libcfs_kernelcomm.h + * + * Kernel <-> userspace communication routines. We'll use a shorthand term + * "lnl" (Lustre NetLink) for this interface name for all arches, even though + * an implemtation may not use NetLink. + * The definitions below are used in the kernel and userspace. + * + */ + +#ifndef __LIBCFS_KERNELCOMM_H__ +#define __LIBCFS_KERNELCOMM_H__ + +#ifndef __LIBCFS_LIBCFS_H__ +#error Do not #include this file directly. #include instead +#endif + +/* LNL message header. + * All current and future LNL messages should use this header. + * To avoid having to include Lustre headers from libcfs, define this here. + */ +struct lnl_hdr { + __u16 lnl_magic; + __u8 lnl_transport; /* Each new Lustre feature should use a different + transport */ + __u8 padding1; + __u16 lnl_msgtype; /* Message type or opcode, transport-specific */ + __u16 lnl_msglen; +} __attribute__((aligned(sizeof(__u64)))); + +#define LNL_MAGIC 0x191C /*Lustre9etLinC */ + +/* lnl_msgtype values are defined in each transport */ +enum lnl_transport_type { + LNL_TRANSPORT_GENERIC = 1, + LNL_TRANSPORT_HSM = 2, +}; + +enum lnl_generic_message_type { + LNL_MSG_SHUTDOWN = 1, +}; + +/* LNL Broadcast Groups. This determines which userspace process hears which + * messages. Mutliple transports may be used within a group, or multiple + * groups may use the same transport. Broadcast + * groups need not be used if e.g. a PID is specified instead. + * Leaving group 0 unassigned at the moment. + */ +#define LNL_GRP_HSM 0x02 +#define LNL_GRP_CNT 2 + + +#if defined(HAVE_NETLINK) && defined (__KERNEL__) +extern int libcfs_klnl_start(int transport); +extern int libcfs_klnl_stop(int transport, int group); +extern int libcfs_klnl_msg_put(int pid, int group, void *payload); +#else +static inline int libcfs_klnl_start(int transport) { + return -ENOSYS; +} +static inline int libcfs_klnl_stop(int transport, int group) { + return 0; +} +static inline int libcfs_klnl_msg_put(int pid, int group, void *payload) { + return -ENOSYS; +} +#endif + +/* + * NetLink socket number, see include/linux/netlink.h + * All LNL users share a single netlink socket. This actually is NetLink + * specific, but is not to be used outside of the Linux implementation + * (linux-kernelcomm.c and posix-kernelcomm.c). + */ +#define LNL_SOCKET 26 + + +#endif /* __LIBCFS_KERNELCOMM_H__ */ + diff --git a/libcfs/include/libcfs/posix/posix-kernelcomm.h b/libcfs/include/libcfs/posix/posix-kernelcomm.h new file mode 100644 index 0000000..7275631 --- /dev/null +++ b/libcfs/include/libcfs/posix/posix-kernelcomm.h @@ -0,0 +1,59 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Nathan Rutman + * + * libcfs/include/libcfs/posix-kernelcomm.h + * + * kernel - userspace communications. + */ + +#ifndef __LIBCFS_POSIX_KERNELCOMM_H__ +#define __LIBCFS_POSIX_KERNELCOMM_H__ + +#ifndef __LIBCFS_LIBCFS_H__ +#error Do not #include this file directly. #include instead +#endif + +typedef int lustre_netlink; +int libcfs_ulnl_start(lustre_netlink *l, int groups); +int libcfs_ulnl_stop(lustre_netlink *l); +struct lnl_hdr; +int libcfs_ulnl_msg_get(lustre_netlink *l, int maxsize, int transport, + struct lnl_hdr **lnlhh); +int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh); + +#endif + diff --git a/libcfs/libcfs/linux/linux-kernelcomm.c b/libcfs/libcfs/linux/linux-kernelcomm.c new file mode 100644 index 0000000..9845b6c --- /dev/null +++ b/libcfs/libcfs/linux/linux-kernelcomm.c @@ -0,0 +1,206 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Nathan Rutman + * + * Kernel <-> userspace communication routines. We'll use a shorthand term + * "lnl" (Lustre NetLink) for the interface names for all arches (even though + * implemtation may not use NetLink). + * For Linux, we use Netlink sockets. + */ + +#define DEBUG_SUBSYSTEM S_CLASS + + +/* This is the kernel side. + * See libcfs/ulinux/ulinux-kernelcomm.c for the user side. + */ + +#if defined(HAVE_NETLINK) && defined(__KERNEL__) + +#include +#include +#include +#include + +#include + +/* Single Netlink Message type to send all Lustre messages */ +#define LNL_MSG 26 + +static struct sock *lnl_socket = NULL; +static atomic_t lnl_start_count = ATOMIC_INIT(0); +static spinlock_t lnl_lock = SPIN_LOCK_UNLOCKED; + +/** Start the netlink socket for this transport + * @param transport lnl_transport + */ +int libcfs_klnl_start(int transport) +{ + int rc = 0; + ENTRY; + + /* If anyone needs it, we can add per-transport incoming message + callbacks. Add the callback as a param here. Store the transport + and callback in a table. Include a generalized incoming msg + callback here to dispatch messages to the appropriate + per-transport callback. */ + + spin_lock(&lnl_lock); + if (atomic_inc_return(&lnl_start_count) > 1) + GOTO(out, rc = 0); + + lnl_socket = netlink_kernel_create(LNL_SOCKET, LNL_GRP_CNT, + NULL /* incoming cb */, + THIS_MODULE); + if (lnl_socket == NULL) { + CERROR("Cannot open socket %d\n", LNL_SOCKET); + atomic_dec(&lnl_start_count); + GOTO(out, rc = -ENODEV); + } + +out: + spin_unlock(&lnl_lock); + RETURN(rc); +} +EXPORT_SYMBOL(libcfs_klnl_start); + +static void send_shutdown_msg(int transport, int group) { + struct lnl_hdr lh; + + lh.lnl_magic = LNL_MAGIC; + lh.lnl_transport = LNL_TRANSPORT_GENERIC; + lh.lnl_msgtype = LNL_MSG_SHUTDOWN; + lh.lnl_msglen = sizeof(lh); + + libcfs_klnl_msg_put(0, group, &lh); +} + +/* This should be called once per (started) transport + * @param transport lnl_transport + * @param group Broadcast group for shutdown message */ +int libcfs_klnl_stop(int transport, int group) +{ + if (group) + send_shutdown_msg(transport, group); + + spin_lock(&lnl_lock); + + if (atomic_dec_and_test(&lnl_start_count)) { + sock_release(lnl_socket->sk_socket); + lnl_socket = NULL; + } + + spin_unlock(&lnl_lock); + return 0; +} +EXPORT_SYMBOL(libcfs_klnl_stop); + +static struct sk_buff *netlink_make_msg(int pid, int seq, void *payload, + int size) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(size); + void *data; + + skb = nlmsg_new(len, GFP_KERNEL); + if (!skb) + return NULL; + + nlh = nlmsg_put(skb, pid, seq, LNL_MSG, size, 0); + if (!nlh) { + nlmsg_free(skb); + return NULL; + } + + data = nlmsg_data(nlh); + memcpy(data, payload, size); + return skb; +} + +/** + * libcfs_klnl_msg_put - send an message from kernel to userspace + * @param pid Process id to send message to for unicast messages; must be 0 for + * broadcast + * @param group Broadcast group; 0 for unicast messages + * @param payload Payload data. First field of payload is always struct lnl_hdr + * + * Allocates an skb, builds the netlink message, and sends it to the pid. + */ +int libcfs_klnl_msg_put(int pid, int group, void *payload) +{ + struct lnl_hdr *lnlh = (struct lnl_hdr *)payload; + struct sk_buff *skb; + int rc; + + if (lnl_socket == NULL) { + CERROR("LustreNetLink: not running\n"); + return -ENOSYS; + } + + if (lnlh->lnl_magic != LNL_MAGIC) { + CERROR("LustreNetLink: bad magic %x\n", lnlh->lnl_magic); + return -ENOSYS; + } + + if ((pid != 0) && (group != 0)) { + CERROR("LustreNetLink: pid=%d or group=%d must be 0\n", + pid, group); + return -EINVAL; + } + + skb = netlink_make_msg(pid, 0, payload, lnlh->lnl_msglen); + if (!skb) + return -ENOMEM; + + if (pid) + rc = nlmsg_unicast(lnl_socket, skb, pid); + else + rc = nlmsg_multicast(lnl_socket, skb, 0, group); + + CDEBUG(0, "Sent message pid=%d, group=%d, rc=%d\n", pid, group, rc); + + if (rc < 0) + CWARN("message send failed (%d) [pid=%d,group=%d]\n", rc, + pid, group); + + return rc; +} +EXPORT_SYMBOL(libcfs_klnl_msg_put); + + +#endif + diff --git a/libcfs/libcfs/ulinux/Makefile.am b/libcfs/libcfs/ulinux/Makefile.am new file mode 100644 index 0000000..0541235 --- /dev/null +++ b/libcfs/libcfs/ulinux/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST := ulinux-kernelcomm.c + diff --git a/libcfs/libcfs/ulinux/ulinux-kernelcomm.c b/libcfs/libcfs/ulinux/ulinux-kernelcomm.c new file mode 100644 index 0000000..8d84316 --- /dev/null +++ b/libcfs/libcfs/ulinux/ulinux-kernelcomm.c @@ -0,0 +1,180 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Nathan Rutman + * + * Kernel - userspace communication routines. We'll use a shorthand term + * "lnl" (Lustre NetLink) for the interface names for all arches (even though + * implemtation may not use NetLink). + * For Linux, we use Netlink sockets. + */ + +#define DEBUG_SUBSYSTEM S_CLASS + +/* This is the userspace side. + * See libcfs/linux/linux-kernelcomm.c for the kernel side. + */ + +#ifdef HAVE_NETLINK + +#include +#include + +#include + +/** Start the userspace side of a LNL pipe. + * @param link Private descriptor for pipe/socket. + * @param groups LNL broadcast group to listen to + * (can be null for unicast to this pid) + */ +int libcfs_ulnl_start(lustre_netlink *link, int groups) +{ + struct sockaddr_nl src_addr; + int sock; + int rc = 0; + + sock = socket(PF_NETLINK, SOCK_RAW, LNL_SOCKET); + if (sock < 0) + return -errno; + + memset(&src_addr, 0, sizeof(src_addr)); + src_addr.nl_family = AF_NETLINK; + src_addr.nl_pid = getpid(); /* self pid */ + src_addr.nl_groups = groups; + rc = bind(sock, (struct sockaddr*)&src_addr, sizeof(src_addr)); + if (rc < 0) { + close(sock); + return -errno; + } + *link = sock; + return 0; +} + +int libcfs_ulnl_stop(lustre_netlink *link) +{ + return close(*link); +} + +/** Read a message from the netlink layer. + * + * @param link Private descriptor for pipe/socket. + * @param maxsize Maximum message size allowed + * @param transport Only listen to messages on this transport + * (and the generic transport) + * @param lnlhh Handle to the new LNL message + */ +int libcfs_ulnl_msg_get(lustre_netlink *link, int maxsize, int transport, + struct lnl_hdr **lnlhh) +{ + struct iovec iov; + struct sockaddr_nl dest_addr; + struct msghdr msg; + struct nlmsghdr *nlh = NULL; + struct lnl_hdr *lnlh; + int rc = 0; + + nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(maxsize)); + if (!nlh) + return -ENOMEM; + + memset(nlh, 0, NLMSG_SPACE(maxsize)); + iov.iov_base = (void *)nlh; + iov.iov_len = NLMSG_SPACE(maxsize); + + memset(&dest_addr, 0, sizeof(dest_addr)); + msg.msg_name = (void *)&dest_addr; + msg.msg_namelen = sizeof(dest_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + CDEBUG(0, "Waiting for message from kernel on pid %d\n", getpid()); + + while (1) { + /* Read message from kernel */ + rc = recvmsg(*link, &msg, 0); + if (rc <= 0) { + perror("recv"); + rc = -errno; + break; + } + lnlh = (struct lnl_hdr *)NLMSG_DATA(nlh); + CDEBUG(0, " Received message mg=%x t=%d m=%d l=%d\n", + lnlh->lnl_magic, lnlh->lnl_transport, lnlh->lnl_msgtype, + lnlh->lnl_msglen); + if (lnlh->lnl_magic != LNL_MAGIC) { + CERROR("bad message magic %x != %x\n", + lnlh->lnl_magic, LNL_MAGIC); + rc = -EPROTO; + break; + } + if (lnlh->lnl_transport == transport || + lnlh->lnl_transport == LNL_TRANSPORT_GENERIC) { + *lnlhh = lnlh; + return 0; + } + /* Ignore messages on other transports */ + } + free(nlh); + return rc; +} + +/* Free a message returned by the above fn */ +int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh) +{ + /* compute nlmsdghdr offset */ + char *p = (char *)NLMSG_DATA(0); + + free((void *)((char *)*lnlhh - p)); + *lnlhh = NULL; + return 0; +} + +#else /* HAVE_NETLINK */ +int libcfs_ulnl_start(lustre_netlink *link, int groups) { + return -ENOSYS; +} +int libcfs_ulnl_stop(lustre_netlink *link) { + return 0; +} + +int libcfs_ulnl_msg_get(lustre_netlink *link, int maxsize, int transport, + struct lnl_hdr **lnlhh) { + return -ENOSYS; +} +int libcfs_ulnl_msg_free(struct lnl_hdr **lnlhh) { + return -ENOSYS; +} +#endif /* HAVE_NETLINK */ + diff --git a/lustre/ChangeLog b/lustre/ChangeLog index a5dd055..38ec1a2 100644 --- a/lustre/ChangeLog +++ b/lustre/ChangeLog @@ -14,6 +14,10 @@ tbd Sun Microsystems, Inc. * File join has been disabled in this release, refer to Bugzilla 16929. Severity : enhancement +Bugzilla : 19856 +Description: Add LustreNetLink, a kernel-userspace communcation path. + +Severity : enhancement Bugzilla : 19847 Description: Update kernel to SLES10 SP2 2.6.16.60-0.39.3. diff --git a/lustre/tests/copytool.c b/lustre/tests/copytool.c new file mode 100644 index 0000000..a74fac3 --- /dev/null +++ b/lustre/tests/copytool.c @@ -0,0 +1,108 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Nathan Rutman + * + */ + +/* HSM copytool example program. + * The copytool acts on action requests from Lustre to copy files to and from + * an HSM archive system. + * + * Note: under Linux, until llapi_copytool_fini is called (or the program is + * killed), the libcfs module will be referenced and unremovable, + * even after Lustre services stop. + */ + +#include +#include +#include +#include + +int main() { + void *ctdata; + int archive_nums[] = {1}; /* which archive numbers we care about */ + int rc; + + rc = llapi_copytool_start(&ctdata, 0, ARRAY_SIZE(archive_nums), + archive_nums); + if (rc < 0) { + fprintf(stderr, "Can't start copytool interface: %s\n", + strerror(-rc)); + return rc; + } + + printf("Waiting for message from kernel (pid=%d)\n", getpid()); + + while(1) { + struct hsm_action_list *hal; + struct hsm_action_item *hai; + int msgsize, i = 0; + + rc = llapi_copytool_recv(ctdata, &hal, &msgsize); + if (rc == -ESHUTDOWN) { + fprintf(stderr, "shutting down"); + break; + } + if (rc < 0) { + fprintf(stderr, "Message receive: %s", strerror(-rc)); + break; + } + if (msgsize == 0) + continue; /* msg not for us */ + + printf("Copytool fs=%s archive#=%d item_count=%d\n", + hal->hal_fsname, hal->hal_archive_num, hal->hal_count); + + hai = hai_zero(hal); + while (++i <= hal->hal_count) { + printf("Item %d: action %d reclen %d\n", i, + hai->hai_action, hai->hai_len); + printf(" "DFID" gid="LPU64" cookie="LPU64"\n", + PFID(&hai->hai_fid), hai->hai_gid, + hai->hai_cookie); + hai = hai_next(hai); + } + + llapi_copytool_free(&hal); + } + + llapi_copytool_fini(&ctdata); + + return 0; +} + + + -- 1.8.3.1