Messages in this thread Patch in this message | | | Date | Thu, 23 Jul 2009 17:04:21 +0800 | From | Li Zefan <> | Subject | Re: [PATCH/RFC] ummunot: Userspace support for MMU notifications |
| |
> > > 1. ioctl() to register/unregister an address range to watch in the > > > kernel (cf struct ummunot_register_ioctl in <linux/ummunot.h>). > > > > > > 2. read() to retrieve events generated when a mapping in a watched > > > address range is invalidated (cf struct ummunot_event in > > > <linux/ummunot.h>). select()/poll()/epoll() and SIGIO are handled > > > for this IO. > > > > > > 3. mmap() one page at offset 0 to map a kernel page that contains a > > > generation counter that is incremented each time an event is > > > generated. This allows userspace to have a fast path that checks > > > that no events have occurred without a system call. > > > > If you stand back and squint, each of 1, 2 and 3 are things which the > > kernel already provides for the delivery of ftrace events to userspace. > > > > Did you look at reusing all that stuff? > > No, not really... will investigate a bit further. Any pointers to how > the ftrace stuff might work?
This can be implemented as a tracer or trace events, though I'm not sure if it can fully meet your requirements or not.
To implement it as trace events, we add tracepoints in mmu_inlivadate_xxx(), and define some TRACE_EVENT() macros.
And below shows how to use it:
# mount -t debugfs xxx /mnt # cd /mnt/tracing/ # echo 1 > events/mmu/enable # echo '(start >= 10000000 && end <= 10004096) || \ (start >= 20000000 && end <= 20004096)' > events/mmu/filter # cat trace_pipe bash-2066 [001] 795.239077: mmu_invalidate_range_start: start=10000000 end=10000100 bash-2066 [001] 795.239091: mmu_invalidate_range_start: start=10000000 end=10000100 bash-2066 [001] 795.239098: mmu_invalidate_range_start: start=10000000 end=10000100 cat-2189 [001] 795.239502: mmu_invalidate_page: start=20000000 end=20003000 cat-2189 [001] 795.239578: mmu_invalidate_page: start=20000000 end=20003000 bash-2066 [001] 795.239626: mmu_invalidate_page: start=20000000 end=20003000
The patch is extremely simple:
--- include/linux/mmu_notifier.h | 4 +++ include/trace/events/mmu.h | 55 ++++++++++++++++++++++++++++++++++++++++++ mm/mmu_notifier.c | 3 ++ 3 files changed, 62 insertions(+), 0 deletions(-) create mode 100644 include/trace/events/mmu.h
diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index b77486d..49ff4cc 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -5,6 +5,8 @@ #include <linux/spinlock.h> #include <linux/mm_types.h> +#include <trace/events/mmu.h> + struct mmu_notifier; struct mmu_notifier_ops; @@ -178,6 +180,7 @@ static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, unsigned long address) { + trace_mmu_invalidate_page(address); if (mm_has_notifiers(mm)) __mmu_notifier_invalidate_page(mm, address); } @@ -185,6 +188,7 @@ static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm, unsigned long start, unsigned long end) { + trace_mmu_invalidate_range_start(start, end); if (mm_has_notifiers(mm)) __mmu_notifier_invalidate_range_start(mm, start, end); } diff --git a/include/trace/events/mmu.h b/include/trace/events/mmu.h new file mode 100644 index 0000000..0d6bbcd --- /dev/null +++ b/include/trace/events/mmu.h @@ -0,0 +1,55 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mmu + +#if !defined(_TRACE_MMU_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MMU_H + +#include <linux/tracepoint.h> + +#ifdef CONFIG_MMU_NOTIFIER + +TRACE_EVENT(mmu_invalidate_page, + + TP_PROTO(unsigned long addr), + + TP_ARGS(addr), + + TP_STRUCT__entry( + __field( unsigned long, start ) + __field( unsigned long, end ) + ), + + TP_fast_assign( + __entry->start = addr; + __entry->end = addr + PAGE_SIZE; + ), + + TP_printk("start=%lu end=%lu", __entry->start, __entry->end) +); + +TRACE_EVENT(mmu_invalidate_range_start, + + TP_PROTO(unsigned long start, unsigned long end), + + TP_ARGS(start, end), + + TP_STRUCT__entry( + __field( unsigned long, start ) + __field( unsigned long, end ) + ), + + TP_fast_assign( + __entry->start = start; + __entry->end = end; + ), + + TP_printk("start=%lu end=%lu", __entry->start, __entry->end) +); + +#endif /* CONFIG_MMU_NOTIFIER */ + +#endif /* _TRACE_MMU_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> + diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 5f4ef02..685ffdc 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -17,6 +17,9 @@ #include <linux/rcupdate.h> #include <linux/sched.h> +#define CREATE_TRACE_POINTS +#include <trace/events/mmu.h> + /* * This function can't run concurrently against mmu_notifier_register * because mm->mm_users > 0 during mmu_notifier_register and exit_mmap -- 1.6.3
| |