fix setattr error handling in sysfs, configfs
[safe/jmp/linux-2.6] / fs / dlm / debug_fs.c
index 9e27a16..c6cf251 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2009 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
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
+#include <linux/slab.h>
 
 #include "dlm_internal.h"
 #include "lock.h"
@@ -25,17 +26,6 @@ static struct mutex debug_buf_lock;
 
 static struct dentry *dlm_root;
 
-struct rsb_iter {
-       int entry;
-       struct dlm_ls *ls;
-       struct list_head *next;
-       struct dlm_rsb *rsb;
-};
-
-/*
- * dump all rsb's in the lockspace hash table
- */
-
 static char *print_lockmode(int mode)
 {
        switch (mode) {
@@ -58,13 +48,13 @@ static char *print_lockmode(int mode)
        }
 }
 
-static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
-                      struct dlm_rsb *res)
+static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
+                             struct dlm_rsb *res)
 {
        seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
 
-       if (lkb->lkb_status == DLM_LKSTS_CONVERT
-           || lkb->lkb_status == DLM_LKSTS_WAITING)
+       if (lkb->lkb_status == DLM_LKSTS_CONVERT ||
+           lkb->lkb_status == DLM_LKSTS_WAITING)
                seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
 
        if (lkb->lkb_nodeid) {
@@ -78,31 +68,42 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
        if (lkb->lkb_wait_type)
                seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
 
-       seq_printf(s, "\n");
+       return seq_printf(s, "\n");
 }
 
-static int print_resource(struct dlm_rsb *res, struct seq_file *s)
+static int print_format1(struct dlm_rsb *res, struct seq_file *s)
 {
        struct dlm_lkb *lkb;
        int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
+       int rv;
+
+       lock_rsb(res);
+
+       rv = seq_printf(s, "\nResource %p Name (len=%d) \"",
+                       res, res->res_length);
+       if (rv)
+               goto out;
 
-       seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
        for (i = 0; i < res->res_length; i++) {
                if (isprint(res->res_name[i]))
                        seq_printf(s, "%c", res->res_name[i]);
                else
                        seq_printf(s, "%c", '.');
        }
+
        if (res->res_nodeid > 0)
-               seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
-                          res->res_nodeid);
+               rv = seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
+                               res->res_nodeid);
        else if (res->res_nodeid == 0)
-               seq_printf(s, "\"  \nMaster Copy\n");
+               rv = seq_printf(s, "\"  \nMaster Copy\n");
        else if (res->res_nodeid == -1)
-               seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
-                          res->res_first_lkid);
+               rv = seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
+                               res->res_first_lkid);
        else
-               seq_printf(s, "\"  \nInvalid master %d\n", res->res_nodeid);
+               rv = seq_printf(s, "\"  \nInvalid master %d\n",
+                               res->res_nodeid);
+       if (rv)
+               goto out;
 
        /* Print the LVB: */
        if (res->res_lvbptr) {
@@ -115,188 +116,489 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s)
                }
                if (rsb_flag(res, RSB_VALNOTVALID))
                        seq_printf(s, " (INVALID)");
-               seq_printf(s, "\n");
+               rv = seq_printf(s, "\n");
+               if (rv)
+                       goto out;
        }
 
        root_list = !list_empty(&res->res_root_list);
        recover_list = !list_empty(&res->res_recover_list);
 
        if (root_list || recover_list) {
-               seq_printf(s, "Recovery: root %d recover %d flags %lx "
-                          "count %d\n", root_list, recover_list,
-                          res->res_flags, res->res_recover_locks_count);
+               rv = seq_printf(s, "Recovery: root %d recover %d flags %lx "
+                               "count %d\n", root_list, recover_list,
+                               res->res_flags, res->res_recover_locks_count);
+               if (rv)
+                       goto out;
        }
 
        /* Print the locks attached to this resource */
        seq_printf(s, "Granted Queue\n");
-       list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
-               print_lock(s, lkb, res);
+       list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) {
+               rv = print_format1_lock(s, lkb, res);
+               if (rv)
+                       goto out;
+       }
 
        seq_printf(s, "Conversion Queue\n");
-       list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
-               print_lock(s, lkb, res);
+       list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) {
+               rv = print_format1_lock(s, lkb, res);
+               if (rv)
+                       goto out;
+       }
 
        seq_printf(s, "Waiting Queue\n");
-       list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
-               print_lock(s, lkb, res);
+       list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) {
+               rv = print_format1_lock(s, lkb, res);
+               if (rv)
+                       goto out;
+       }
 
        if (list_empty(&res->res_lookup))
                goto out;
 
        seq_printf(s, "Lookup Queue\n");
        list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
-               seq_printf(s, "%08x %s", lkb->lkb_id,
-                          print_lockmode(lkb->lkb_rqmode));
+               rv = seq_printf(s, "%08x %s", lkb->lkb_id,
+                               print_lockmode(lkb->lkb_rqmode));
                if (lkb->lkb_wait_type)
                        seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
-               seq_printf(s, "\n");
+               rv = seq_printf(s, "\n");
        }
  out:
-       return 0;
+       unlock_rsb(res);
+       return rv;
 }
 
-static int rsb_iter_next(struct rsb_iter *ri)
+static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
+                             struct dlm_rsb *r)
 {
-       struct dlm_ls *ls = ri->ls;
-       int i;
-
-       if (!ri->next) {
- top:
-               /* Find the next non-empty hash bucket */
-               for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
-                       read_lock(&ls->ls_rsbtbl[i].lock);
-                       if (!list_empty(&ls->ls_rsbtbl[i].list)) {
-                               ri->next = ls->ls_rsbtbl[i].list.next;
-                               ri->rsb = list_entry(ri->next, struct dlm_rsb,
-                                                       res_hashchain);
-                               dlm_hold_rsb(ri->rsb);
-                               read_unlock(&ls->ls_rsbtbl[i].lock);
-                               break;
-                       }
-                       read_unlock(&ls->ls_rsbtbl[i].lock);
-                }
-               ri->entry = i;
-
-               if (ri->entry >= ls->ls_rsbtbl_size)
-                       return 1;
-       } else {
-               struct dlm_rsb *old = ri->rsb;
-               i = ri->entry;
-               read_lock(&ls->ls_rsbtbl[i].lock);
-               ri->next = ri->next->next;
-               if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
-                       /* End of list - move to next bucket */
-                       ri->next = NULL;
-                       ri->entry++;
-                       read_unlock(&ls->ls_rsbtbl[i].lock);
-                       dlm_put_rsb(old);
-                       goto top;
-                }
-               ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
-               read_unlock(&ls->ls_rsbtbl[i].lock);
-               dlm_put_rsb(old);
+       u64 xid = 0;
+       u64 us;
+       int rv;
+
+       if (lkb->lkb_flags & DLM_IFL_USER) {
+               if (lkb->lkb_ua)
+                       xid = lkb->lkb_ua->xid;
        }
 
-       return 0;
+       /* microseconds since lkb was added to current queue */
+       us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp));
+
+       /* id nodeid remid pid xid exflags flags sts grmode rqmode time_us
+          r_nodeid r_len r_name */
+
+       rv = seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",
+                       lkb->lkb_id,
+                       lkb->lkb_nodeid,
+                       lkb->lkb_remid,
+                       lkb->lkb_ownpid,
+                       (unsigned long long)xid,
+                       lkb->lkb_exflags,
+                       lkb->lkb_flags,
+                       lkb->lkb_status,
+                       lkb->lkb_grmode,
+                       lkb->lkb_rqmode,
+                       (unsigned long long)us,
+                       r->res_nodeid,
+                       r->res_length,
+                       r->res_name);
+       return rv;
 }
 
-static void rsb_iter_free(struct rsb_iter *ri)
+static int print_format2(struct dlm_rsb *r, struct seq_file *s)
 {
-       kfree(ri);
+       struct dlm_lkb *lkb;
+       int rv = 0;
+
+       lock_rsb(r);
+
+       list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+               rv = print_format2_lock(s, lkb, r);
+               if (rv)
+                       goto out;
+       }
+
+       list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+               rv = print_format2_lock(s, lkb, r);
+               if (rv)
+                       goto out;
+       }
+
+       list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
+               rv = print_format2_lock(s, lkb, r);
+               if (rv)
+                       goto out;
+       }
+ out:
+       unlock_rsb(r);
+       return rv;
 }
 
-static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
+static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
+                             int rsb_lookup)
 {
-       struct rsb_iter *ri;
+       u64 xid = 0;
+       int rv;
 
-       ri = kmalloc(sizeof *ri, GFP_KERNEL);
-       if (!ri)
-               return NULL;
+       if (lkb->lkb_flags & DLM_IFL_USER) {
+               if (lkb->lkb_ua)
+                       xid = lkb->lkb_ua->xid;
+       }
 
-       ri->ls = ls;
-       ri->entry = 0;
-       ri->next = NULL;
+       rv = seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",
+                       lkb->lkb_id,
+                       lkb->lkb_nodeid,
+                       lkb->lkb_remid,
+                       lkb->lkb_ownpid,
+                       (unsigned long long)xid,
+                       lkb->lkb_exflags,
+                       lkb->lkb_flags,
+                       lkb->lkb_status,
+                       lkb->lkb_grmode,
+                       lkb->lkb_rqmode,
+                       lkb->lkb_bastmode,
+                       rsb_lookup,
+                       lkb->lkb_wait_type,
+                       lkb->lkb_lvbseq,
+                       (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
+                       (unsigned long long)ktime_to_ns(lkb->lkb_time_bast));
+       return rv;
+}
 
-       if (rsb_iter_next(ri)) {
-               rsb_iter_free(ri);
-               return NULL;
+static int print_format3(struct dlm_rsb *r, struct seq_file *s)
+{
+       struct dlm_lkb *lkb;
+       int i, lvblen = r->res_ls->ls_lvblen;
+       int print_name = 1;
+       int rv;
+
+       lock_rsb(r);
+
+       rv = seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",
+                       r,
+                       r->res_nodeid,
+                       r->res_first_lkid,
+                       r->res_flags,
+                       !list_empty(&r->res_root_list),
+                       !list_empty(&r->res_recover_list),
+                       r->res_recover_locks_count,
+                       r->res_length);
+       if (rv)
+               goto out;
+
+       for (i = 0; i < r->res_length; i++) {
+               if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
+                       print_name = 0;
+       }
+
+       seq_printf(s, "%s", print_name ? "str " : "hex");
+
+       for (i = 0; i < r->res_length; i++) {
+               if (print_name)
+                       seq_printf(s, "%c", r->res_name[i]);
+               else
+                       seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
+       }
+       rv = seq_printf(s, "\n");
+       if (rv)
+               goto out;
+
+       if (!r->res_lvbptr)
+               goto do_locks;
+
+       seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen);
+
+       for (i = 0; i < lvblen; i++)
+               seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);
+       rv = seq_printf(s, "\n");
+       if (rv)
+               goto out;
+
+ do_locks:
+       list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+               rv = print_format3_lock(s, lkb, 0);
+               if (rv)
+                       goto out;
+       }
+
+       list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+               rv = print_format3_lock(s, lkb, 0);
+               if (rv)
+                       goto out;
+       }
+
+       list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
+               rv = print_format3_lock(s, lkb, 0);
+               if (rv)
+                       goto out;
        }
 
-       return ri;
+       list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {
+               rv = print_format3_lock(s, lkb, 1);
+               if (rv)
+                       goto out;
+       }
+ out:
+       unlock_rsb(r);
+       return rv;
 }
 
-static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
-{
-       struct rsb_iter *ri;
-       loff_t n = *pos;
+struct rsbtbl_iter {
+       struct dlm_rsb *rsb;
+       unsigned bucket;
+       int format;
+       int header;
+};
 
-       ri = rsb_iter_init(file->private);
-       if (!ri)
-               return NULL;
+/* seq_printf returns -1 if the buffer is full, and 0 otherwise.
+   If the buffer is full, seq_printf can be called again, but it
+   does nothing and just returns -1.  So, the these printing routines
+   periodically check the return value to avoid wasting too much time
+   trying to print to a full buffer. */
 
-       while (n--) {
-               if (rsb_iter_next(ri)) {
-                       rsb_iter_free(ri);
-                       return NULL;
+static int table_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+       struct rsbtbl_iter *ri = iter_ptr;
+       int rv = 0;
+
+       switch (ri->format) {
+       case 1:
+               rv = print_format1(ri->rsb, seq);
+               break;
+       case 2:
+               if (ri->header) {
+                       seq_printf(seq, "id nodeid remid pid xid exflags "
+                                       "flags sts grmode rqmode time_ms "
+                                       "r_nodeid r_len r_name\n");
+                       ri->header = 0;
+               }
+               rv = print_format2(ri->rsb, seq);
+               break;
+       case 3:
+               if (ri->header) {
+                       seq_printf(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n");
+                       ri->header = 0;
                }
+               rv = print_format3(ri->rsb, seq);
+               break;
        }
 
-       return ri;
+       return rv;
 }
 
-static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
+static const struct seq_operations format1_seq_ops;
+static const struct seq_operations format2_seq_ops;
+static const struct seq_operations format3_seq_ops;
+
+static void *table_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct rsb_iter *ri = iter_ptr;
+       struct dlm_ls *ls = seq->private;
+       struct rsbtbl_iter *ri;
+       struct dlm_rsb *r;
+       loff_t n = *pos;
+       unsigned bucket, entry;
+
+       bucket = n >> 32;
+       entry = n & ((1LL << 32) - 1);
 
-       (*pos)++;
+       if (bucket >= ls->ls_rsbtbl_size)
+               return NULL;
 
-       if (rsb_iter_next(ri)) {
-               rsb_iter_free(ri);
+       ri = kzalloc(sizeof(struct rsbtbl_iter), GFP_NOFS);
+       if (!ri)
                return NULL;
+       if (n == 0)
+               ri->header = 1;
+       if (seq->op == &format1_seq_ops)
+               ri->format = 1;
+       if (seq->op == &format2_seq_ops)
+               ri->format = 2;
+       if (seq->op == &format3_seq_ops)
+               ri->format = 3;
+
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
+       if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
+               list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list,
+                                   res_hashchain) {
+                       if (!entry--) {
+                               dlm_hold_rsb(r);
+                               ri->rsb = r;
+                               ri->bucket = bucket;
+                               spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+                               return ri;
+                       }
+               }
        }
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+
+       /*
+        * move to the first rsb in the next non-empty bucket
+        */
+
+       /* zero the entry */
+       n &= ~((1LL << 32) - 1);
+
+       while (1) {
+               bucket++;
+               n += 1LL << 32;
 
-       return ri;
+               if (bucket >= ls->ls_rsbtbl_size) {
+                       kfree(ri);
+                       return NULL;
+               }
+
+               spin_lock(&ls->ls_rsbtbl[bucket].lock);
+               if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
+                       r = list_first_entry(&ls->ls_rsbtbl[bucket].list,
+                                            struct dlm_rsb, res_hashchain);
+                       dlm_hold_rsb(r);
+                       ri->rsb = r;
+                       ri->bucket = bucket;
+                       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+                       *pos = n;
+                       return ri;
+               }
+               spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+       }
 }
 
-static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
+static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
 {
-       /* nothing for now */
+       struct dlm_ls *ls = seq->private;
+       struct rsbtbl_iter *ri = iter_ptr;
+       struct list_head *next;
+       struct dlm_rsb *r, *rp;
+       loff_t n = *pos;
+       unsigned bucket;
+
+       bucket = n >> 32;
+
+       /*
+        * move to the next rsb in the same bucket
+        */
+
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
+       rp = ri->rsb;
+       next = rp->res_hashchain.next;
+
+       if (next != &ls->ls_rsbtbl[bucket].list) {
+               r = list_entry(next, struct dlm_rsb, res_hashchain);
+               dlm_hold_rsb(r);
+               ri->rsb = r;
+               spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+               dlm_put_rsb(rp);
+               ++*pos;
+               return ri;
+       }
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+       dlm_put_rsb(rp);
+
+       /*
+        * move to the first rsb in the next non-empty bucket
+        */
+
+       /* zero the entry */
+       n &= ~((1LL << 32) - 1);
+
+       while (1) {
+               bucket++;
+               n += 1LL << 32;
+
+               if (bucket >= ls->ls_rsbtbl_size) {
+                       kfree(ri);
+                       return NULL;
+               }
+
+               spin_lock(&ls->ls_rsbtbl[bucket].lock);
+               if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
+                       r = list_first_entry(&ls->ls_rsbtbl[bucket].list,
+                                            struct dlm_rsb, res_hashchain);
+                       dlm_hold_rsb(r);
+                       ri->rsb = r;
+                       ri->bucket = bucket;
+                       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+                       *pos = n;
+                       return ri;
+               }
+               spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+       }
 }
 
-static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
+static void table_seq_stop(struct seq_file *seq, void *iter_ptr)
 {
-       struct rsb_iter *ri = iter_ptr;
+       struct rsbtbl_iter *ri = iter_ptr;
 
-       print_resource(ri->rsb, file);
-
-       return 0;
+       if (ri) {
+               dlm_put_rsb(ri->rsb);
+               kfree(ri);
+       }
 }
 
-static struct seq_operations rsb_seq_ops = {
-       .start = rsb_seq_start,
-       .next  = rsb_seq_next,
-       .stop  = rsb_seq_stop,
-       .show  = rsb_seq_show,
+static const struct seq_operations format1_seq_ops = {
+       .start = table_seq_start,
+       .next  = table_seq_next,
+       .stop  = table_seq_stop,
+       .show  = table_seq_show,
+};
+
+static const struct seq_operations format2_seq_ops = {
+       .start = table_seq_start,
+       .next  = table_seq_next,
+       .stop  = table_seq_stop,
+       .show  = table_seq_show,
+};
+
+static const struct seq_operations format3_seq_ops = {
+       .start = table_seq_start,
+       .next  = table_seq_next,
+       .stop  = table_seq_stop,
+       .show  = table_seq_show,
 };
 
-static int rsb_open(struct inode *inode, struct file *file)
+static const struct file_operations format1_fops;
+static const struct file_operations format2_fops;
+static const struct file_operations format3_fops;
+
+static int table_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
-       int ret;
+       int ret = -1;
+
+       if (file->f_op == &format1_fops)
+               ret = seq_open(file, &format1_seq_ops);
+       else if (file->f_op == &format2_fops)
+               ret = seq_open(file, &format2_seq_ops);
+       else if (file->f_op == &format3_fops)
+               ret = seq_open(file, &format3_seq_ops);
 
-       ret = seq_open(file, &rsb_seq_ops);
        if (ret)
                return ret;
 
        seq = file->private_data;
-       seq->private = inode->i_private;
-
+       seq->private = inode->i_private; /* the dlm_ls */
        return 0;
 }
 
-static const struct file_operations rsb_fops = {
+static const struct file_operations format1_fops = {
        .owner   = THIS_MODULE,
-       .open    = rsb_open,
+       .open    = table_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release
+};
+
+static const struct file_operations format2_fops = {
+       .owner   = THIS_MODULE,
+       .open    = table_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release
+};
+
+static const struct file_operations format3_fops = {
+       .owner   = THIS_MODULE,
+       .open    = table_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
        .release = seq_release
@@ -344,17 +646,57 @@ static const struct file_operations waiters_fops = {
        .read    = waiters_read
 };
 
+void dlm_delete_debug_file(struct dlm_ls *ls)
+{
+       if (ls->ls_debug_rsb_dentry)
+               debugfs_remove(ls->ls_debug_rsb_dentry);
+       if (ls->ls_debug_waiters_dentry)
+               debugfs_remove(ls->ls_debug_waiters_dentry);
+       if (ls->ls_debug_locks_dentry)
+               debugfs_remove(ls->ls_debug_locks_dentry);
+       if (ls->ls_debug_all_dentry)
+               debugfs_remove(ls->ls_debug_all_dentry);
+}
+
 int dlm_create_debug_file(struct dlm_ls *ls)
 {
        char name[DLM_LOCKSPACE_LEN+8];
 
+       /* format 1 */
+
        ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
                                                      S_IFREG | S_IRUGO,
                                                      dlm_root,
                                                      ls,
-                                                     &rsb_fops);
+                                                     &format1_fops);
        if (!ls->ls_debug_rsb_dentry)
-               return -ENOMEM;
+               goto fail;
+
+       /* format 2 */
+
+       memset(name, 0, sizeof(name));
+       snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name);
+
+       ls->ls_debug_locks_dentry = debugfs_create_file(name,
+                                                       S_IFREG | S_IRUGO,
+                                                       dlm_root,
+                                                       ls,
+                                                       &format2_fops);
+       if (!ls->ls_debug_locks_dentry)
+               goto fail;
+
+       /* format 3 */
+
+       memset(name, 0, sizeof(name));
+       snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_all", ls->ls_name);
+
+       ls->ls_debug_all_dentry = debugfs_create_file(name,
+                                                     S_IFREG | S_IRUGO,
+                                                     dlm_root,
+                                                     ls,
+                                                     &format3_fops);
+       if (!ls->ls_debug_all_dentry)
+               goto fail;
 
        memset(name, 0, sizeof(name));
        snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
@@ -364,23 +706,17 @@ int dlm_create_debug_file(struct dlm_ls *ls)
                                                          dlm_root,
                                                          ls,
                                                          &waiters_fops);
-       if (!ls->ls_debug_waiters_dentry) {
-               debugfs_remove(ls->ls_debug_rsb_dentry);
-               return -ENOMEM;
-       }
+       if (!ls->ls_debug_waiters_dentry)
+               goto fail;
 
        return 0;
-}
 
-void dlm_delete_debug_file(struct dlm_ls *ls)
-{
-       if (ls->ls_debug_rsb_dentry)
-               debugfs_remove(ls->ls_debug_rsb_dentry);
-       if (ls->ls_debug_waiters_dentry)
-               debugfs_remove(ls->ls_debug_waiters_dentry);
+ fail:
+       dlm_delete_debug_file(ls);
+       return -ENOMEM;
 }
 
-int dlm_register_debugfs(void)
+int __init dlm_register_debugfs(void)
 {
        mutex_init(&debug_buf_lock);
        dlm_root = debugfs_create_dir("dlm", NULL);