diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/glock.c | 210 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 49 | ||||
-rw-r--r-- | fs/gfs2/lock_dlm.c | 123 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 8 | ||||
-rw-r--r-- | fs/gfs2/trace_gfs2.h | 60 |
5 files changed, 431 insertions, 19 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 351a3e797789..dab2526071cc 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/rcupdate.h> | 29 | #include <linux/rcupdate.h> |
30 | #include <linux/rculist_bl.h> | 30 | #include <linux/rculist_bl.h> |
31 | #include <linux/bit_spinlock.h> | 31 | #include <linux/bit_spinlock.h> |
32 | #include <linux/percpu.h> | ||
32 | 33 | ||
33 | #include "gfs2.h" | 34 | #include "gfs2.h" |
34 | #include "incore.h" | 35 | #include "incore.h" |
@@ -543,6 +544,11 @@ __acquires(&gl->gl_spin) | |||
543 | do_error(gl, 0); /* Fail queued try locks */ | 544 | do_error(gl, 0); /* Fail queued try locks */ |
544 | } | 545 | } |
545 | gl->gl_req = target; | 546 | gl->gl_req = target; |
547 | set_bit(GLF_BLOCKING, &gl->gl_flags); | ||
548 | if ((gl->gl_req == LM_ST_UNLOCKED) || | ||
549 | (gl->gl_state == LM_ST_EXCLUSIVE) || | ||
550 | (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB))) | ||
551 | clear_bit(GLF_BLOCKING, &gl->gl_flags); | ||
546 | spin_unlock(&gl->gl_spin); | 552 | spin_unlock(&gl->gl_spin); |
547 | if (glops->go_xmote_th) | 553 | if (glops->go_xmote_th) |
548 | glops->go_xmote_th(gl); | 554 | glops->go_xmote_th(gl); |
@@ -744,6 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
744 | return -ENOMEM; | 750 | return -ENOMEM; |
745 | 751 | ||
746 | atomic_inc(&sdp->sd_glock_disposal); | 752 | atomic_inc(&sdp->sd_glock_disposal); |
753 | gl->gl_sbd = sdp; | ||
747 | gl->gl_flags = 0; | 754 | gl->gl_flags = 0; |
748 | gl->gl_name = name; | 755 | gl->gl_name = name; |
749 | atomic_set(&gl->gl_ref, 1); | 756 | atomic_set(&gl->gl_ref, 1); |
@@ -752,12 +759,17 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
752 | gl->gl_demote_state = LM_ST_EXCLUSIVE; | 759 | gl->gl_demote_state = LM_ST_EXCLUSIVE; |
753 | gl->gl_hash = hash; | 760 | gl->gl_hash = hash; |
754 | gl->gl_ops = glops; | 761 | gl->gl_ops = glops; |
755 | snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number); | 762 | gl->gl_dstamp = ktime_set(0, 0); |
763 | preempt_disable(); | ||
764 | /* We use the global stats to estimate the initial per-glock stats */ | ||
765 | gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type]; | ||
766 | preempt_enable(); | ||
767 | gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0; | ||
768 | gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0; | ||
756 | memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb)); | 769 | memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb)); |
757 | gl->gl_lksb.sb_lvbptr = gl->gl_lvb; | 770 | gl->gl_lksb.sb_lvbptr = gl->gl_lvb; |
758 | gl->gl_tchange = jiffies; | 771 | gl->gl_tchange = jiffies; |
759 | gl->gl_object = NULL; | 772 | gl->gl_object = NULL; |
760 | gl->gl_sbd = sdp; | ||
761 | gl->gl_hold_time = GL_GLOCK_DFT_HOLD; | 773 | gl->gl_hold_time = GL_GLOCK_DFT_HOLD; |
762 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); | 774 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); |
763 | INIT_WORK(&gl->gl_delete, delete_work_func); | 775 | INIT_WORK(&gl->gl_delete, delete_work_func); |
@@ -999,6 +1011,8 @@ fail: | |||
999 | } | 1011 | } |
1000 | set_bit(GLF_QUEUED, &gl->gl_flags); | 1012 | set_bit(GLF_QUEUED, &gl->gl_flags); |
1001 | trace_gfs2_glock_queue(gh, 1); | 1013 | trace_gfs2_glock_queue(gh, 1); |
1014 | gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT); | ||
1015 | gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT); | ||
1002 | if (likely(insert_pt == NULL)) { | 1016 | if (likely(insert_pt == NULL)) { |
1003 | list_add_tail(&gh->gh_list, &gl->gl_holders); | 1017 | list_add_tail(&gh->gh_list, &gl->gl_holders); |
1004 | if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) | 1018 | if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) |
@@ -1658,6 +1672,8 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl) | |||
1658 | *p++ = 'L'; | 1672 | *p++ = 'L'; |
1659 | if (gl->gl_object) | 1673 | if (gl->gl_object) |
1660 | *p++ = 'o'; | 1674 | *p++ = 'o'; |
1675 | if (test_bit(GLF_BLOCKING, gflags)) | ||
1676 | *p++ = 'b'; | ||
1661 | *p = 0; | 1677 | *p = 0; |
1662 | return buf; | 1678 | return buf; |
1663 | } | 1679 | } |
@@ -1714,8 +1730,78 @@ out: | |||
1714 | return error; | 1730 | return error; |
1715 | } | 1731 | } |
1716 | 1732 | ||
1733 | static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr) | ||
1734 | { | ||
1735 | struct gfs2_glock *gl = iter_ptr; | ||
1736 | |||
1737 | seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n", | ||
1738 | gl->gl_name.ln_type, | ||
1739 | (unsigned long long)gl->gl_name.ln_number, | ||
1740 | (long long)gl->gl_stats.stats[GFS2_LKS_SRTT], | ||
1741 | (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR], | ||
1742 | (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB], | ||
1743 | (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB], | ||
1744 | (long long)gl->gl_stats.stats[GFS2_LKS_SIRT], | ||
1745 | (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR], | ||
1746 | (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT], | ||
1747 | (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]); | ||
1748 | return 0; | ||
1749 | } | ||
1750 | |||
1751 | static const char *gfs2_gltype[] = { | ||
1752 | "type", | ||
1753 | "reserved", | ||
1754 | "nondisk", | ||
1755 | "inode", | ||
1756 | "rgrp", | ||
1757 | "meta", | ||
1758 | "iopen", | ||
1759 | "flock", | ||
1760 | "plock", | ||
1761 | "quota", | ||
1762 | "journal", | ||
1763 | }; | ||
1764 | |||
1765 | static const char *gfs2_stype[] = { | ||
1766 | [GFS2_LKS_SRTT] = "srtt", | ||
1767 | [GFS2_LKS_SRTTVAR] = "srttvar", | ||
1768 | [GFS2_LKS_SRTTB] = "srttb", | ||
1769 | [GFS2_LKS_SRTTVARB] = "srttvarb", | ||
1770 | [GFS2_LKS_SIRT] = "sirt", | ||
1771 | [GFS2_LKS_SIRTVAR] = "sirtvar", | ||
1772 | [GFS2_LKS_DCOUNT] = "dlm", | ||
1773 | [GFS2_LKS_QCOUNT] = "queue", | ||
1774 | }; | ||
1775 | |||
1776 | #define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype)) | ||
1777 | |||
1778 | static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) | ||
1779 | { | ||
1780 | struct gfs2_glock_iter *gi = seq->private; | ||
1781 | struct gfs2_sbd *sdp = gi->sdp; | ||
1782 | unsigned index = gi->hash >> 3; | ||
1783 | unsigned subindex = gi->hash & 0x07; | ||
1784 | s64 value; | ||
1785 | int i; | ||
1786 | |||
1787 | if (index == 0 && subindex != 0) | ||
1788 | return 0; | ||
1717 | 1789 | ||
1790 | seq_printf(seq, "%-10s %8s:", gfs2_gltype[index], | ||
1791 | (index == 0) ? "cpu": gfs2_stype[subindex]); | ||
1718 | 1792 | ||
1793 | for_each_possible_cpu(i) { | ||
1794 | const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i); | ||
1795 | if (index == 0) { | ||
1796 | value = i; | ||
1797 | } else { | ||
1798 | value = lkstats->lkstats[index - 1].stats[subindex]; | ||
1799 | } | ||
1800 | seq_printf(seq, " %15lld", (long long)value); | ||
1801 | } | ||
1802 | seq_putc(seq, '\n'); | ||
1803 | return 0; | ||
1804 | } | ||
1719 | 1805 | ||
1720 | int __init gfs2_glock_init(void) | 1806 | int __init gfs2_glock_init(void) |
1721 | { | 1807 | { |
@@ -1828,6 +1914,35 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) | |||
1828 | return dump_glock(seq, iter_ptr); | 1914 | return dump_glock(seq, iter_ptr); |
1829 | } | 1915 | } |
1830 | 1916 | ||
1917 | static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos) | ||
1918 | { | ||
1919 | struct gfs2_glock_iter *gi = seq->private; | ||
1920 | |||
1921 | gi->hash = *pos; | ||
1922 | if (*pos >= GFS2_NR_SBSTATS) | ||
1923 | return NULL; | ||
1924 | preempt_disable(); | ||
1925 | return SEQ_START_TOKEN; | ||
1926 | } | ||
1927 | |||
1928 | static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr, | ||
1929 | loff_t *pos) | ||
1930 | { | ||
1931 | struct gfs2_glock_iter *gi = seq->private; | ||
1932 | (*pos)++; | ||
1933 | gi->hash++; | ||
1934 | if (gi->hash >= GFS2_NR_SBSTATS) { | ||
1935 | preempt_enable(); | ||
1936 | return NULL; | ||
1937 | } | ||
1938 | return SEQ_START_TOKEN; | ||
1939 | } | ||
1940 | |||
1941 | static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr) | ||
1942 | { | ||
1943 | preempt_enable(); | ||
1944 | } | ||
1945 | |||
1831 | static const struct seq_operations gfs2_glock_seq_ops = { | 1946 | static const struct seq_operations gfs2_glock_seq_ops = { |
1832 | .start = gfs2_glock_seq_start, | 1947 | .start = gfs2_glock_seq_start, |
1833 | .next = gfs2_glock_seq_next, | 1948 | .next = gfs2_glock_seq_next, |
@@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = { | |||
1835 | .show = gfs2_glock_seq_show, | 1950 | .show = gfs2_glock_seq_show, |
1836 | }; | 1951 | }; |
1837 | 1952 | ||
1838 | static int gfs2_debugfs_open(struct inode *inode, struct file *file) | 1953 | static const struct seq_operations gfs2_glstats_seq_ops = { |
1954 | .start = gfs2_glock_seq_start, | ||
1955 | .next = gfs2_glock_seq_next, | ||
1956 | .stop = gfs2_glock_seq_stop, | ||
1957 | .show = gfs2_glstats_seq_show, | ||
1958 | }; | ||
1959 | |||
1960 | static const struct seq_operations gfs2_sbstats_seq_ops = { | ||
1961 | .start = gfs2_sbstats_seq_start, | ||
1962 | .next = gfs2_sbstats_seq_next, | ||
1963 | .stop = gfs2_sbstats_seq_stop, | ||
1964 | .show = gfs2_sbstats_seq_show, | ||
1965 | }; | ||
1966 | |||
1967 | static int gfs2_glocks_open(struct inode *inode, struct file *file) | ||
1839 | { | 1968 | { |
1840 | int ret = seq_open_private(file, &gfs2_glock_seq_ops, | 1969 | int ret = seq_open_private(file, &gfs2_glock_seq_ops, |
1841 | sizeof(struct gfs2_glock_iter)); | 1970 | sizeof(struct gfs2_glock_iter)); |
@@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file) | |||
1847 | return ret; | 1976 | return ret; |
1848 | } | 1977 | } |
1849 | 1978 | ||
1850 | static const struct file_operations gfs2_debug_fops = { | 1979 | static int gfs2_glstats_open(struct inode *inode, struct file *file) |
1980 | { | ||
1981 | int ret = seq_open_private(file, &gfs2_glstats_seq_ops, | ||
1982 | sizeof(struct gfs2_glock_iter)); | ||
1983 | if (ret == 0) { | ||
1984 | struct seq_file *seq = file->private_data; | ||
1985 | struct gfs2_glock_iter *gi = seq->private; | ||
1986 | gi->sdp = inode->i_private; | ||
1987 | } | ||
1988 | return ret; | ||
1989 | } | ||
1990 | |||
1991 | static int gfs2_sbstats_open(struct inode *inode, struct file *file) | ||
1992 | { | ||
1993 | int ret = seq_open_private(file, &gfs2_sbstats_seq_ops, | ||
1994 | sizeof(struct gfs2_glock_iter)); | ||
1995 | if (ret == 0) { | ||
1996 | struct seq_file *seq = file->private_data; | ||
1997 | struct gfs2_glock_iter *gi = seq->private; | ||
1998 | gi->sdp = inode->i_private; | ||
1999 | } | ||
2000 | return ret; | ||
2001 | } | ||
2002 | |||
2003 | static const struct file_operations gfs2_glocks_fops = { | ||
2004 | .owner = THIS_MODULE, | ||
2005 | .open = gfs2_glocks_open, | ||
2006 | .read = seq_read, | ||
2007 | .llseek = seq_lseek, | ||
2008 | .release = seq_release_private, | ||
2009 | }; | ||
2010 | |||
2011 | static const struct file_operations gfs2_glstats_fops = { | ||
1851 | .owner = THIS_MODULE, | 2012 | .owner = THIS_MODULE, |
1852 | .open = gfs2_debugfs_open, | 2013 | .open = gfs2_glstats_open, |
2014 | .read = seq_read, | ||
2015 | .llseek = seq_lseek, | ||
2016 | .release = seq_release_private, | ||
2017 | }; | ||
2018 | |||
2019 | static const struct file_operations gfs2_sbstats_fops = { | ||
2020 | .owner = THIS_MODULE, | ||
2021 | .open = gfs2_sbstats_open, | ||
1853 | .read = seq_read, | 2022 | .read = seq_read, |
1854 | .llseek = seq_lseek, | 2023 | .llseek = seq_lseek, |
1855 | .release = seq_release_private, | 2024 | .release = seq_release_private, |
@@ -1863,20 +2032,45 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp) | |||
1863 | sdp->debugfs_dentry_glocks = debugfs_create_file("glocks", | 2032 | sdp->debugfs_dentry_glocks = debugfs_create_file("glocks", |
1864 | S_IFREG | S_IRUGO, | 2033 | S_IFREG | S_IRUGO, |
1865 | sdp->debugfs_dir, sdp, | 2034 | sdp->debugfs_dir, sdp, |
1866 | &gfs2_debug_fops); | 2035 | &gfs2_glocks_fops); |
1867 | if (!sdp->debugfs_dentry_glocks) | 2036 | if (!sdp->debugfs_dentry_glocks) |
1868 | return -ENOMEM; | 2037 | goto fail; |
2038 | |||
2039 | sdp->debugfs_dentry_glstats = debugfs_create_file("glstats", | ||
2040 | S_IFREG | S_IRUGO, | ||
2041 | sdp->debugfs_dir, sdp, | ||
2042 | &gfs2_glstats_fops); | ||
2043 | if (!sdp->debugfs_dentry_glstats) | ||
2044 | goto fail; | ||
2045 | |||
2046 | sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats", | ||
2047 | S_IFREG | S_IRUGO, | ||
2048 | sdp->debugfs_dir, sdp, | ||
2049 | &gfs2_sbstats_fops); | ||
2050 | if (!sdp->debugfs_dentry_sbstats) | ||
2051 | goto fail; | ||
1869 | 2052 | ||
1870 | return 0; | 2053 | return 0; |
2054 | fail: | ||
2055 | gfs2_delete_debugfs_file(sdp); | ||
2056 | return -ENOMEM; | ||
1871 | } | 2057 | } |
1872 | 2058 | ||
1873 | void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp) | 2059 | void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp) |
1874 | { | 2060 | { |
1875 | if (sdp && sdp->debugfs_dir) { | 2061 | if (sdp->debugfs_dir) { |
1876 | if (sdp->debugfs_dentry_glocks) { | 2062 | if (sdp->debugfs_dentry_glocks) { |
1877 | debugfs_remove(sdp->debugfs_dentry_glocks); | 2063 | debugfs_remove(sdp->debugfs_dentry_glocks); |
1878 | sdp->debugfs_dentry_glocks = NULL; | 2064 | sdp->debugfs_dentry_glocks = NULL; |
1879 | } | 2065 | } |
2066 | if (sdp->debugfs_dentry_glstats) { | ||
2067 | debugfs_remove(sdp->debugfs_dentry_glstats); | ||
2068 | sdp->debugfs_dentry_glstats = NULL; | ||
2069 | } | ||
2070 | if (sdp->debugfs_dentry_sbstats) { | ||
2071 | debugfs_remove(sdp->debugfs_dentry_sbstats); | ||
2072 | sdp->debugfs_dentry_sbstats = NULL; | ||
2073 | } | ||
1880 | debugfs_remove(sdp->debugfs_dir); | 2074 | debugfs_remove(sdp->debugfs_dir); |
1881 | sdp->debugfs_dir = NULL; | 2075 | sdp->debugfs_dir = NULL; |
1882 | } | 2076 | } |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 97742a7ea9cc..4d546df58ac9 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/rculist_bl.h> | 19 | #include <linux/rculist_bl.h> |
20 | #include <linux/completion.h> | 20 | #include <linux/completion.h> |
21 | #include <linux/rbtree.h> | 21 | #include <linux/rbtree.h> |
22 | #include <linux/ktime.h> | ||
23 | #include <linux/percpu.h> | ||
22 | 24 | ||
23 | #define DIO_WAIT 0x00000010 | 25 | #define DIO_WAIT 0x00000010 |
24 | #define DIO_METADATA 0x00000020 | 26 | #define DIO_METADATA 0x00000020 |
@@ -205,6 +207,22 @@ struct gfs2_glock_operations { | |||
205 | }; | 207 | }; |
206 | 208 | ||
207 | enum { | 209 | enum { |
210 | GFS2_LKS_SRTT = 0, /* Non blocking smoothed round trip time */ | ||
211 | GFS2_LKS_SRTTVAR = 1, /* Non blocking smoothed variance */ | ||
212 | GFS2_LKS_SRTTB = 2, /* Blocking smoothed round trip time */ | ||
213 | GFS2_LKS_SRTTVARB = 3, /* Blocking smoothed variance */ | ||
214 | GFS2_LKS_SIRT = 4, /* Smoothed Inter-request time */ | ||
215 | GFS2_LKS_SIRTVAR = 5, /* Smoothed Inter-request variance */ | ||
216 | GFS2_LKS_DCOUNT = 6, /* Count of dlm requests */ | ||
217 | GFS2_LKS_QCOUNT = 7, /* Count of gfs2_holder queues */ | ||
218 | GFS2_NR_LKSTATS | ||
219 | }; | ||
220 | |||
221 | struct gfs2_lkstats { | ||
222 | s64 stats[GFS2_NR_LKSTATS]; | ||
223 | }; | ||
224 | |||
225 | enum { | ||
208 | /* States */ | 226 | /* States */ |
209 | HIF_HOLDER = 6, /* Set for gh that "holds" the glock */ | 227 | HIF_HOLDER = 6, /* Set for gh that "holds" the glock */ |
210 | HIF_FIRST = 7, | 228 | HIF_FIRST = 7, |
@@ -238,10 +256,12 @@ enum { | |||
238 | GLF_QUEUED = 12, | 256 | GLF_QUEUED = 12, |
239 | GLF_LRU = 13, | 257 | GLF_LRU = 13, |
240 | GLF_OBJECT = 14, /* Used only for tracing */ | 258 | GLF_OBJECT = 14, /* Used only for tracing */ |
259 | GLF_BLOCKING = 15, | ||
241 | }; | 260 | }; |
242 | 261 | ||
243 | struct gfs2_glock { | 262 | struct gfs2_glock { |
244 | struct hlist_bl_node gl_list; | 263 | struct hlist_bl_node gl_list; |
264 | struct gfs2_sbd *gl_sbd; | ||
245 | unsigned long gl_flags; /* GLF_... */ | 265 | unsigned long gl_flags; /* GLF_... */ |
246 | struct lm_lockname gl_name; | 266 | struct lm_lockname gl_name; |
247 | atomic_t gl_ref; | 267 | atomic_t gl_ref; |
@@ -261,16 +281,14 @@ struct gfs2_glock { | |||
261 | struct list_head gl_holders; | 281 | struct list_head gl_holders; |
262 | 282 | ||
263 | const struct gfs2_glock_operations *gl_ops; | 283 | const struct gfs2_glock_operations *gl_ops; |
264 | char gl_strname[GDLM_STRNAME_BYTES]; | 284 | ktime_t gl_dstamp; |
285 | struct gfs2_lkstats gl_stats; | ||
265 | struct dlm_lksb gl_lksb; | 286 | struct dlm_lksb gl_lksb; |
266 | char gl_lvb[32]; | 287 | char gl_lvb[32]; |
267 | unsigned long gl_tchange; | 288 | unsigned long gl_tchange; |
268 | void *gl_object; | 289 | void *gl_object; |
269 | 290 | ||
270 | struct list_head gl_lru; | 291 | struct list_head gl_lru; |
271 | |||
272 | struct gfs2_sbd *gl_sbd; | ||
273 | |||
274 | struct list_head gl_ail_list; | 292 | struct list_head gl_ail_list; |
275 | atomic_t gl_ail_count; | 293 | atomic_t gl_ail_count; |
276 | atomic_t gl_revokes; | 294 | atomic_t gl_revokes; |
@@ -560,8 +578,14 @@ struct lm_lockstruct { | |||
560 | uint32_t *ls_recover_result; /* result of last jid recovery */ | 578 | uint32_t *ls_recover_result; /* result of last jid recovery */ |
561 | }; | 579 | }; |
562 | 580 | ||
581 | struct gfs2_pcpu_lkstats { | ||
582 | /* One struct for each glock type */ | ||
583 | struct gfs2_lkstats lkstats[10]; | ||
584 | }; | ||
585 | |||
563 | struct gfs2_sbd { | 586 | struct gfs2_sbd { |
564 | struct super_block *sd_vfs; | 587 | struct super_block *sd_vfs; |
588 | struct gfs2_pcpu_lkstats __percpu *sd_lkstats; | ||
565 | struct kobject sd_kobj; | 589 | struct kobject sd_kobj; |
566 | unsigned long sd_flags; /* SDF_... */ | 590 | unsigned long sd_flags; /* SDF_... */ |
567 | struct gfs2_sb_host sd_sb; | 591 | struct gfs2_sb_host sd_sb; |
@@ -725,8 +749,23 @@ struct gfs2_sbd { | |||
725 | 749 | ||
726 | unsigned long sd_last_warning; | 750 | unsigned long sd_last_warning; |
727 | struct dentry *debugfs_dir; /* debugfs directory */ | 751 | struct dentry *debugfs_dir; /* debugfs directory */ |
728 | struct dentry *debugfs_dentry_glocks; /* for debugfs */ | 752 | struct dentry *debugfs_dentry_glocks; |
753 | struct dentry *debugfs_dentry_glstats; | ||
754 | struct dentry *debugfs_dentry_sbstats; | ||
729 | }; | 755 | }; |
730 | 756 | ||
757 | static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which) | ||
758 | { | ||
759 | gl->gl_stats.stats[which]++; | ||
760 | } | ||
761 | |||
762 | static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) | ||
763 | { | ||
764 | const struct gfs2_sbd *sdp = gl->gl_sbd; | ||
765 | preempt_disable(); | ||
766 | this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++; | ||
767 | preempt_enable(); | ||
768 | } | ||
769 | |||
731 | #endif /* __INCORE_DOT_H__ */ | 770 | #endif /* __INCORE_DOT_H__ */ |
732 | 771 | ||
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 8944d1e32ab5..f8411bd1b805 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c | |||
@@ -18,14 +18,106 @@ | |||
18 | #include "glock.h" | 18 | #include "glock.h" |
19 | #include "util.h" | 19 | #include "util.h" |
20 | #include "sys.h" | 20 | #include "sys.h" |
21 | #include "trace_gfs2.h" | ||
21 | 22 | ||
22 | extern struct workqueue_struct *gfs2_control_wq; | 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 | static void gdlm_ast(void *arg) | 115 | static void gdlm_ast(void *arg) |
25 | { | 116 | { |
26 | struct gfs2_glock *gl = arg; | 117 | struct gfs2_glock *gl = arg; |
27 | unsigned ret = gl->gl_state; | 118 | unsigned ret = gl->gl_state; |
28 | 119 | ||
120 | gfs2_update_reply_times(gl); | ||
29 | BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); | 121 | BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); |
30 | 122 | ||
31 | if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) | 123 | if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) |
@@ -111,7 +203,7 @@ static int make_mode(const unsigned int lmstate) | |||
111 | static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, | 203 | static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, |
112 | const int req) | 204 | const int req) |
113 | { | 205 | { |
114 | u32 lkf = 0; | 206 | u32 lkf = DLM_LKF_VALBLK; |
115 | 207 | ||
116 | if (gfs_flags & LM_FLAG_TRY) | 208 | if (gfs_flags & LM_FLAG_TRY) |
117 | lkf |= DLM_LKF_NOQUEUE; | 209 | lkf |= DLM_LKF_NOQUEUE; |
@@ -138,26 +230,43 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, | |||
138 | if (lkid != 0) | 230 | if (lkid != 0) |
139 | lkf |= DLM_LKF_CONVERT; | 231 | lkf |= DLM_LKF_CONVERT; |
140 | 232 | ||
141 | lkf |= DLM_LKF_VALBLK; | ||
142 | |||
143 | return lkf; | 233 | return lkf; |
144 | } | 234 | } |
145 | 235 | ||
236 | static void gfs2_reverse_hex(char *c, u64 value) | ||
237 | { | ||
238 | while (value) { | ||
239 | *c-- = hex_asc[value & 0x0f]; | ||
240 | value >>= 4; | ||
241 | } | ||
242 | } | ||
243 | |||
146 | static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, | 244 | static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, |
147 | unsigned int flags) | 245 | unsigned int flags) |
148 | { | 246 | { |
149 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; | 247 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; |
150 | int req; | 248 | int req; |
151 | u32 lkf; | 249 | u32 lkf; |
250 | char strname[GDLM_STRNAME_BYTES] = ""; | ||
152 | 251 | ||
153 | req = make_mode(req_state); | 252 | req = make_mode(req_state); |
154 | lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); | 253 | lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); |
155 | 254 | gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); | |
255 | gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); | ||
256 | if (gl->gl_lksb.sb_lkid) { | ||
257 | gfs2_update_request_times(gl); | ||
258 | } else { | ||
259 | memset(strname, ' ', GDLM_STRNAME_BYTES - 1); | ||
260 | strname[GDLM_STRNAME_BYTES - 1] = '\0'; | ||
261 | gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type); | ||
262 | gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number); | ||
263 | gl->gl_dstamp = ktime_get_real(); | ||
264 | } | ||
156 | /* | 265 | /* |
157 | * Submit the actual lock request. | 266 | * Submit the actual lock request. |
158 | */ | 267 | */ |
159 | 268 | ||
160 | return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, | 269 | return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname, |
161 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); | 270 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); |
162 | } | 271 | } |
163 | 272 | ||
@@ -172,6 +281,10 @@ static void gdlm_put_lock(struct gfs2_glock *gl) | |||
172 | return; | 281 | return; |
173 | } | 282 | } |
174 | 283 | ||
284 | clear_bit(GLF_BLOCKING, &gl->gl_flags); | ||
285 | gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); | ||
286 | gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); | ||
287 | gfs2_update_request_times(gl); | ||
175 | error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, | 288 | error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, |
176 | NULL, gl); | 289 | NULL, gl); |
177 | if (error) { | 290 | if (error) { |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 24f609c9ef91..a55baa7f3239 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -68,6 +68,12 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
68 | 68 | ||
69 | sb->s_fs_info = sdp; | 69 | sb->s_fs_info = sdp; |
70 | sdp->sd_vfs = sb; | 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 | set_bit(SDF_NOJOURNALID, &sdp->sd_flags); | 77 | set_bit(SDF_NOJOURNALID, &sdp->sd_flags); |
72 | gfs2_tune_init(&sdp->sd_tune); | 78 | gfs2_tune_init(&sdp->sd_tune); |
73 | 79 | ||
@@ -1221,6 +1227,7 @@ fail_sys: | |||
1221 | gfs2_sys_fs_del(sdp); | 1227 | gfs2_sys_fs_del(sdp); |
1222 | fail: | 1228 | fail: |
1223 | gfs2_delete_debugfs_file(sdp); | 1229 | gfs2_delete_debugfs_file(sdp); |
1230 | free_percpu(sdp->sd_lkstats); | ||
1224 | kfree(sdp); | 1231 | kfree(sdp); |
1225 | sb->s_fs_info = NULL; | 1232 | sb->s_fs_info = NULL; |
1226 | return error; | 1233 | return error; |
@@ -1393,6 +1400,7 @@ static void gfs2_kill_sb(struct super_block *sb) | |||
1393 | shrink_dcache_sb(sb); | 1400 | shrink_dcache_sb(sb); |
1394 | kill_block_super(sb); | 1401 | kill_block_super(sb); |
1395 | gfs2_delete_debugfs_file(sdp); | 1402 | gfs2_delete_debugfs_file(sdp); |
1403 | free_percpu(sdp->sd_lkstats); | ||
1396 | kfree(sdp); | 1404 | kfree(sdp); |
1397 | } | 1405 | } |
1398 | 1406 | ||
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 5d07609ec57d..dfa89cd75534 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/dlmconstants.h> | 11 | #include <linux/dlmconstants.h> |
12 | #include <linux/gfs2_ondisk.h> | 12 | #include <linux/gfs2_ondisk.h> |
13 | #include <linux/writeback.h> | 13 | #include <linux/writeback.h> |
14 | #include <linux/ktime.h> | ||
14 | #include "incore.h" | 15 | #include "incore.h" |
15 | #include "glock.h" | 16 | #include "glock.h" |
16 | 17 | ||
@@ -43,7 +44,8 @@ | |||
43 | {(1UL << GLF_FROZEN), "F" }, \ | 44 | {(1UL << GLF_FROZEN), "F" }, \ |
44 | {(1UL << GLF_QUEUED), "q" }, \ | 45 | {(1UL << GLF_QUEUED), "q" }, \ |
45 | {(1UL << GLF_LRU), "L" }, \ | 46 | {(1UL << GLF_LRU), "L" }, \ |
46 | {(1UL << GLF_OBJECT), "o" }) | 47 | {(1UL << GLF_OBJECT), "o" }, \ |
48 | {(1UL << GLF_BLOCKING), "b" }) | ||
47 | 49 | ||
48 | #ifndef NUMPTY | 50 | #ifndef NUMPTY |
49 | #define NUMPTY | 51 | #define NUMPTY |
@@ -236,6 +238,62 @@ TRACE_EVENT(gfs2_glock_queue, | |||
236 | glock_trace_name(__entry->state)) | 238 | glock_trace_name(__entry->state)) |
237 | ); | 239 | ); |
238 | 240 | ||
241 | /* DLM sends a reply to GFS2 */ | ||
242 | TRACE_EVENT(gfs2_glock_lock_time, | ||
243 | |||
244 | TP_PROTO(const struct gfs2_glock *gl, s64 tdiff), | ||
245 | |||
246 | TP_ARGS(gl, tdiff), | ||
247 | |||
248 | TP_STRUCT__entry( | ||
249 | __field( dev_t, dev ) | ||
250 | __field( u64, glnum ) | ||
251 | __field( u32, gltype ) | ||
252 | __field( int, status ) | ||
253 | __field( char, flags ) | ||
254 | __field( s64, tdiff ) | ||
255 | __field( s64, srtt ) | ||
256 | __field( s64, srttvar ) | ||
257 | __field( s64, srttb ) | ||
258 | __field( s64, srttvarb ) | ||
259 | __field( s64, sirt ) | ||
260 | __field( s64, sirtvar ) | ||
261 | __field( s64, dcount ) | ||
262 | __field( s64, qcount ) | ||
263 | ), | ||
264 | |||
265 | TP_fast_assign( | ||
266 | __entry->dev = gl->gl_sbd->sd_vfs->s_dev; | ||
267 | __entry->glnum = gl->gl_name.ln_number; | ||
268 | __entry->gltype = gl->gl_name.ln_type; | ||
269 | __entry->status = gl->gl_lksb.sb_status; | ||
270 | __entry->flags = gl->gl_lksb.sb_flags; | ||
271 | __entry->tdiff = tdiff; | ||
272 | __entry->srtt = gl->gl_stats.stats[GFS2_LKS_SRTT]; | ||
273 | __entry->srttvar = gl->gl_stats.stats[GFS2_LKS_SRTTVAR]; | ||
274 | __entry->srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB]; | ||
275 | __entry->srttvarb = gl->gl_stats.stats[GFS2_LKS_SRTTVARB]; | ||
276 | __entry->sirt = gl->gl_stats.stats[GFS2_LKS_SIRT]; | ||
277 | __entry->sirtvar = gl->gl_stats.stats[GFS2_LKS_SIRTVAR]; | ||
278 | __entry->dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT]; | ||
279 | __entry->qcount = gl->gl_stats.stats[GFS2_LKS_QCOUNT]; | ||
280 | ), | ||
281 | |||
282 | 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", | ||
283 | MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype, | ||
284 | (unsigned long long)__entry->glnum, | ||
285 | __entry->status, __entry->flags, | ||
286 | (long long)__entry->tdiff, | ||
287 | (long long)__entry->srtt, | ||
288 | (long long)__entry->srttvar, | ||
289 | (long long)__entry->srttb, | ||
290 | (long long)__entry->srttvarb, | ||
291 | (long long)__entry->sirt, | ||
292 | (long long)__entry->sirtvar, | ||
293 | (long long)__entry->dcount, | ||
294 | (long long)__entry->qcount) | ||
295 | ); | ||
296 | |||
239 | /* Section 2 - Log/journal | 297 | /* Section 2 - Log/journal |
240 | * | 298 | * |
241 | * Objectives: | 299 | * Objectives: |