diff options
author | Jeff Layton <jlayton@poochiereds.net> | 2014-05-09 14:13:05 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@poochiereds.net> | 2014-06-02 08:09:30 -0400 |
commit | 62af4f1f7df44ea0bb1a11c94ac9fb384bf1c564 (patch) | |
tree | 5fdc044c1d7eed924a90d101a306ba53617ebac2 | |
parent | 5315c26a6c557f44733725004fc7dc25c8a94cd5 (diff) |
locks: add some tracepoints in the lease handling code
v2: add a __break_lease tracepoint for non-blocking case
Recently, I needed these to help track down a softlockup when recalling a
delegation, but they might be helpful in other situations as well.
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Signed-off-by: Jeff Layton <jlayton@poochiereds.net>
-rw-r--r-- | fs/locks.c | 11 | ||||
-rw-r--r-- | include/trace/events/filelock.h | 96 |
2 files changed, 107 insertions, 0 deletions
diff --git a/fs/locks.c b/fs/locks.c index facf76d9fcb4..da57c9b7e844 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -130,6 +130,9 @@ | |||
130 | #include <linux/percpu.h> | 130 | #include <linux/percpu.h> |
131 | #include <linux/lglock.h> | 131 | #include <linux/lglock.h> |
132 | 132 | ||
133 | #define CREATE_TRACE_POINTS | ||
134 | #include <trace/events/filelock.h> | ||
135 | |||
133 | #include <asm/uaccess.h> | 136 | #include <asm/uaccess.h> |
134 | 137 | ||
135 | #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) | 138 | #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) |
@@ -1287,6 +1290,7 @@ static void time_out_leases(struct inode *inode) | |||
1287 | 1290 | ||
1288 | before = &inode->i_flock; | 1291 | before = &inode->i_flock; |
1289 | while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { | 1292 | while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { |
1293 | trace_time_out_leases(inode, fl); | ||
1290 | if (past_time(fl->fl_downgrade_time)) | 1294 | if (past_time(fl->fl_downgrade_time)) |
1291 | lease_modify(before, F_RDLCK); | 1295 | lease_modify(before, F_RDLCK); |
1292 | if (past_time(fl->fl_break_time)) | 1296 | if (past_time(fl->fl_break_time)) |
@@ -1374,6 +1378,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
1374 | } | 1378 | } |
1375 | 1379 | ||
1376 | if (i_have_this_lease || (mode & O_NONBLOCK)) { | 1380 | if (i_have_this_lease || (mode & O_NONBLOCK)) { |
1381 | trace_break_lease_noblock(inode, new_fl); | ||
1377 | error = -EWOULDBLOCK; | 1382 | error = -EWOULDBLOCK; |
1378 | goto out; | 1383 | goto out; |
1379 | } | 1384 | } |
@@ -1385,10 +1390,12 @@ restart: | |||
1385 | if (break_time == 0) | 1390 | if (break_time == 0) |
1386 | break_time++; | 1391 | break_time++; |
1387 | locks_insert_block(flock, new_fl); | 1392 | locks_insert_block(flock, new_fl); |
1393 | trace_break_lease_block(inode, new_fl); | ||
1388 | spin_unlock(&inode->i_lock); | 1394 | spin_unlock(&inode->i_lock); |
1389 | error = wait_event_interruptible_timeout(new_fl->fl_wait, | 1395 | error = wait_event_interruptible_timeout(new_fl->fl_wait, |
1390 | !new_fl->fl_next, break_time); | 1396 | !new_fl->fl_next, break_time); |
1391 | spin_lock(&inode->i_lock); | 1397 | spin_lock(&inode->i_lock); |
1398 | trace_break_lease_unblock(inode, new_fl); | ||
1392 | locks_delete_block(new_fl); | 1399 | locks_delete_block(new_fl); |
1393 | if (error >= 0) { | 1400 | if (error >= 0) { |
1394 | if (error == 0) | 1401 | if (error == 0) |
@@ -1510,6 +1517,8 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp | |||
1510 | int error; | 1517 | int error; |
1511 | 1518 | ||
1512 | lease = *flp; | 1519 | lease = *flp; |
1520 | trace_generic_add_lease(inode, lease); | ||
1521 | |||
1513 | /* | 1522 | /* |
1514 | * In the delegation case we need mutual exclusion with | 1523 | * In the delegation case we need mutual exclusion with |
1515 | * a number of operations that take the i_mutex. We trylock | 1524 | * a number of operations that take the i_mutex. We trylock |
@@ -1599,6 +1608,8 @@ static int generic_delete_lease(struct file *filp, struct file_lock **flp) | |||
1599 | struct dentry *dentry = filp->f_path.dentry; | 1608 | struct dentry *dentry = filp->f_path.dentry; |
1600 | struct inode *inode = dentry->d_inode; | 1609 | struct inode *inode = dentry->d_inode; |
1601 | 1610 | ||
1611 | trace_generic_delete_lease(inode, *flp); | ||
1612 | |||
1602 | for (before = &inode->i_flock; | 1613 | for (before = &inode->i_flock; |
1603 | ((fl = *before) != NULL) && IS_LEASE(fl); | 1614 | ((fl = *before) != NULL) && IS_LEASE(fl); |
1604 | before = &fl->fl_next) { | 1615 | before = &fl->fl_next) { |
diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h new file mode 100644 index 000000000000..59d11c22f076 --- /dev/null +++ b/include/trace/events/filelock.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Events for filesystem locks | ||
3 | * | ||
4 | * Copyright 2013 Jeff Layton <jlayton@poochiereds.net> | ||
5 | */ | ||
6 | #undef TRACE_SYSTEM | ||
7 | #define TRACE_SYSTEM filelock | ||
8 | |||
9 | #if !defined(_TRACE_FILELOCK_H) || defined(TRACE_HEADER_MULTI_READ) | ||
10 | #define _TRACE_FILELOCK_H | ||
11 | |||
12 | #include <linux/tracepoint.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/kdev_t.h> | ||
16 | |||
17 | #define show_fl_flags(val) \ | ||
18 | __print_flags(val, "|", \ | ||
19 | { FL_POSIX, "FL_POSIX" }, \ | ||
20 | { FL_FLOCK, "FL_FLOCK" }, \ | ||
21 | { FL_DELEG, "FL_DELEG" }, \ | ||
22 | { FL_ACCESS, "FL_ACCESS" }, \ | ||
23 | { FL_EXISTS, "FL_EXISTS" }, \ | ||
24 | { FL_LEASE, "FL_LEASE" }, \ | ||
25 | { FL_CLOSE, "FL_CLOSE" }, \ | ||
26 | { FL_SLEEP, "FL_SLEEP" }, \ | ||
27 | { FL_DOWNGRADE_PENDING, "FL_DOWNGRADE_PENDING" }, \ | ||
28 | { FL_UNLOCK_PENDING, "FL_UNLOCK_PENDING" }, \ | ||
29 | { FL_OFDLCK, "FL_OFDLCK" }) | ||
30 | |||
31 | #define show_fl_type(val) \ | ||
32 | __print_symbolic(val, \ | ||
33 | { F_RDLCK, "F_RDLCK" }, \ | ||
34 | { F_WRLCK, "F_WRLCK" }, \ | ||
35 | { F_UNLCK, "F_UNLCK" }) | ||
36 | |||
37 | DECLARE_EVENT_CLASS(filelock_lease, | ||
38 | |||
39 | TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
40 | |||
41 | TP_ARGS(inode, fl), | ||
42 | |||
43 | TP_STRUCT__entry( | ||
44 | __field(struct file_lock *, fl) | ||
45 | __field(unsigned long, i_ino) | ||
46 | __field(dev_t, s_dev) | ||
47 | __field(struct file_lock *, fl_next) | ||
48 | __field(fl_owner_t, fl_owner) | ||
49 | __field(unsigned int, fl_flags) | ||
50 | __field(unsigned char, fl_type) | ||
51 | __field(unsigned long, fl_break_time) | ||
52 | __field(unsigned long, fl_downgrade_time) | ||
53 | ), | ||
54 | |||
55 | TP_fast_assign( | ||
56 | __entry->fl = fl; | ||
57 | __entry->s_dev = inode->i_sb->s_dev; | ||
58 | __entry->i_ino = inode->i_ino; | ||
59 | __entry->fl_next = fl->fl_next; | ||
60 | __entry->fl_owner = fl->fl_owner; | ||
61 | __entry->fl_flags = fl->fl_flags; | ||
62 | __entry->fl_type = fl->fl_type; | ||
63 | __entry->fl_break_time = fl->fl_break_time; | ||
64 | __entry->fl_downgrade_time = fl->fl_downgrade_time; | ||
65 | ), | ||
66 | |||
67 | TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_flags=%s fl_type=%s fl_break_time=%lu fl_downgrade_time=%lu", | ||
68 | __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev), | ||
69 | __entry->i_ino, __entry->fl_next, __entry->fl_owner, | ||
70 | show_fl_flags(__entry->fl_flags), | ||
71 | show_fl_type(__entry->fl_type), | ||
72 | __entry->fl_break_time, __entry->fl_downgrade_time) | ||
73 | ); | ||
74 | |||
75 | DEFINE_EVENT(filelock_lease, break_lease_noblock, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
76 | TP_ARGS(inode, fl)); | ||
77 | |||
78 | DEFINE_EVENT(filelock_lease, break_lease_block, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
79 | TP_ARGS(inode, fl)); | ||
80 | |||
81 | DEFINE_EVENT(filelock_lease, break_lease_unblock, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
82 | TP_ARGS(inode, fl)); | ||
83 | |||
84 | DEFINE_EVENT(filelock_lease, generic_add_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
85 | TP_ARGS(inode, fl)); | ||
86 | |||
87 | DEFINE_EVENT(filelock_lease, generic_delete_lease, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
88 | TP_ARGS(inode, fl)); | ||
89 | |||
90 | DEFINE_EVENT(filelock_lease, time_out_leases, TP_PROTO(struct inode *inode, struct file_lock *fl), | ||
91 | TP_ARGS(inode, fl)); | ||
92 | |||
93 | #endif /* _TRACE_FILELOCK_H */ | ||
94 | |||
95 | /* This part must be outside protection */ | ||
96 | #include <trace/define_trace.h> | ||