-2008-07-15 Robert Read <rread@sun.com>
+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
--- /dev/null
+/* -*- 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 <nathan.rutman@sun.com>
+ *
+ * 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 <libcfs/libcfs.h> 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__ */
+
--- /dev/null
+/* -*- 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 <nathan.rutman@sun.com>
+ *
+ * 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 <libcfs/libcfs.h> 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
+
--- /dev/null
+/* -*- 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 <nathan.rutman@sun.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+
+#include <libcfs/libcfs.h>
+
+/* 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
+
--- /dev/null
+EXTRA_DIST := ulinux-kernelcomm.c
+
--- /dev/null
+/* -*- 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 <nathan.rutman@sun.com>
+ *
+ * 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 <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <libcfs/libcfs.h>
+
+/** 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 */
+
* 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.
--- /dev/null
+/* -*- 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 <nathan.rutman@sun.com>
+ *
+ */
+
+/* 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 <stdio.h>
+#include <libcfs/libcfs.h>
+#include <lustre/lustre_user.h>
+#include <lustre/liblustreapi.h>
+
+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;
+}
+
+
+