Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

GFS2: glock statistics gathering

The stats are divided into two sets: those relating to the
super block and those relating to an individual glock. The
super block stats are done on a per cpu basis in order to
try and reduce the overhead of gathering them. They are also
further divided by glock type.

In the case of both the super block and glock statistics,
the same information is gathered in each case. The super
block statistics are used to provide default values for
most of the glock statistics, so that newly created glocks
should have, as far as possible, a sensible starting point.

The statistics are divided into three pairs of mean and
variance, plus two counters. The mean/variance pairs are
smoothed exponential estimates and the algorithm used is
one which will be very familiar to those used to calculation
of round trip times in network code.

The three pairs of mean/variance measure the following
things:

1. DLM lock time (non-blocking requests)
2. DLM lock time (blocking requests)
3. Inter-request time (again to the DLM)

A non-blocking request is one which will complete right
away, whatever the state of the DLM lock in question. That
currently means any requests when (a) the current state of
the lock is exclusive (b) the requested state is either null
or unlocked or (c) the "try lock" flag is set. A blocking
request covers all the other lock requests.

There are two counters. The first is there primarily to show
how many lock requests have been made, and thus how much data
has gone into the mean/variance calculations. The other counter
is counting queueing of holders at the top layer of the glock
code. Hopefully that number will be a lot larger than the number
of dlm lock requests issued.

So why gather these statistics? There are several reasons
we'd like to get a better idea of these timings:

1. To be able to better set the glock "min hold time"
2. To spot performance issues more easily
3. To improve the algorithm for selecting resource groups for
allocation (to base it on lock wait time, rather than blindly
using a "try lock")
Due to the smoothing action of the updates, a step change in
some input quantity being sampled will only fully be taken
into account after 8 samples (or 4 for the variance) and this
needs to be carefully considered when interpreting the
results.

Knowing both the time it takes a lock request to complete and
the average time between lock requests for a glock means we
can compute the total percentage of the time for which the
node is able to use a glock vs. time that the rest of the
cluster has its share. That will be very useful when setting
the lock min hold time.

The other point to remember is that all times are in
nanoseconds. Great care has been taken to ensure that we
measure exactly the quantities that we want, as accurately
as possible. There are always inaccuracies in any
measuring system, but I hope this is as accurate as we
can reasonably make it.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

+431 -19
+202 -8
fs/gfs2/glock.c
··· 29 29 #include <linux/rcupdate.h> 30 30 #include <linux/rculist_bl.h> 31 31 #include <linux/bit_spinlock.h> 32 + #include <linux/percpu.h> 32 33 33 34 #include "gfs2.h" 34 35 #include "incore.h" ··· 544 543 do_error(gl, 0); /* Fail queued try locks */ 545 544 } 546 545 gl->gl_req = target; 546 + set_bit(GLF_BLOCKING, &gl->gl_flags); 547 + if ((gl->gl_req == LM_ST_UNLOCKED) || 548 + (gl->gl_state == LM_ST_EXCLUSIVE) || 549 + (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB))) 550 + clear_bit(GLF_BLOCKING, &gl->gl_flags); 547 551 spin_unlock(&gl->gl_spin); 548 552 if (glops->go_xmote_th) 549 553 glops->go_xmote_th(gl); ··· 750 744 return -ENOMEM; 751 745 752 746 atomic_inc(&sdp->sd_glock_disposal); 747 + gl->gl_sbd = sdp; 753 748 gl->gl_flags = 0; 754 749 gl->gl_name = name; 755 750 atomic_set(&gl->gl_ref, 1); ··· 759 752 gl->gl_demote_state = LM_ST_EXCLUSIVE; 760 753 gl->gl_hash = hash; 761 754 gl->gl_ops = glops; 762 - snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number); 755 + gl->gl_dstamp = ktime_set(0, 0); 756 + preempt_disable(); 757 + /* We use the global stats to estimate the initial per-glock stats */ 758 + gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type]; 759 + preempt_enable(); 760 + gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0; 761 + gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0; 763 762 memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb)); 764 763 gl->gl_lksb.sb_lvbptr = gl->gl_lvb; 765 764 gl->gl_tchange = jiffies; 766 765 gl->gl_object = NULL; 767 - gl->gl_sbd = sdp; 768 766 gl->gl_hold_time = GL_GLOCK_DFT_HOLD; 769 767 INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); 770 768 INIT_WORK(&gl->gl_delete, delete_work_func); ··· 1011 999 } 1012 1000 set_bit(GLF_QUEUED, &gl->gl_flags); 1013 1001 trace_gfs2_glock_queue(gh, 1); 1002 + gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT); 1003 + gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT); 1014 1004 if (likely(insert_pt == NULL)) { 1015 1005 list_add_tail(&gh->gh_list, &gl->gl_holders); 1016 1006 if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) ··· 1672 1658 *p++ = 'L'; 1673 1659 if (gl->gl_object) 1674 1660 *p++ = 'o'; 1661 + if (test_bit(GLF_BLOCKING, gflags)) 1662 + *p++ = 'b'; 1675 1663 *p = 0; 1676 1664 return buf; 1677 1665 } ··· 1730 1714 return error; 1731 1715 } 1732 1716 1717 + static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr) 1718 + { 1719 + struct gfs2_glock *gl = iter_ptr; 1733 1720 1721 + seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n", 1722 + gl->gl_name.ln_type, 1723 + (unsigned long long)gl->gl_name.ln_number, 1724 + (long long)gl->gl_stats.stats[GFS2_LKS_SRTT], 1725 + (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR], 1726 + (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB], 1727 + (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB], 1728 + (long long)gl->gl_stats.stats[GFS2_LKS_SIRT], 1729 + (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR], 1730 + (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT], 1731 + (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]); 1732 + return 0; 1733 + } 1734 1734 1735 + static const char *gfs2_gltype[] = { 1736 + "type", 1737 + "reserved", 1738 + "nondisk", 1739 + "inode", 1740 + "rgrp", 1741 + "meta", 1742 + "iopen", 1743 + "flock", 1744 + "plock", 1745 + "quota", 1746 + "journal", 1747 + }; 1748 + 1749 + static const char *gfs2_stype[] = { 1750 + [GFS2_LKS_SRTT] = "srtt", 1751 + [GFS2_LKS_SRTTVAR] = "srttvar", 1752 + [GFS2_LKS_SRTTB] = "srttb", 1753 + [GFS2_LKS_SRTTVARB] = "srttvarb", 1754 + [GFS2_LKS_SIRT] = "sirt", 1755 + [GFS2_LKS_SIRTVAR] = "sirtvar", 1756 + [GFS2_LKS_DCOUNT] = "dlm", 1757 + [GFS2_LKS_QCOUNT] = "queue", 1758 + }; 1759 + 1760 + #define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype)) 1761 + 1762 + static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) 1763 + { 1764 + struct gfs2_glock_iter *gi = seq->private; 1765 + struct gfs2_sbd *sdp = gi->sdp; 1766 + unsigned index = gi->hash >> 3; 1767 + unsigned subindex = gi->hash & 0x07; 1768 + s64 value; 1769 + int i; 1770 + 1771 + if (index == 0 && subindex != 0) 1772 + return 0; 1773 + 1774 + seq_printf(seq, "%-10s %8s:", gfs2_gltype[index], 1775 + (index == 0) ? "cpu": gfs2_stype[subindex]); 1776 + 1777 + for_each_possible_cpu(i) { 1778 + const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i); 1779 + if (index == 0) { 1780 + value = i; 1781 + } else { 1782 + value = lkstats->lkstats[index - 1].stats[subindex]; 1783 + } 1784 + seq_printf(seq, " %15lld", (long long)value); 1785 + } 1786 + seq_putc(seq, '\n'); 1787 + return 0; 1788 + } 1735 1789 1736 1790 int __init gfs2_glock_init(void) 1737 1791 { ··· 1914 1828 return dump_glock(seq, iter_ptr); 1915 1829 } 1916 1830 1831 + static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos) 1832 + { 1833 + struct gfs2_glock_iter *gi = seq->private; 1834 + 1835 + gi->hash = *pos; 1836 + if (*pos >= GFS2_NR_SBSTATS) 1837 + return NULL; 1838 + preempt_disable(); 1839 + return SEQ_START_TOKEN; 1840 + } 1841 + 1842 + static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr, 1843 + loff_t *pos) 1844 + { 1845 + struct gfs2_glock_iter *gi = seq->private; 1846 + (*pos)++; 1847 + gi->hash++; 1848 + if (gi->hash >= GFS2_NR_SBSTATS) { 1849 + preempt_enable(); 1850 + return NULL; 1851 + } 1852 + return SEQ_START_TOKEN; 1853 + } 1854 + 1855 + static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr) 1856 + { 1857 + preempt_enable(); 1858 + } 1859 + 1917 1860 static const struct seq_operations gfs2_glock_seq_ops = { 1918 1861 .start = gfs2_glock_seq_start, 1919 1862 .next = gfs2_glock_seq_next, ··· 1950 1835 .show = gfs2_glock_seq_show, 1951 1836 }; 1952 1837 1953 - static int gfs2_debugfs_open(struct inode *inode, struct file *file) 1838 + static const struct seq_operations gfs2_glstats_seq_ops = { 1839 + .start = gfs2_glock_seq_start, 1840 + .next = gfs2_glock_seq_next, 1841 + .stop = gfs2_glock_seq_stop, 1842 + .show = gfs2_glstats_seq_show, 1843 + }; 1844 + 1845 + static const struct seq_operations gfs2_sbstats_seq_ops = { 1846 + .start = gfs2_sbstats_seq_start, 1847 + .next = gfs2_sbstats_seq_next, 1848 + .stop = gfs2_sbstats_seq_stop, 1849 + .show = gfs2_sbstats_seq_show, 1850 + }; 1851 + 1852 + static int gfs2_glocks_open(struct inode *inode, struct file *file) 1954 1853 { 1955 1854 int ret = seq_open_private(file, &gfs2_glock_seq_ops, 1956 1855 sizeof(struct gfs2_glock_iter)); ··· 1976 1847 return ret; 1977 1848 } 1978 1849 1979 - static const struct file_operations gfs2_debug_fops = { 1850 + static int gfs2_glstats_open(struct inode *inode, struct file *file) 1851 + { 1852 + int ret = seq_open_private(file, &gfs2_glstats_seq_ops, 1853 + sizeof(struct gfs2_glock_iter)); 1854 + if (ret == 0) { 1855 + struct seq_file *seq = file->private_data; 1856 + struct gfs2_glock_iter *gi = seq->private; 1857 + gi->sdp = inode->i_private; 1858 + } 1859 + return ret; 1860 + } 1861 + 1862 + static int gfs2_sbstats_open(struct inode *inode, struct file *file) 1863 + { 1864 + int ret = seq_open_private(file, &gfs2_sbstats_seq_ops, 1865 + sizeof(struct gfs2_glock_iter)); 1866 + if (ret == 0) { 1867 + struct seq_file *seq = file->private_data; 1868 + struct gfs2_glock_iter *gi = seq->private; 1869 + gi->sdp = inode->i_private; 1870 + } 1871 + return ret; 1872 + } 1873 + 1874 + static const struct file_operations gfs2_glocks_fops = { 1980 1875 .owner = THIS_MODULE, 1981 - .open = gfs2_debugfs_open, 1876 + .open = gfs2_glocks_open, 1877 + .read = seq_read, 1878 + .llseek = seq_lseek, 1879 + .release = seq_release_private, 1880 + }; 1881 + 1882 + static const struct file_operations gfs2_glstats_fops = { 1883 + .owner = THIS_MODULE, 1884 + .open = gfs2_glstats_open, 1885 + .read = seq_read, 1886 + .llseek = seq_lseek, 1887 + .release = seq_release_private, 1888 + }; 1889 + 1890 + static const struct file_operations gfs2_sbstats_fops = { 1891 + .owner = THIS_MODULE, 1892 + .open = gfs2_sbstats_open, 1982 1893 .read = seq_read, 1983 1894 .llseek = seq_lseek, 1984 1895 .release = seq_release_private, ··· 2032 1863 sdp->debugfs_dentry_glocks = debugfs_create_file("glocks", 2033 1864 S_IFREG | S_IRUGO, 2034 1865 sdp->debugfs_dir, sdp, 2035 - &gfs2_debug_fops); 1866 + &gfs2_glocks_fops); 2036 1867 if (!sdp->debugfs_dentry_glocks) 2037 - return -ENOMEM; 1868 + goto fail; 1869 + 1870 + sdp->debugfs_dentry_glstats = debugfs_create_file("glstats", 1871 + S_IFREG | S_IRUGO, 1872 + sdp->debugfs_dir, sdp, 1873 + &gfs2_glstats_fops); 1874 + if (!sdp->debugfs_dentry_glstats) 1875 + goto fail; 1876 + 1877 + sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats", 1878 + S_IFREG | S_IRUGO, 1879 + sdp->debugfs_dir, sdp, 1880 + &gfs2_sbstats_fops); 1881 + if (!sdp->debugfs_dentry_sbstats) 1882 + goto fail; 2038 1883 2039 1884 return 0; 1885 + fail: 1886 + gfs2_delete_debugfs_file(sdp); 1887 + return -ENOMEM; 2040 1888 } 2041 1889 2042 1890 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp) 2043 1891 { 2044 - if (sdp && sdp->debugfs_dir) { 1892 + if (sdp->debugfs_dir) { 2045 1893 if (sdp->debugfs_dentry_glocks) { 2046 1894 debugfs_remove(sdp->debugfs_dentry_glocks); 2047 1895 sdp->debugfs_dentry_glocks = NULL; 1896 + } 1897 + if (sdp->debugfs_dentry_glstats) { 1898 + debugfs_remove(sdp->debugfs_dentry_glstats); 1899 + sdp->debugfs_dentry_glstats = NULL; 1900 + } 1901 + if (sdp->debugfs_dentry_sbstats) { 1902 + debugfs_remove(sdp->debugfs_dentry_sbstats); 1903 + sdp->debugfs_dentry_sbstats = NULL; 2048 1904 } 2049 1905 debugfs_remove(sdp->debugfs_dir); 2050 1906 sdp->debugfs_dir = NULL;
+44 -5
fs/gfs2/incore.h
··· 19 19 #include <linux/rculist_bl.h> 20 20 #include <linux/completion.h> 21 21 #include <linux/rbtree.h> 22 + #include <linux/ktime.h> 23 + #include <linux/percpu.h> 22 24 23 25 #define DIO_WAIT 0x00000010 24 26 #define DIO_METADATA 0x00000020 ··· 207 205 }; 208 206 209 207 enum { 208 + GFS2_LKS_SRTT = 0, /* Non blocking smoothed round trip time */ 209 + GFS2_LKS_SRTTVAR = 1, /* Non blocking smoothed variance */ 210 + GFS2_LKS_SRTTB = 2, /* Blocking smoothed round trip time */ 211 + GFS2_LKS_SRTTVARB = 3, /* Blocking smoothed variance */ 212 + GFS2_LKS_SIRT = 4, /* Smoothed Inter-request time */ 213 + GFS2_LKS_SIRTVAR = 5, /* Smoothed Inter-request variance */ 214 + GFS2_LKS_DCOUNT = 6, /* Count of dlm requests */ 215 + GFS2_LKS_QCOUNT = 7, /* Count of gfs2_holder queues */ 216 + GFS2_NR_LKSTATS 217 + }; 218 + 219 + struct gfs2_lkstats { 220 + s64 stats[GFS2_NR_LKSTATS]; 221 + }; 222 + 223 + enum { 210 224 /* States */ 211 225 HIF_HOLDER = 6, /* Set for gh that "holds" the glock */ 212 226 HIF_FIRST = 7, ··· 256 238 GLF_QUEUED = 12, 257 239 GLF_LRU = 13, 258 240 GLF_OBJECT = 14, /* Used only for tracing */ 241 + GLF_BLOCKING = 15, 259 242 }; 260 243 261 244 struct gfs2_glock { 262 245 struct hlist_bl_node gl_list; 246 + struct gfs2_sbd *gl_sbd; 263 247 unsigned long gl_flags; /* GLF_... */ 264 248 struct lm_lockname gl_name; 265 249 atomic_t gl_ref; ··· 281 261 struct list_head gl_holders; 282 262 283 263 const struct gfs2_glock_operations *gl_ops; 284 - char gl_strname[GDLM_STRNAME_BYTES]; 264 + ktime_t gl_dstamp; 265 + struct gfs2_lkstats gl_stats; 285 266 struct dlm_lksb gl_lksb; 286 267 char gl_lvb[32]; 287 268 unsigned long gl_tchange; 288 269 void *gl_object; 289 270 290 271 struct list_head gl_lru; 291 - 292 - struct gfs2_sbd *gl_sbd; 293 - 294 272 struct list_head gl_ail_list; 295 273 atomic_t gl_ail_count; 296 274 atomic_t gl_revokes; ··· 578 560 uint32_t *ls_recover_result; /* result of last jid recovery */ 579 561 }; 580 562 563 + struct gfs2_pcpu_lkstats { 564 + /* One struct for each glock type */ 565 + struct gfs2_lkstats lkstats[10]; 566 + }; 567 + 581 568 struct gfs2_sbd { 582 569 struct super_block *sd_vfs; 570 + struct gfs2_pcpu_lkstats __percpu *sd_lkstats; 583 571 struct kobject sd_kobj; 584 572 unsigned long sd_flags; /* SDF_... */ 585 573 struct gfs2_sb_host sd_sb; ··· 749 725 750 726 unsigned long sd_last_warning; 751 727 struct dentry *debugfs_dir; /* debugfs directory */ 752 - struct dentry *debugfs_dentry_glocks; /* for debugfs */ 728 + struct dentry *debugfs_dentry_glocks; 729 + struct dentry *debugfs_dentry_glstats; 730 + struct dentry *debugfs_dentry_sbstats; 753 731 }; 732 + 733 + static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which) 734 + { 735 + gl->gl_stats.stats[which]++; 736 + } 737 + 738 + static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) 739 + { 740 + const struct gfs2_sbd *sdp = gl->gl_sbd; 741 + preempt_disable(); 742 + this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++; 743 + preempt_enable(); 744 + } 754 745 755 746 #endif /* __INCORE_DOT_H__ */ 756 747
+118 -5
fs/gfs2/lock_dlm.c
··· 18 18 #include "glock.h" 19 19 #include "util.h" 20 20 #include "sys.h" 21 + #include "trace_gfs2.h" 21 22 22 23 extern struct workqueue_struct *gfs2_control_wq; 23 24 25 + /** 26 + * gfs2_update_stats - Update time based stats 27 + * @mv: Pointer to mean/variance structure to update 28 + * @sample: New data to include 29 + * 30 + * @delta is the difference between the current rtt sample and the 31 + * running average srtt. We add 1/8 of that to the srtt in order to 32 + * update the current srtt estimate. The varience estimate is a bit 33 + * more complicated. We subtract the abs value of the @delta from 34 + * the current variance estimate and add 1/4 of that to the running 35 + * total. 36 + * 37 + * Note that the index points at the array entry containing the smoothed 38 + * mean value, and the variance is always in the following entry 39 + * 40 + * Reference: TCP/IP Illustrated, vol 2, p. 831,832 41 + * All times are in units of integer nanoseconds. Unlike the TCP/IP case, 42 + * they are not scaled fixed point. 43 + */ 44 + 45 + static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index, 46 + s64 sample) 47 + { 48 + s64 delta = sample - s->stats[index]; 49 + s->stats[index] += (delta >> 3); 50 + index++; 51 + s->stats[index] += ((abs64(delta) - s->stats[index]) >> 2); 52 + } 53 + 54 + /** 55 + * gfs2_update_reply_times - Update locking statistics 56 + * @gl: The glock to update 57 + * 58 + * This assumes that gl->gl_dstamp has been set earlier. 59 + * 60 + * The rtt (lock round trip time) is an estimate of the time 61 + * taken to perform a dlm lock request. We update it on each 62 + * reply from the dlm. 63 + * 64 + * The blocking flag is set on the glock for all dlm requests 65 + * which may potentially block due to lock requests from other nodes. 66 + * DLM requests where the current lock state is exclusive, the 67 + * requested state is null (or unlocked) or where the TRY or 68 + * TRY_1CB flags are set are classified as non-blocking. All 69 + * other DLM requests are counted as (potentially) blocking. 70 + */ 71 + static inline void gfs2_update_reply_times(struct gfs2_glock *gl) 72 + { 73 + struct gfs2_pcpu_lkstats *lks; 74 + const unsigned gltype = gl->gl_name.ln_type; 75 + unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ? 76 + GFS2_LKS_SRTTB : GFS2_LKS_SRTT; 77 + s64 rtt; 78 + 79 + preempt_disable(); 80 + rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp)); 81 + lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); 82 + gfs2_update_stats(&gl->gl_stats, index, rtt); /* Local */ 83 + gfs2_update_stats(&lks->lkstats[gltype], index, rtt); /* Global */ 84 + preempt_enable(); 85 + 86 + trace_gfs2_glock_lock_time(gl, rtt); 87 + } 88 + 89 + /** 90 + * gfs2_update_request_times - Update locking statistics 91 + * @gl: The glock to update 92 + * 93 + * The irt (lock inter-request times) measures the average time 94 + * between requests to the dlm. It is updated immediately before 95 + * each dlm call. 96 + */ 97 + 98 + static inline void gfs2_update_request_times(struct gfs2_glock *gl) 99 + { 100 + struct gfs2_pcpu_lkstats *lks; 101 + const unsigned gltype = gl->gl_name.ln_type; 102 + ktime_t dstamp; 103 + s64 irt; 104 + 105 + preempt_disable(); 106 + dstamp = gl->gl_dstamp; 107 + gl->gl_dstamp = ktime_get_real(); 108 + irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp)); 109 + lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); 110 + gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt); /* Local */ 111 + gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt); /* Global */ 112 + preempt_enable(); 113 + } 114 + 24 115 static void gdlm_ast(void *arg) 25 116 { 26 117 struct gfs2_glock *gl = arg; 27 118 unsigned ret = gl->gl_state; 28 119 120 + gfs2_update_reply_times(gl); 29 121 BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); 30 122 31 123 if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) ··· 203 111 static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, 204 112 const int req) 205 113 { 206 - u32 lkf = 0; 114 + u32 lkf = DLM_LKF_VALBLK; 207 115 208 116 if (gfs_flags & LM_FLAG_TRY) 209 117 lkf |= DLM_LKF_NOQUEUE; ··· 230 138 if (lkid != 0) 231 139 lkf |= DLM_LKF_CONVERT; 232 140 233 - lkf |= DLM_LKF_VALBLK; 234 - 235 141 return lkf; 142 + } 143 + 144 + static void gfs2_reverse_hex(char *c, u64 value) 145 + { 146 + while (value) { 147 + *c-- = hex_asc[value & 0x0f]; 148 + value >>= 4; 149 + } 236 150 } 237 151 238 152 static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, ··· 247 149 struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; 248 150 int req; 249 151 u32 lkf; 152 + char strname[GDLM_STRNAME_BYTES] = ""; 250 153 251 154 req = make_mode(req_state); 252 155 lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); 253 - 156 + gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); 157 + gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); 158 + if (gl->gl_lksb.sb_lkid) { 159 + gfs2_update_request_times(gl); 160 + } else { 161 + memset(strname, ' ', GDLM_STRNAME_BYTES - 1); 162 + strname[GDLM_STRNAME_BYTES - 1] = '\0'; 163 + gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type); 164 + gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number); 165 + gl->gl_dstamp = ktime_get_real(); 166 + } 254 167 /* 255 168 * Submit the actual lock request. 256 169 */ 257 170 258 - return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, 171 + return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname, 259 172 GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); 260 173 } 261 174 ··· 281 172 return; 282 173 } 283 174 175 + clear_bit(GLF_BLOCKING, &gl->gl_flags); 176 + gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); 177 + gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); 178 + gfs2_update_request_times(gl); 284 179 error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, 285 180 NULL, gl); 286 181 if (error) {
+8
fs/gfs2/ops_fstype.c
··· 68 68 69 69 sb->s_fs_info = sdp; 70 70 sdp->sd_vfs = sb; 71 + sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats); 72 + if (!sdp->sd_lkstats) { 73 + kfree(sdp); 74 + return NULL; 75 + } 76 + 71 77 set_bit(SDF_NOJOURNALID, &sdp->sd_flags); 72 78 gfs2_tune_init(&sdp->sd_tune); 73 79 ··· 1227 1221 gfs2_sys_fs_del(sdp); 1228 1222 fail: 1229 1223 gfs2_delete_debugfs_file(sdp); 1224 + free_percpu(sdp->sd_lkstats); 1230 1225 kfree(sdp); 1231 1226 sb->s_fs_info = NULL; 1232 1227 return error; ··· 1400 1393 shrink_dcache_sb(sb); 1401 1394 kill_block_super(sb); 1402 1395 gfs2_delete_debugfs_file(sdp); 1396 + free_percpu(sdp->sd_lkstats); 1403 1397 kfree(sdp); 1404 1398 } 1405 1399
+59 -1
fs/gfs2/trace_gfs2.h
··· 11 11 #include <linux/dlmconstants.h> 12 12 #include <linux/gfs2_ondisk.h> 13 13 #include <linux/writeback.h> 14 + #include <linux/ktime.h> 14 15 #include "incore.h" 15 16 #include "glock.h" 16 17 ··· 44 43 {(1UL << GLF_FROZEN), "F" }, \ 45 44 {(1UL << GLF_QUEUED), "q" }, \ 46 45 {(1UL << GLF_LRU), "L" }, \ 47 - {(1UL << GLF_OBJECT), "o" }) 46 + {(1UL << GLF_OBJECT), "o" }, \ 47 + {(1UL << GLF_BLOCKING), "b" }) 48 48 49 49 #ifndef NUMPTY 50 50 #define NUMPTY ··· 236 234 (unsigned long long)__entry->glnum, 237 235 __entry->queue ? "" : "de", 238 236 glock_trace_name(__entry->state)) 237 + ); 238 + 239 + /* DLM sends a reply to GFS2 */ 240 + TRACE_EVENT(gfs2_glock_lock_time, 241 + 242 + TP_PROTO(const struct gfs2_glock *gl, s64 tdiff), 243 + 244 + TP_ARGS(gl, tdiff), 245 + 246 + TP_STRUCT__entry( 247 + __field( dev_t, dev ) 248 + __field( u64, glnum ) 249 + __field( u32, gltype ) 250 + __field( int, status ) 251 + __field( char, flags ) 252 + __field( s64, tdiff ) 253 + __field( s64, srtt ) 254 + __field( s64, srttvar ) 255 + __field( s64, srttb ) 256 + __field( s64, srttvarb ) 257 + __field( s64, sirt ) 258 + __field( s64, sirtvar ) 259 + __field( s64, dcount ) 260 + __field( s64, qcount ) 261 + ), 262 + 263 + TP_fast_assign( 264 + __entry->dev = gl->gl_sbd->sd_vfs->s_dev; 265 + __entry->glnum = gl->gl_name.ln_number; 266 + __entry->gltype = gl->gl_name.ln_type; 267 + __entry->status = gl->gl_lksb.sb_status; 268 + __entry->flags = gl->gl_lksb.sb_flags; 269 + __entry->tdiff = tdiff; 270 + __entry->srtt = gl->gl_stats.stats[GFS2_LKS_SRTT]; 271 + __entry->srttvar = gl->gl_stats.stats[GFS2_LKS_SRTTVAR]; 272 + __entry->srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB]; 273 + __entry->srttvarb = gl->gl_stats.stats[GFS2_LKS_SRTTVARB]; 274 + __entry->sirt = gl->gl_stats.stats[GFS2_LKS_SIRT]; 275 + __entry->sirtvar = gl->gl_stats.stats[GFS2_LKS_SIRTVAR]; 276 + __entry->dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT]; 277 + __entry->qcount = gl->gl_stats.stats[GFS2_LKS_QCOUNT]; 278 + ), 279 + 280 + TP_printk("%u,%u glock %d:%lld status:%d flags:%02x tdiff:%lld srtt:%lld/%lld srttb:%lld/%lld sirt:%lld/%lld dcnt:%lld qcnt:%lld", 281 + MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype, 282 + (unsigned long long)__entry->glnum, 283 + __entry->status, __entry->flags, 284 + (long long)__entry->tdiff, 285 + (long long)__entry->srtt, 286 + (long long)__entry->srttvar, 287 + (long long)__entry->srttb, 288 + (long long)__entry->srttvarb, 289 + (long long)__entry->sirt, 290 + (long long)__entry->sirtvar, 291 + (long long)__entry->dcount, 292 + (long long)__entry->qcount) 239 293 ); 240 294 241 295 /* Section 2 - Log/journal