scoutfs: add debugfs "locks" for scoutfs_lock

Add a file for showing the scoutfs_lock struct contents.  This is the
layer above the detailed dlmglue/dlm info provided in the existing
"locking_state" file.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2018-01-12 12:45:31 -08:00
committed by Mark Fasheh
parent a9c7511c8b
commit f54e59eef1
2 changed files with 123 additions and 0 deletions

View File

@@ -17,6 +17,9 @@
#include <linux/dlm.h>
#include <linux/mm.h>
#include <linux/sort.h>
#include <linux/debugfs.h>
#include <linux/idr.h>
#include <linux/ctype.h>
#include "super.h"
#include "lock.h"
@@ -55,6 +58,8 @@ struct lock_info {
struct list_head lru_list;
unsigned long long lru_nr;
struct workqueue_struct *lock_reclaim_wq;
struct dentry *debug_locks_dentry;
struct idr debug_locks_idr;
};
#define DECLARE_LOCK_INFO(sb, name) \
@@ -283,6 +288,9 @@ static void put_scoutfs_lock(struct super_block *sb, struct scoutfs_lock *lock)
RB_CLEAR_NODE(&lock->range_node);
}
list_del(&lock->lru_entry);
if (lock->debug_locks_id)
idr_remove(&linfo->debug_locks_idr,
lock->debug_locks_id);
spin_unlock(&linfo->lock);
ocfs2_simple_drop_lockres(&linfo->dlmglue,
&lock->lockres);
@@ -418,6 +426,7 @@ static struct scoutfs_lock *alloc_scoutfs_lock(struct super_block *sb,
{
DECLARE_LOCK_INFO(sb, linfo);
struct scoutfs_lock *lock;
int id;
if (WARN_ON_ONCE(!!start != !!end))
return NULL;
@@ -426,6 +435,18 @@ static struct scoutfs_lock *alloc_scoutfs_lock(struct super_block *sb,
if (lock == NULL)
return NULL;
idr_preload(GFP_NOFS);
spin_lock(&linfo->lock);
id = idr_alloc(&linfo->debug_locks_idr, lock, 1, INT_MAX, GFP_NOWAIT);
if (id > 0)
lock->debug_locks_id = id;
spin_unlock(&linfo->lock);
idr_preload_end();
if (id <= 0) {
free_scoutfs_lock(lock);
return NULL;
}
RB_CLEAR_NODE(&lock->node);
RB_CLEAR_NODE(&lock->range_node);
@@ -1106,6 +1127,7 @@ static int init_lock_info(struct super_block *sb)
spin_lock_init(&linfo->lock);
INIT_LIST_HEAD(&linfo->lru_list);
idr_init(&linfo->debug_locks_idr);
linfo->shrinker.shrink = shrink_lock_tree;
linfo->shrinker.seeks = DEFAULT_SEEKS;
register_shrinker(&linfo->shrinker);
@@ -1132,6 +1154,9 @@ void scoutfs_lock_destroy(struct super_block *sb)
DECLARE_LOCK_INFO(sb, linfo);
if (linfo) {
/* XXX does anything synchronize with open debugfs fds? */
debugfs_remove(linfo->debug_locks_dentry);
unregister_shrinker(&linfo->shrinker);
if (linfo->lock_reclaim_wq)
destroy_workqueue(linfo->lock_reclaim_wq);
@@ -1140,6 +1165,7 @@ void scoutfs_lock_destroy(struct super_block *sb)
* draining the reclaim workqueue.
*/
free_lock_tree(sb);
idr_destroy(&linfo->debug_locks_idr);
if (linfo->dlmglue_online) {
/*
@@ -1161,6 +1187,94 @@ void scoutfs_lock_destroy(struct super_block *sb)
}
}
/* _stop is always called no matter what start returns */
static void *scoutfs_debug_locks_seq_start(struct seq_file *m, loff_t *pos)
__acquires(linfo->lock)
{
struct super_block *sb = m->private;
DECLARE_LOCK_INFO(sb, linfo);
int id;
spin_lock(&linfo->lock);
if (*pos >= INT_MAX)
return NULL;
id = *pos;
return idr_get_next(&linfo->debug_locks_idr, &id);
}
static void *scoutfs_debug_locks_seq_next(struct seq_file *m, void *v,
loff_t *pos)
{
struct super_block *sb = m->private;
DECLARE_LOCK_INFO(sb, linfo);
struct scoutfs_lock *lock = v;
int id;
id = lock->debug_locks_id + 1;
lock = idr_get_next(&linfo->debug_locks_idr, &id);
if (lock)
*pos = lock->debug_locks_id;
return lock;
}
static void scoutfs_debug_locks_seq_stop(struct seq_file *m, void *v)
__releases(linfo->lock)
{
struct super_block *sb = m->private;
DECLARE_LOCK_INFO(sb, linfo);
spin_unlock(&linfo->lock);
}
/* print an upper or lower case char depending on if the flag is set */
#define locks_flag_char(lock, nr, c) \
(test_bit(nr, &(lock)->flags) ? c : tolower(c))
#define locks_flags(lock) \
locks_flag_char(lock, SCOUTFS_LOCK_RECLAIM, 'R'), \
locks_flag_char(lock, SCOUTFS_LOCK_DROPPED, 'D')
static int scoutfs_debug_locks_seq_show(struct seq_file *m, void *v)
{
struct scoutfs_lock *lock = v;
SK_PCPU(seq_printf(m, "name "LN_FMT" start "SK_FMT" end "SK_FMT" sequence %u refcnt %u users %u flags %c%c\n",
LN_ARG(&lock->lock_name), SK_ARG(lock->start),
SK_ARG(lock->end), lock->sequence, lock->refcnt,
lock->users, locks_flags(lock)));
return 0;
}
static const struct seq_operations scoutfs_debug_locks_seq_ops = {
.start = scoutfs_debug_locks_seq_start,
.next = scoutfs_debug_locks_seq_next,
.stop = scoutfs_debug_locks_seq_stop,
.show = scoutfs_debug_locks_seq_show,
};
static int scoutfs_debug_locks_open(struct inode *inode, struct file *file)
{
struct seq_file *m;
int ret;
ret = seq_open(file, &scoutfs_debug_locks_seq_ops);
if (ret == 0) {
m = file->private_data;
m->private = inode->i_private;
}
return ret;
}
static const struct file_operations scoutfs_debug_locks_fops = {
.open = scoutfs_debug_locks_open,
.release = seq_release,
.read = seq_read,
.llseek = seq_lseek,
};
int scoutfs_lock_setup(struct super_block *sb)
{
struct lock_info *linfo;
@@ -1172,6 +1286,14 @@ int scoutfs_lock_setup(struct super_block *sb)
return ret;
linfo = sbi->lock_info;
linfo->debug_locks_dentry = debugfs_create_file("locks",
S_IFREG|S_IRUSR, sbi->debug_root, sb,
&scoutfs_debug_locks_fops);
if (!linfo->debug_locks_dentry) {
ret = -ENOMEM;
goto out;
}
linfo->lock_reclaim_wq = alloc_workqueue("scoutfs_reclaim",
WQ_UNBOUND|WQ_HIGHPRI, 0);
if (!linfo->lock_reclaim_wq) {

View File

@@ -25,6 +25,7 @@ struct scoutfs_lock {
struct rb_node node;
struct rb_node range_node;
unsigned int refcnt;
unsigned int debug_locks_id;
struct ocfs2_lock_res lockres;
struct list_head lru_entry;
struct work_struct reclaim_work;