summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/glock.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-14 13:18:27 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-14 13:19:04 +0200
commit6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch)
tree021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /fs/gfs2/glock.c
parent682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff)
parenta385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff)
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree), to prepare for tooling changes, and also to pick up v3.4 MM changes that the uprobes code needs to take care of. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'fs/gfs2/glock.c')
-rw-r--r--fs/gfs2/glock.c210
1 files changed, 202 insertions, 8 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 351a3e79778..dab2526071c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -29,6 +29,7 @@
#include <linux/rcupdate.h>
#include <linux/rculist_bl.h>
#include <linux/bit_spinlock.h>
+#include <linux/percpu.h>
#include "gfs2.h"
#include "incore.h"
@@ -543,6 +544,11 @@ __acquires(&gl->gl_spin)
do_error(gl, 0); /* Fail queued try locks */
}
gl->gl_req = target;
+ set_bit(GLF_BLOCKING, &gl->gl_flags);
+ if ((gl->gl_req == LM_ST_UNLOCKED) ||
+ (gl->gl_state == LM_ST_EXCLUSIVE) ||
+ (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
+ clear_bit(GLF_BLOCKING, &gl->gl_flags);
spin_unlock(&gl->gl_spin);
if (glops->go_xmote_th)
glops->go_xmote_th(gl);
@@ -744,6 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
return -ENOMEM;
atomic_inc(&sdp->sd_glock_disposal);
+ gl->gl_sbd = sdp;
gl->gl_flags = 0;
gl->gl_name = name;
atomic_set(&gl->gl_ref, 1);
@@ -752,12 +759,17 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_demote_state = LM_ST_EXCLUSIVE;
gl->gl_hash = hash;
gl->gl_ops = glops;
- snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number);
+ gl->gl_dstamp = ktime_set(0, 0);
+ preempt_disable();
+ /* We use the global stats to estimate the initial per-glock stats */
+ gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type];
+ preempt_enable();
+ gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0;
+ gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0;
memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
gl->gl_tchange = jiffies;
gl->gl_object = NULL;
- gl->gl_sbd = sdp;
gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
INIT_WORK(&gl->gl_delete, delete_work_func);
@@ -999,6 +1011,8 @@ fail:
}
set_bit(GLF_QUEUED, &gl->gl_flags);
trace_gfs2_glock_queue(gh, 1);
+ gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
+ gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
if (likely(insert_pt == NULL)) {
list_add_tail(&gh->gh_list, &gl->gl_holders);
if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
@@ -1658,6 +1672,8 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
*p++ = 'L';
if (gl->gl_object)
*p++ = 'o';
+ if (test_bit(GLF_BLOCKING, gflags))
+ *p++ = 'b';
*p = 0;
return buf;
}
@@ -1714,8 +1730,78 @@ out:
return error;
}
+static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+ struct gfs2_glock *gl = iter_ptr;
+
+ seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n",
+ gl->gl_name.ln_type,
+ (unsigned long long)gl->gl_name.ln_number,
+ (long long)gl->gl_stats.stats[GFS2_LKS_SRTT],
+ (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR],
+ (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB],
+ (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB],
+ (long long)gl->gl_stats.stats[GFS2_LKS_SIRT],
+ (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR],
+ (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT],
+ (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]);
+ return 0;
+}
+
+static const char *gfs2_gltype[] = {
+ "type",
+ "reserved",
+ "nondisk",
+ "inode",
+ "rgrp",
+ "meta",
+ "iopen",
+ "flock",
+ "plock",
+ "quota",
+ "journal",
+};
+
+static const char *gfs2_stype[] = {
+ [GFS2_LKS_SRTT] = "srtt",
+ [GFS2_LKS_SRTTVAR] = "srttvar",
+ [GFS2_LKS_SRTTB] = "srttb",
+ [GFS2_LKS_SRTTVARB] = "srttvarb",
+ [GFS2_LKS_SIRT] = "sirt",
+ [GFS2_LKS_SIRTVAR] = "sirtvar",
+ [GFS2_LKS_DCOUNT] = "dlm",
+ [GFS2_LKS_QCOUNT] = "queue",
+};
+
+#define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype))
+
+static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+ struct gfs2_glock_iter *gi = seq->private;
+ struct gfs2_sbd *sdp = gi->sdp;
+ unsigned index = gi->hash >> 3;
+ unsigned subindex = gi->hash & 0x07;
+ s64 value;
+ int i;
+
+ if (index == 0 && subindex != 0)
+ return 0;
+ seq_printf(seq, "%-10s %8s:", gfs2_gltype[index],
+ (index == 0) ? "cpu": gfs2_stype[subindex]);
+ for_each_possible_cpu(i) {
+ const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i);
+ if (index == 0) {
+ value = i;
+ } else {
+ value = lkstats->lkstats[index - 1].stats[subindex];
+ }
+ seq_printf(seq, " %15lld", (long long)value);
+ }
+ seq_putc(seq, '\n');
+ return 0;
+}
int __init gfs2_glock_init(void)
{
@@ -1828,6 +1914,35 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
return dump_glock(seq, iter_ptr);
}
+static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct gfs2_glock_iter *gi = seq->private;
+
+ gi->hash = *pos;
+ if (*pos >= GFS2_NR_SBSTATS)
+ return NULL;
+ preempt_disable();
+ return SEQ_START_TOKEN;
+}
+
+static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr,
+ loff_t *pos)
+{
+ struct gfs2_glock_iter *gi = seq->private;
+ (*pos)++;
+ gi->hash++;
+ if (gi->hash >= GFS2_NR_SBSTATS) {
+ preempt_enable();
+ return NULL;
+ }
+ return SEQ_START_TOKEN;
+}
+
+static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr)
+{
+ preempt_enable();
+}
+
static const struct seq_operations gfs2_glock_seq_ops = {
.start = gfs2_glock_seq_start,
.next = gfs2_glock_seq_next,
@@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = {
.show = gfs2_glock_seq_show,
};
-static int gfs2_debugfs_open(struct inode *inode, struct file *file)
+static const struct seq_operations gfs2_glstats_seq_ops = {
+ .start = gfs2_glock_seq_start,
+ .next = gfs2_glock_seq_next,
+ .stop = gfs2_glock_seq_stop,
+ .show = gfs2_glstats_seq_show,
+};
+
+static const struct seq_operations gfs2_sbstats_seq_ops = {
+ .start = gfs2_sbstats_seq_start,
+ .next = gfs2_sbstats_seq_next,
+ .stop = gfs2_sbstats_seq_stop,
+ .show = gfs2_sbstats_seq_show,
+};
+
+static int gfs2_glocks_open(struct inode *inode, struct file *file)
{
int ret = seq_open_private(file, &gfs2_glock_seq_ops,
sizeof(struct gfs2_glock_iter));
@@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file)
return ret;
}
-static const struct file_operations gfs2_debug_fops = {
+static int gfs2_glstats_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open_private(file, &gfs2_glstats_seq_ops,
+ sizeof(struct gfs2_glock_iter));
+ if (ret == 0) {
+ struct seq_file *seq = file->private_data;
+ struct gfs2_glock_iter *gi = seq->private;
+ gi->sdp = inode->i_private;
+ }
+ return ret;
+}
+
+static int gfs2_sbstats_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open_private(file, &gfs2_sbstats_seq_ops,
+ sizeof(struct gfs2_glock_iter));
+ if (ret == 0) {
+ struct seq_file *seq = file->private_data;
+ struct gfs2_glock_iter *gi = seq->private;
+ gi->sdp = inode->i_private;
+ }
+ return ret;
+}
+
+static const struct file_operations gfs2_glocks_fops = {
+ .owner = THIS_MODULE,
+ .open = gfs2_glocks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static const struct file_operations gfs2_glstats_fops = {
.owner = THIS_MODULE,
- .open = gfs2_debugfs_open,
+ .open = gfs2_glstats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static const struct file_operations gfs2_sbstats_fops = {
+ .owner = THIS_MODULE,
+ .open = gfs2_sbstats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
@@ -1863,20 +2032,45 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
- &gfs2_debug_fops);
+ &gfs2_glocks_fops);
if (!sdp->debugfs_dentry_glocks)
- return -ENOMEM;
+ goto fail;
+
+ sdp->debugfs_dentry_glstats = debugfs_create_file("glstats",
+ S_IFREG | S_IRUGO,
+ sdp->debugfs_dir, sdp,
+ &gfs2_glstats_fops);
+ if (!sdp->debugfs_dentry_glstats)
+ goto fail;
+
+ sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats",
+ S_IFREG | S_IRUGO,
+ sdp->debugfs_dir, sdp,
+ &gfs2_sbstats_fops);
+ if (!sdp->debugfs_dentry_sbstats)
+ goto fail;
return 0;
+fail:
+ gfs2_delete_debugfs_file(sdp);
+ return -ENOMEM;
}
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
{
- if (sdp && sdp->debugfs_dir) {
+ if (sdp->debugfs_dir) {
if (sdp->debugfs_dentry_glocks) {
debugfs_remove(sdp->debugfs_dentry_glocks);
sdp->debugfs_dentry_glocks = NULL;
}
+ if (sdp->debugfs_dentry_glstats) {
+ debugfs_remove(sdp->debugfs_dentry_glstats);
+ sdp->debugfs_dentry_glstats = NULL;
+ }
+ if (sdp->debugfs_dentry_sbstats) {
+ debugfs_remove(sdp->debugfs_dentry_sbstats);
+ sdp->debugfs_dentry_sbstats = NULL;
+ }
debugfs_remove(sdp->debugfs_dir);
sdp->debugfs_dir = NULL;
}