member.o \
                                memory.o \
                                midcomms.o \
+                               netlink.o \
                                lowcomms.o \
                                rcom.o \
                                recover.o \
 
        unsigned int cl_scan_secs;
        unsigned int cl_log_debug;
        unsigned int cl_protocol;
+       unsigned int cl_timewarn_cs;
 };
 
 enum {
        CLUSTER_ATTR_SCAN_SECS,
        CLUSTER_ATTR_LOG_DEBUG,
        CLUSTER_ATTR_PROTOCOL,
+       CLUSTER_ATTR_TIMEWARN_CS,
 };
 
 struct cluster_attribute {
 CLUSTER_ATTR(scan_secs, 1);
 CLUSTER_ATTR(log_debug, 0);
 CLUSTER_ATTR(protocol, 0);
+CLUSTER_ATTR(timewarn_cs, 1);
 
 static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
        [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
        [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
        [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
+       [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
        NULL,
 };
 
 #define DEFAULT_SCAN_SECS          5
 #define DEFAULT_LOG_DEBUG          0
 #define DEFAULT_PROTOCOL           0
+#define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */
 
 struct dlm_config_info dlm_config = {
        .ci_tcp_port = DEFAULT_TCP_PORT,
        .ci_toss_secs = DEFAULT_TOSS_SECS,
        .ci_scan_secs = DEFAULT_SCAN_SECS,
        .ci_log_debug = DEFAULT_LOG_DEBUG,
-       .ci_protocol = DEFAULT_PROTOCOL
+       .ci_protocol = DEFAULT_PROTOCOL,
+       .ci_timewarn_cs = DEFAULT_TIMEWARN_CS
 };
 
 
        int ci_scan_secs;
        int ci_log_debug;
        int ci_protocol;
+       int ci_timewarn_cs;
 };
 
 extern struct dlm_config_info dlm_config;
 
 #define DLM_IFL_OVERLAP_UNLOCK  0x00080000
 #define DLM_IFL_OVERLAP_CANCEL  0x00100000
 #define DLM_IFL_ENDOFLIFE      0x00200000
+#define DLM_IFL_WATCH_TIMEWARN 0x00400000
 #define DLM_IFL_USER           0x00000001
 #define DLM_IFL_ORPHAN         0x00000002
+#define DLM_IFL_TIMEOUT_CANCEL 0x00000004
 
 struct dlm_lkb {
        struct dlm_rsb          *lkb_resource;  /* the rsb */
        struct list_head        lkb_wait_reply; /* waiting for remote reply */
        struct list_head        lkb_astqueue;   /* need ast to be sent */
        struct list_head        lkb_ownqueue;   /* list of locks for a process */
+       struct list_head        lkb_time_list;
+       unsigned long           lkb_timestamp;
+       unsigned long           lkb_timeout_cs;
 
        char                    *lkb_lvbptr;
        struct dlm_lksb         *lkb_lksb;      /* caller's status block */
        struct mutex            ls_orphans_mutex;
        struct list_head        ls_orphans;
 
+       struct mutex            ls_timeout_mutex;
+       struct list_head        ls_timeout;
+
        struct list_head        ls_nodes;       /* current nodes in ls */
        struct list_head        ls_nodes_gone;  /* dead node list, recovery */
        int                     ls_num_nodes;   /* number of nodes in ls */
        struct task_struct      *ls_recoverd_task;
        struct mutex            ls_recoverd_active;
        spinlock_t              ls_recover_lock;
+       unsigned long           ls_recover_begin; /* jiffies timestamp */
        uint32_t                ls_recover_status; /* DLM_RS_ */
        uint64_t                ls_recover_seq;
        struct dlm_recover      *ls_recover_args;
 #define LSFL_RCOM_READY                3
 #define LSFL_RCOM_WAIT         4
 #define LSFL_UEVENT_WAIT       5
+#define LSFL_TIMEWARN          6
 
 /* much of this is just saving user space pointers associated with the
    lock that we pass back to the user lib with an ast */
 
 static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
 static int send_remove(struct dlm_rsb *r);
 static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
 static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
                                    struct dlm_message *ms);
 static int receive_extralen(struct dlm_message *ms);
 static void do_purge(struct dlm_ls *ls, int nodeid, int pid);
+static void del_timeout(struct dlm_lkb *lkb);
+void dlm_timeout_warn(struct dlm_lkb *lkb);
 
 /*
  * Lock compatibilty matrix - thanks Steve
        if (is_master_copy(lkb))
                return;
 
+       del_timeout(lkb);
+
        DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
 
+       /* if the operation was a cancel, then return -DLM_ECANCEL, if a
+          timeout caused the cancel then return -ETIMEDOUT */
+       if (rv == -DLM_ECANCEL && (lkb->lkb_flags & DLM_IFL_TIMEOUT_CANCEL)) {
+               lkb->lkb_flags &= ~DLM_IFL_TIMEOUT_CANCEL;
+               rv = -ETIMEDOUT;
+       }
+
        lkb->lkb_lksb->sb_status = rv;
        lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
 
        kref_init(&lkb->lkb_ref);
        INIT_LIST_HEAD(&lkb->lkb_ownqueue);
        INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
+       INIT_LIST_HEAD(&lkb->lkb_time_list);
 
        get_random_bytes(&bucket, sizeof(bucket));
        bucket &= (ls->ls_lkbtbl_size - 1);
        }
 }
 
+static void add_timeout(struct dlm_lkb *lkb)
+{
+       struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+
+       if (is_master_copy(lkb))
+               return;
+
+       if (lkb->lkb_exflags & DLM_LKF_TIMEOUT)
+               goto add_it;
+
+       if (test_bit(LSFL_TIMEWARN, &ls->ls_flags) &&
+           !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) {
+               lkb->lkb_flags |= DLM_IFL_WATCH_TIMEWARN;
+               goto add_it;
+       }
+       return;
+
+ add_it:
+       DLM_ASSERT(list_empty(&lkb->lkb_time_list), dlm_print_lkb(lkb););
+       mutex_lock(&ls->ls_timeout_mutex);
+       hold_lkb(lkb);
+       lkb->lkb_timestamp = jiffies;
+       list_add_tail(&lkb->lkb_time_list, &ls->ls_timeout);
+       mutex_unlock(&ls->ls_timeout_mutex);
+}
+
+static void del_timeout(struct dlm_lkb *lkb)
+{
+       struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+
+       mutex_lock(&ls->ls_timeout_mutex);
+       if (!list_empty(&lkb->lkb_time_list)) {
+               list_del_init(&lkb->lkb_time_list);
+               unhold_lkb(lkb);
+       }
+       mutex_unlock(&ls->ls_timeout_mutex);
+}
+
+/* FIXME: is it safe to look at lkb_exflags, lkb_flags, lkb_timestamp, and
+   lkb_lksb_timeout without lock_rsb?  Note: we can't lock timeout_mutex
+   and then lock rsb because of lock ordering in add_timeout.  We may need
+   to specify some special timeout-related bits in the lkb that are just to
+   be accessed under the timeout_mutex. */
+
+void dlm_scan_timeout(struct dlm_ls *ls)
+{
+       struct dlm_rsb *r;
+       struct dlm_lkb *lkb;
+       int do_cancel, do_warn;
+
+       for (;;) {
+               if (dlm_locking_stopped(ls))
+                       break;
+
+               do_cancel = 0;
+               do_warn = 0;
+               mutex_lock(&ls->ls_timeout_mutex);
+               list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list) {
+
+                       if ((lkb->lkb_exflags & DLM_LKF_TIMEOUT) &&
+                           time_after_eq(jiffies, lkb->lkb_timestamp +
+                                         lkb->lkb_timeout_cs * HZ/100))
+                               do_cancel = 1;
+
+                       if ((lkb->lkb_flags & DLM_IFL_WATCH_TIMEWARN) &&
+                           time_after_eq(jiffies, lkb->lkb_timestamp +
+                                          dlm_config.ci_timewarn_cs * HZ/100))
+                               do_warn = 1;
+
+                       if (!do_cancel && !do_warn)
+                               continue;
+                       hold_lkb(lkb);
+                       break;
+               }
+               mutex_unlock(&ls->ls_timeout_mutex);
+
+               if (!do_cancel && !do_warn)
+                       break;
+
+               r = lkb->lkb_resource;
+               hold_rsb(r);
+               lock_rsb(r);
+
+               if (do_warn) {
+                       /* clear flag so we only warn once */
+                       lkb->lkb_flags &= ~DLM_IFL_WATCH_TIMEWARN;
+                       if (!(lkb->lkb_exflags & DLM_LKF_TIMEOUT))
+                               del_timeout(lkb);
+                       dlm_timeout_warn(lkb);
+               }
+
+               if (do_cancel) {
+                       lkb->lkb_flags &= ~DLM_IFL_WATCH_TIMEWARN;
+                       lkb->lkb_flags |= DLM_IFL_TIMEOUT_CANCEL;
+                       del_timeout(lkb);
+                       _cancel_lock(r, lkb);
+               }
+
+               unlock_rsb(r);
+               unhold_rsb(r);
+               dlm_put_lkb(lkb);
+       }
+}
+
+/* This is only called by dlm_recoverd, and we rely on dlm_ls_stop() stopping
+   dlm_recoverd before checking/setting ls_recover_begin. */
+
+void dlm_adjust_timeouts(struct dlm_ls *ls)
+{
+       struct dlm_lkb *lkb;
+       long adj = jiffies - ls->ls_recover_begin;
+
+       ls->ls_recover_begin = 0;
+       mutex_lock(&ls->ls_timeout_mutex);
+       list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
+               lkb->lkb_timestamp += adj;
+       mutex_unlock(&ls->ls_timeout_mutex);
+}
+
 /* lkb is master or local copy */
 
 static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
                if (is_overlap(lkb))
                        goto out;
 
+               /* don't let scand try to do a cancel */
+               del_timeout(lkb);
+
                if (lkb->lkb_flags & DLM_IFL_RESEND) {
                        lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
                        rv = -EBUSY;
                if (is_overlap_unlock(lkb))
                        goto out;
 
+               /* don't let scand try to do a cancel */
+               del_timeout(lkb);
+
                if (lkb->lkb_flags & DLM_IFL_RESEND) {
                        lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
                        rv = -EBUSY;
                error = -EINPROGRESS;
                add_lkb(r, lkb, DLM_LKSTS_WAITING);
                send_blocking_asts(r, lkb);
+               add_timeout(lkb);
                goto out;
        }
 
                del_lkb(r, lkb);
                add_lkb(r, lkb, DLM_LKSTS_CONVERT);
                send_blocking_asts(r, lkb);
+               add_timeout(lkb);
                goto out;
        }
 
                lkb->lkb_remid = ms->m_lkid;
                if (is_altmode(lkb))
                        munge_altmode(lkb, ms);
-               if (result)
+               if (result) {
                        add_lkb(r, lkb, DLM_LKSTS_WAITING);
-               else {
+                       add_timeout(lkb);
+               } else {
                        grant_lock_pc(r, lkb, ms);
                        queue_cast(r, lkb, 0);
                }
                        munge_demoted(lkb, ms);
                del_lkb(r, lkb);
                add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+               add_timeout(lkb);
                break;
 
        case 0:
 
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 void dlm_scan_rsbs(struct dlm_ls *ls);
 int dlm_lock_recovery_try(struct dlm_ls *ls);
 void dlm_unlock_recovery(struct dlm_ls *ls);
+void dlm_scan_timeout(struct dlm_ls *ls);
+void dlm_adjust_timeouts(struct dlm_ls *ls);
 
 int dlm_purge_locks(struct dlm_ls *ls);
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
 
                list_for_each_entry(ls, &lslist, ls_list) {
                        if (dlm_lock_recovery_try(ls)) {
                                dlm_scan_rsbs(ls);
+                               dlm_scan_timeout(ls);
                                dlm_unlock_recovery(ls);
                        }
                }
                goto out;
        memcpy(ls->ls_name, name, namelen);
        ls->ls_namelen = namelen;
-       ls->ls_exflags = flags;
        ls->ls_lvblen = lvblen;
        ls->ls_count = 0;
        ls->ls_flags = 0;
 
+       /* ls_exflags are forced to match among nodes, and we don't
+          need to require all nodes to have TIMEWARN active */
+       if (flags & DLM_LSFL_TIMEWARN)
+               set_bit(LSFL_TIMEWARN, &ls->ls_flags);
+       ls->ls_exflags = (flags & ~DLM_LSFL_TIMEWARN);
+
        size = dlm_config.ci_rsbtbl_size;
        ls->ls_rsbtbl_size = size;
 
        mutex_init(&ls->ls_waiters_mutex);
        INIT_LIST_HEAD(&ls->ls_orphans);
        mutex_init(&ls->ls_orphans_mutex);
+       INIT_LIST_HEAD(&ls->ls_timeout);
+       mutex_init(&ls->ls_timeout_mutex);
 
        INIT_LIST_HEAD(&ls->ls_nodes);
        INIT_LIST_HEAD(&ls->ls_nodes_gone);
 
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 static inline int dlm_register_debugfs(void) { return 0; }
 static inline void dlm_unregister_debugfs(void) { }
 #endif
+int dlm_netlink_init(void);
+void dlm_netlink_exit(void);
 
 static int __init init_dlm(void)
 {
        if (error)
                goto out_debug;
 
+       error = dlm_netlink_init();
+       if (error)
+               goto out_user;
+
        printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
 
        return 0;
 
+ out_user:
+       dlm_user_exit();
  out_debug:
        dlm_unregister_debugfs();
  out_config:
 
 static void __exit exit_dlm(void)
 {
+       dlm_netlink_exit();
        dlm_user_exit();
        dlm_config_exit();
        dlm_memory_exit();
 
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
        dlm_recoverd_suspend(ls);
        ls->ls_recover_status = 0;
        dlm_recoverd_resume(ls);
+
+       if (!ls->ls_recover_begin)
+               ls->ls_recover_begin = jiffies;
        return 0;
 }
 
 
--- /dev/null
+/*
+ * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#include <net/genetlink.h>
+#include <linux/dlm.h>
+#include <linux/dlm_netlink.h>
+
+#include "dlm_internal.h"
+
+static uint32_t dlm_nl_seqnum;
+static uint32_t listener_nlpid;
+
+static struct genl_family family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = DLM_GENL_NAME,
+       .version        = DLM_GENL_VERSION,
+};
+
+static int prepare_data(u8 cmd, struct sk_buff **skbp, size_t size)
+{
+       struct sk_buff *skb;
+       void *data;
+
+       skb = genlmsg_new(size, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       /* add the message headers */
+       data = genlmsg_put(skb, 0, dlm_nl_seqnum++, &family, 0, cmd);
+       if (!data) {
+               nlmsg_free(skb);
+               return -EINVAL;
+       }
+
+       *skbp = skb;
+       return 0;
+}
+
+static struct dlm_lock_data *mk_data(struct sk_buff *skb)
+{
+       struct nlattr *ret;
+
+       ret = nla_reserve(skb, DLM_TYPE_LOCK, sizeof(struct dlm_lock_data));
+       if (!ret)
+               return NULL;
+       return nla_data(ret);
+}
+
+static int send_data(struct sk_buff *skb)
+{
+       struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+       void *data = genlmsg_data(genlhdr);
+       int rv;
+
+       rv = genlmsg_end(skb, data);
+       if (rv < 0) {
+               nlmsg_free(skb);
+               return rv;
+       }
+
+       return genlmsg_unicast(skb, listener_nlpid);
+}
+
+static int user_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+       listener_nlpid = info->snd_pid;
+       printk("user_cmd nlpid %u\n", listener_nlpid);
+       return 0;
+}
+
+static struct genl_ops dlm_nl_ops = {
+       .cmd            = DLM_CMD_HELLO,
+       .doit           = user_cmd,
+};
+
+int dlm_netlink_init(void)
+{
+       int rv;
+
+       rv = genl_register_family(&family);
+       if (rv)
+               return rv;
+
+       rv = genl_register_ops(&family, &dlm_nl_ops);
+       if (rv < 0)
+               goto err;
+       return 0;
+ err:
+       genl_unregister_family(&family);
+       return rv;
+}
+
+void dlm_netlink_exit(void)
+{
+       genl_unregister_ops(&family, &dlm_nl_ops);
+       genl_unregister_family(&family);
+}
+
+static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb)
+{
+       struct dlm_rsb *r = lkb->lkb_resource;
+       struct dlm_user_args *ua = (struct dlm_user_args *) lkb->lkb_astparam;
+
+       memset(data, 0, sizeof(struct dlm_lock_data));
+
+       data->version = DLM_LOCK_DATA_VERSION;
+       data->nodeid = lkb->lkb_nodeid;
+       data->ownpid = lkb->lkb_ownpid;
+       data->id = lkb->lkb_id;
+       data->remid = lkb->lkb_remid;
+       data->status = lkb->lkb_status;
+       data->grmode = lkb->lkb_grmode;
+       data->rqmode = lkb->lkb_rqmode;
+       data->timestamp = lkb->lkb_timestamp;
+       if (ua)
+               data->xid = ua->xid;
+       if (r) {
+               data->lockspace_id = r->res_ls->ls_global_id;
+               data->resource_namelen = r->res_length;
+               memcpy(data->resource_name, r->res_name, r->res_length);
+       }
+}
+
+void dlm_timeout_warn(struct dlm_lkb *lkb)
+{
+       struct dlm_lock_data *data;
+       struct sk_buff *send_skb;
+       size_t size;
+       int rv;
+
+       log_debug(lkb->lkb_resource->res_ls, "timeout_warn %x", lkb->lkb_id);
+
+       size = nla_total_size(sizeof(struct dlm_lock_data)) +
+              nla_total_size(0); /* why this? */
+
+       rv = prepare_data(DLM_CMD_TIMEOUT, &send_skb, size);
+       if (rv < 0)
+               return;
+
+       data = mk_data(send_skb);
+       if (!data) {
+               nlmsg_free(send_skb);
+               return;
+       }
+
+       fill_data(data, lkb);
+
+       send_data(send_skb);
+}
+
 
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 
        dlm_clear_members_gone(ls);
 
+       dlm_adjust_timeouts(ls);
+
        error = enable_locking(ls, rv->seq);
        if (error) {
                log_debug(ls, "enable_locking failed %d", error);
 
                return -EPERM;
 
        error = dlm_new_lockspace(params->name, strlen(params->name),
-                                 &lockspace, 0, DLM_USER_LVB_LEN);
+                                 &lockspace, params->flags, DLM_USER_LVB_LEN);
        if (error)
                return error;
 
 
 header-y += const.h
 header-y += cycx_cfm.h
 header-y += dlm_device.h
+header-y += dlm_netlink.h
 header-y += dm-ioctl.h
 header-y += dn.h
 header-y += dqblk_v1.h
 
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 #define DLM_LKF_ALTPR          0x00008000
 #define DLM_LKF_ALTCW          0x00010000
 #define DLM_LKF_FORCEUNLOCK    0x00020000
+#define DLM_LKF_TIMEOUT                0x00040000
 
 /*
  * Some return codes that are not in errno.h
        char *   sb_lvbptr;
 };
 
+#define DLM_LSFL_NODIR         0x00000001
+#define DLM_LSFL_TIMEWARN      0x00000002
 
 #ifdef __KERNEL__
 
-#define DLM_LSFL_NODIR         0x00000001
-
 /*
  * dlm_new_lockspace
  *
 
--- /dev/null
+/*
+ * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef _DLM_NETLINK_H
+#define _DLM_NETLINK_H
+
+enum {
+       DLM_STATUS_WAITING = 1,
+       DLM_STATUS_GRANTED = 2,
+       DLM_STATUS_CONVERT = 3,
+};
+
+#define DLM_LOCK_DATA_VERSION 1
+
+struct dlm_lock_data {
+       uint16_t version;
+       uint32_t lockspace_id;
+       int nodeid;
+       int ownpid;
+       uint32_t id;
+       uint32_t remid;
+       uint64_t xid;
+       int8_t status;
+       int8_t grmode;
+       int8_t rqmode;
+       unsigned long timestamp;
+       int resource_namelen;
+       char resource_name[DLM_RESNAME_MAXLEN];
+};
+
+enum {
+       DLM_CMD_UNSPEC = 0,
+       DLM_CMD_HELLO,          /* user->kernel */
+       DLM_CMD_TIMEOUT,        /* kernel->user */
+       __DLM_CMD_MAX,
+};
+
+#define DLM_CMD_MAX (__DLM_CMD_MAX - 1)
+
+enum {
+       DLM_TYPE_UNSPEC = 0,
+       DLM_TYPE_LOCK,
+       __DLM_TYPE_MAX,
+};
+
+#define DLM_TYPE_MAX (__DLM_TYPE_MAX - 1)
+
+#define DLM_GENL_VERSION 0x1
+#define DLM_GENL_NAME "DLM"
+
+#endif /* _DLM_NETLINK_H */