diff options
author | Dave Chinner <david@fromorbit.com> | 2010-01-11 06:47:46 -0500 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-01-15 16:34:12 -0500 |
commit | 0fa800fbd549736dfdc1d7761f87e33dc8cd973b (patch) | |
tree | 3940f2f5bc4bb3bec888f7ef9ed8a8c875e02695 | |
parent | aed3bb90abaf0b42e8c8747e192f7bb97f445279 (diff) |
xfs: Add trace points for per-ag refcount debugging.
Uninline xfs_perag_{get,put} so that tracepoints can be inserted
into them to speed debugging of reference count problems.
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_trace.h | 27 | ||||
-rw-r--r-- | fs/xfs/xfs_ag.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 34 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 25 |
4 files changed, 65 insertions, 23 deletions
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index 3353aef50530..1bb09e70b2eb 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h | |||
@@ -78,6 +78,33 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class, | |||
78 | ) | 78 | ) |
79 | ) | 79 | ) |
80 | 80 | ||
81 | #define DEFINE_PERAG_REF_EVENT(name) \ | ||
82 | TRACE_EVENT(name, \ | ||
83 | TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \ | ||
84 | unsigned long caller_ip), \ | ||
85 | TP_ARGS(mp, agno, refcount, caller_ip), \ | ||
86 | TP_STRUCT__entry( \ | ||
87 | __field(dev_t, dev) \ | ||
88 | __field(xfs_agnumber_t, agno) \ | ||
89 | __field(int, refcount) \ | ||
90 | __field(unsigned long, caller_ip) \ | ||
91 | ), \ | ||
92 | TP_fast_assign( \ | ||
93 | __entry->dev = mp->m_super->s_dev; \ | ||
94 | __entry->agno = agno; \ | ||
95 | __entry->refcount = refcount; \ | ||
96 | __entry->caller_ip = caller_ip; \ | ||
97 | ), \ | ||
98 | TP_printk("dev %d:%d agno %u refcount %d caller %pf", \ | ||
99 | MAJOR(__entry->dev), MINOR(__entry->dev), \ | ||
100 | __entry->agno, \ | ||
101 | __entry->refcount, \ | ||
102 | (char *)__entry->caller_ip) \ | ||
103 | ); | ||
104 | |||
105 | DEFINE_PERAG_REF_EVENT(xfs_perag_get) | ||
106 | DEFINE_PERAG_REF_EVENT(xfs_perag_put) | ||
107 | |||
81 | #define DEFINE_ATTR_LIST_EVENT(name) \ | 108 | #define DEFINE_ATTR_LIST_EVENT(name) \ |
82 | DEFINE_EVENT(xfs_attr_list_class, name, \ | 109 | DEFINE_EVENT(xfs_attr_list_class, name, \ |
83 | TP_PROTO(struct xfs_attr_list_context *ctx), \ | 110 | TP_PROTO(struct xfs_attr_list_context *ctx), \ |
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 18ae43f4255d..963bc2700bf7 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h | |||
@@ -197,6 +197,8 @@ typedef struct xfs_perag_busy { | |||
197 | #endif | 197 | #endif |
198 | 198 | ||
199 | typedef struct xfs_perag { | 199 | typedef struct xfs_perag { |
200 | struct xfs_mount *pag_mount; /* owner filesystem */ | ||
201 | xfs_agnumber_t pag_agno; /* AG this structure belongs to */ | ||
200 | atomic_t pag_ref; /* perag reference count */ | 202 | atomic_t pag_ref; /* perag reference count */ |
201 | char pagf_init; /* this agf's entry is initialized */ | 203 | char pagf_init; /* this agf's entry is initialized */ |
202 | char pagi_init; /* this agi's entry is initialized */ | 204 | char pagi_init; /* this agi's entry is initialized */ |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index f241fec26070..049dbc71c28e 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -201,6 +201,38 @@ xfs_uuid_unmount( | |||
201 | 201 | ||
202 | 202 | ||
203 | /* | 203 | /* |
204 | * Reference counting access wrappers to the perag structures. | ||
205 | */ | ||
206 | struct xfs_perag * | ||
207 | xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) | ||
208 | { | ||
209 | struct xfs_perag *pag; | ||
210 | int ref = 0; | ||
211 | |||
212 | spin_lock(&mp->m_perag_lock); | ||
213 | pag = radix_tree_lookup(&mp->m_perag_tree, agno); | ||
214 | if (pag) { | ||
215 | ASSERT(atomic_read(&pag->pag_ref) >= 0); | ||
216 | /* catch leaks in the positive direction during testing */ | ||
217 | ASSERT(atomic_read(&pag->pag_ref) < 1000); | ||
218 | ref = atomic_inc_return(&pag->pag_ref); | ||
219 | } | ||
220 | spin_unlock(&mp->m_perag_lock); | ||
221 | trace_xfs_perag_get(mp, agno, ref, _RET_IP_); | ||
222 | return pag; | ||
223 | } | ||
224 | |||
225 | void | ||
226 | xfs_perag_put(struct xfs_perag *pag) | ||
227 | { | ||
228 | int ref; | ||
229 | |||
230 | ASSERT(atomic_read(&pag->pag_ref) > 0); | ||
231 | ref = atomic_dec_return(&pag->pag_ref); | ||
232 | trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_); | ||
233 | } | ||
234 | |||
235 | /* | ||
204 | * Free up the resources associated with a mount structure. Assume that | 236 | * Free up the resources associated with a mount structure. Assume that |
205 | * the structure was initially zeroed, so we can tell which fields got | 237 | * the structure was initially zeroed, so we can tell which fields got |
206 | * initialized. | 238 | * initialized. |
@@ -433,6 +465,8 @@ xfs_initialize_perag( | |||
433 | kmem_free(pag); | 465 | kmem_free(pag); |
434 | return -EEXIST; | 466 | return -EEXIST; |
435 | } | 467 | } |
468 | pag->pag_agno = index; | ||
469 | pag->pag_mount = mp; | ||
436 | spin_unlock(&mp->m_perag_lock); | 470 | spin_unlock(&mp->m_perag_lock); |
437 | radix_tree_preload_end(); | 471 | radix_tree_preload_end(); |
438 | } | 472 | } |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 16b22120b98f..e62fd1cde464 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -386,29 +386,8 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) | |||
386 | /* | 386 | /* |
387 | * perag get/put wrappers for ref counting | 387 | * perag get/put wrappers for ref counting |
388 | */ | 388 | */ |
389 | static inline struct xfs_perag * | 389 | struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno); |
390 | xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) | 390 | void xfs_perag_put(struct xfs_perag *pag); |
391 | { | ||
392 | struct xfs_perag *pag; | ||
393 | |||
394 | spin_lock(&mp->m_perag_lock); | ||
395 | pag = radix_tree_lookup(&mp->m_perag_tree, agno); | ||
396 | if (pag) { | ||
397 | ASSERT(atomic_read(&pag->pag_ref) >= 0); | ||
398 | /* catch leaks in the positive direction during testing */ | ||
399 | ASSERT(atomic_read(&pag->pag_ref) < 1000); | ||
400 | atomic_inc(&pag->pag_ref); | ||
401 | } | ||
402 | spin_unlock(&mp->m_perag_lock); | ||
403 | return pag; | ||
404 | } | ||
405 | |||
406 | static inline void | ||
407 | xfs_perag_put(struct xfs_perag *pag) | ||
408 | { | ||
409 | ASSERT(atomic_read(&pag->pag_ref) > 0); | ||
410 | atomic_dec(&pag->pag_ref); | ||
411 | } | ||
412 | 391 | ||
413 | /* | 392 | /* |
414 | * Per-cpu superblock locking functions | 393 | * Per-cpu superblock locking functions |