ummunotify: Userspace support for MMU notifications
Subsystems (3)
PATCH 1/1 ummunotify: Userspace support for MMU notifications
Andrew,
I am resubmitting this patch because I believe that the discussion has shown this to be an acceptable solution. I have fixed the 32 bit build errors, but other than that change, the code is the same as Roland's V3 patch.
From: Roland Dreier <[email protected]>
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping via free(), munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.
We solve this not by implementing the full API proposed in the email linked above but rather with a simpler and more generic interface, which may be useful in other contexts. Specifically, we implement a new character device driver, ummunotify, that creates a /dev/ummunotify node. A userspace process can open this node read-only and use the fd as follows:
1. ioctl() to register/unregister an address range to watch in the kernel (cf struct ummunotify_register_ioctl in <linux/ummunotify.h>).
2. read() to retrieve events generated when a mapping in a watched address range is invalidated (cf struct ummunotify_event in <linux/ummunotify.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.
Thanks to Jason Gunthorpe <jgunthorpe <at> obsidianresearch.com> for suggestions on the interface design. Also thanks to Jeff Squyres <jsquyres <at> cisco.com> for prototyping support for this in Open MPI, which helped find several bugs during development.
---
Changes since v3:
- Fixed replaced [get|put] user with copy_[from|to]_user to fix x86 builds
--- Documentation/Makefile | 3 +- Documentation/ummunotify/Makefile | 7 + Documentation/ummunotify/ummunotify.txt | 150 ++++++++ Documentation/ummunotify/umn-test.c | 200 +++++++++++ drivers/char/Kconfig | 12 + drivers/char/Makefile | 1 + drivers/char/ummunotify.c | 567 +++++++++++++++++++++++++++++++ include/linux/ummunotify.h | 121 +++++++ 8 files changed, 1060 insertions(+), 1 deletions(-) create mode 100644 Documentation/ummunotify/Makefile create mode 100644 Documentation/ummunotify/ummunotify.txt create mode 100644 Documentation/ummunotify/umn-test.c create mode 100644 drivers/char/ummunotify.c create mode 100644 include/linux/ummunotify.h
Documentation/Makefile +2 -1
@@ -1,3 +1,4 @@ obj-m := DocBook/ accounting/ auxdisplay/ connector/ \ filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \ - pcmcia/ spi/ timers/ video4linux/ vm/ watchdog/src/ + pcmcia/ spi/ timers/ video4linux/ vm/ ummunotify/ \ + watchdog/src/
Documentation/ummunotify/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# List of programs to build +hostprogs-y := umn-test + +# Tell kbuild to always build the programs +always := $(hostprogs-y) + +HOSTCFLAGS_umn-test.o += -I$(objtree)/usr/include
Documentation/ummunotify/ummunotify.txt new file +150 -0
150 lines not on this page · raw message
Documentation/ummunotify/umn-test.c new file +200 -0
200 lines not on this page · raw message
drivers/char/Kconfig +12 -0
@@ -1111,6 +1111,18 @@ config DEVPORT depends on ISA || PCI default y +config UMMUNOTIFY + tristate "Userspace MMU notifications" + select MMU_NOTIFIER + help + The ummunotify (userspace MMU notification) driver creates a + character device that can be used by userspace libraries to + get notifications when an application's memory mapping + changed. This is used, for example, by RDMA libraries to + improve the reliability of memory registration caching, since + the kernel's MMU notifications can be used to know precisely + when to shoot down a cached registration. + source "drivers/s390/char/Kconfig" endmenu
drivers/char/Makefile +1 -0
@@ -97,6 +97,7 @@ obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o +obj-$(CONFIG_UMMUNOTIFY) += ummunotify.o obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/
drivers/char/ummunotify.c new file +567 -0
567 lines not on this page · raw message
include/linux/ummunotify.h new file +121 -0
121 lines not on this page · raw message
Signature · 6 lines
1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi!
Quoted 5 lines
I am resubmitting this patch because I believe that the discussion has shown this to be an acceptable solution. I have fixed the 32 bit build errors, but other than that change, the code is the same as Roland's V3 patch.
Quoted 8 lines
From: Roland Dreier <[email protected]>
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping viafree(),munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.
I do not know. I still believe that this does not belong in the kernel; application should not need to trace itself to know what it does.
Pavel
Signature · 6 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · On Mon, 12 Apr 2010 07:22:17 +0100 Eric B Munson <[email protected]> wrote:
Andrew,
I am resubmitting this patch because I believe that the discussion has shown this to be an acceptable solution.
To whom? Some acked-by's would clarify.
Quoted 4 lines
I have fixed the 32 bit
build errors, but other than that change, the code is the same as Roland's V3 patch.
Quoted 8 lines
From: Roland Dreier <[email protected]>
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping viafree(),munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.
But this info could be reassembled by tracking syscall activity, yes? Perhaps some discussion here explaining why the (possibly enhanced) ptrace, audit, etc interfaces are unsuitable.
Quoted 15 lines
We solve this not by implementing the full API proposed in the email linked above but rather with a simpler and more generic interface, which may be useful in other contexts. Specifically, we implement a new character device driver, ummunotify, that creates a
/dev/ummunotifynode. A userspace process can open this node read-only and use the fd as follows:1.
ioctl()to register/unregister an address range to watch in the kernel (cf structummunotify_register_ioctlin <linux/ummunotify.h>).2.
read()to retrieve events generated when a mapping in a watched address range is invalidated (cf structummunotify_eventin <linux/ummunotify.h>). select()/poll()/epoll() and SIGIO are handled for this IO.
Quoted 4 lines
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.
OK, what's missing from this whole description and from ummunotify.txt
is: how does one specify the target process? Does /dev/ummunotify implicitly attach to current->mm? If so, why, and what are the implications of this?
If instead it is possible to attach to some other process's mmu activity (/proc/<pid>/ummunotity?) then how is that done and what are the security/permissions implications?
Also, the whole thing is obviously racy: by the time userspace finds out that something has happened, it might have changed. This inevitably reduces the applicability/usefulness of the whole thing as compared to some synchronous mechanism which halts the monitored thread until the request has been processed and acked. All this should (IMO) be explored, explained and justified.
Also, what prevents the obvious DoS which occurs when I register for events and just let them queue up until the kernel runs out of memory? presumably events get dropped - what are the reliability implications of this and how is the max queue length managed?
Also, ioctls are unpopular. Were other intefaces considered?
Quoted 122 lines
Thanks to Jason Gunthorpe <jgunthorpe <at> obsidianresearch.com> for suggestions on the interface design. Also thanks to Jeff Squyres <jsquyres <at> cisco.com> for prototyping support for this in Open MPI, which helped find several bugs during development.
Signed-off-by Roland Dreier <[email protected]>Signed-off-by Eric B Munson <[email protected]>---
Changes since v3:
- Fixed replaced [get|put] user with copy_[from|to]_user to fix x86 builds--- Documentation/Makefile | 3 +- Documentation/ummunotify/Makefile | 7 + Documentation/ummunotify/ummunotify.txt | 150 ++++++++ Documentation/ummunotify/umn-test.c | 200 +++++++++++ drivers/char/Kconfig | 12 + drivers/char/Makefile | 1 + drivers/char/ummunotify.c | 567 +++++++++++++++++++++++++++++++ include/linux/ummunotify.h | 121 +++++++ 8 files changed, 1060 insertions(+), 1 deletions(-) create mode 100644 Documentation/ummunotify/Makefile create mode 100644 Documentation/ummunotify/ummunotify.txt create mode 100644 Documentation/ummunotify/umn-test.c create mode 100644 drivers/char/ummunotify.c create mode 100644 include/linux/ummunotify.hDocumentation/Makefile +2
-1@@ -1,3 +1,4 @@ obj-m := DocBook/ accounting/ auxdisplay/ connector/ \ filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \ - pcmcia/ spi/ timers/ video4linux/ vm/ watchdog/src/ + pcmcia/ spi/ timers/ video4linux/ vm/ ummunotify/ \ + watchdog/src/Documentation/ummunotify/Makefile new file +7
-0@@ -0,0 +1,7 @@ +# List of programs to build +hostprogs-y := umn-test + +# Tell kbuild to always build the programs +always := $(hostprogs-y) + +HOSTCFLAGS_umn-test.o += -I$(objtree)/usr/includeDocumentation/ummunotify/ummunotify.txt new file +64
-0@@ -0,0 +1,150 @@ +UMMUNOTIFY + + Ummunotify relays MMU notifier events to userspace. This is useful + for libraries that need to track the memory mapping of applications; + for example, MPI implementations using RDMA want to cache memory + registrations for performance, but tracking all possible crazy cases + such as when, say, the FORTRAN runtime frees memory is impossible + without kernel help. + +Basic Model + + A userspace process uses it by opening /dev/ummunotify, which + returns a file descriptor. Interest in address ranges is registered + using ioctl() and MMU notifier events are retrieved using read(), as + described in more detail below. Userspace can register multiple + address ranges to watch, and can unregister individual ranges. + + Userspace can also mmap() a single read-only page at offset 0 on + this file descriptor. This page contains (at offest 0) a single + 64-bit generation counter that the kernel increments each time an + MMU notifier event occurs. Userspace can use this to very quickly + check if there are any events to retrieve without needing to do a + system call. + +Control + + To start using ummunotify, a process opens /dev/ummunotify in + read-only mode. Control from userspace is done via ioctl(); the + defined ioctls are: + + UMMUNOTIFY_EXCHANGE_FEATURES: This ioctl takes a single 32-bit + word of feature flags as input, and the kernel updates the + features flags word to contain only features requested by + userspace and also supported by the kernel. + + This ioctl is only included for forward compatibility; no + feature flags are currently defined, and the kernel will simply + update any requested feature mask to 0. The kernel will always + default to a feature mask of 0 if this ioctl is not used, so + current userspace does not need to perform this ioctl. + + UMMUNOTIFY_REGISTER_REGION: Userspace uses this ioctl to tell the + kernel to start delivering events for an address range. The + range is described using struct ummunotify_register_ioctl: + + struct ummunotify_register_ioctl { + __u64 start; + __u64 end; + __u64 user_cookie; + __u32 flags; + __u32 reserved; + }; + + start and end give the range of userspace virtual addresses; + start is included in the range and end is not, so an example of + a 4 KB range would be start=0x1000, end=0x2000. + + user_cookie is an opaque 64-bit quantity that is returned by the + kernel in events involving the range, and used by userspace to + stop watching the range. Each registered address range must + have a distinct user_cookie. + + It is fine with the kernel if userspace registers multiple + overlapping or even duplicate address ranges, as long as a
Documentation/ummunotify/ummunotify.txt line 74
Quoted 10 lines
Documentation/ummunotify/ummunotify.txt new file +10
-0+ different cookie is used for each registration. + + flags and reserved are included for forward compatibility; + userspace should simply set them to 0 for the current interface. + + UMMUNOTIFY_UNREGISTER_REGION: Userspace passes in the 64-bit + user_cookie used to register a range to tell the kernel to stop + watching an address range. Once this ioctl completes, the + kernel will not deliver any further events for the range that is + unregistered.
What happens if I register two regions with the same cookie? Will UMMUNOTIFY_UNREGISTER_REGION unregister both, or did I cause a kernel leak?
If it's possible to register for events from a different process then how does the lifetime management happen? What happens when the target process exits?
What happens if I close() the fd when there are outstanding events?
What happens if I close() the fd when there are still-registered regions?
Documentation/ummunotify/ummunotify.txt line 84
Quoted 9 lines
Documentation/ummunotify/ummunotify.txt new file +9
-0+Events + + When an event occurs that invalidates some of a process's memory + mapping in an address range being watched, ummunotify queues an + event report for that address range. If more than one event + invalidates parts of the same address range before userspace + retrieves the queued report, then further reports for the same range + will not be queued -- when userspace does read the queue, only a + single report for a given range will be returned.
So the implementation keeps track of queued events down the operation/start-address/end-address level and, for each new event, checks whether that event is wholly contained within one of the preceding start-address/end-address ranges and if that queued event "invalidated" the new event's range, the new event is suppressed?
Sounds complex and expensive. Why was this added? Can't competent userspace handle this situation?
And what does "invalidate" mean? munmap?
Methinks this paragraph needs some fleshing out.
Documentation/ummunotify/ummunotify.txt line 95
Quoted 10 lines
Documentation/ummunotify/ummunotify.txt new file +10
-0+ If multiple ranges being watched are invalidated by a single event + (which is especially likely if userspace registers overlapping + ranges), then an event report structure will be queued for each + address range registration. + + Userspace retrieves queued events via read() on the ummunotify file + descriptor; a buffer that is at least as big as struct + ummunotify_event should be used to retrieve event reports, and if a + larger buffer is passed to read(), multiple reports will be returned + (if available).
What happens if I try to read() three bytes from that fd?
Documentation/ummunotify/ummunotify.txt line 94
Quoted 1 line
Documentation/ummunotify/ummunotify.txt new file +1
-0+ If the ummunotify file descriptor is in blocking mode,
Done how? Omitting O_NONBLOCK at open() time?
Documentation/ummunotify/ummunotify.txt line 96
Quoted 2 lines
Documentation/ummunotify/ummunotify.txt new file +2
-0+ a read() call + will wait for an event report to be available.
Under which circumstances will that read() terminate? signals, presumably?
Quoted 8 lines
Documentation/ummunotify/ummunotify.txt new file +8
-0+ Userspace may also + set the ummunotify file descriptor to non-blocking mode and use all + standard ways of waiting for data to be available on the ummunotify + file descriptor, including epoll/poll()/select() and SIGIO. + + The format of event reports is: + + struct ummunotify_event {
Documentation/ummunotify/ummunotify.txt
Quoted 10 lines
Documentation/ummunotify/ummunotify.txt new file +10
-0+ __u32 type; + __u32 flags; + __u64 hint_start; + __u64 hint_end; + __u64 user_cookie_counter; + }; + + where the type field is either UMMUNOTIFY_EVENT_TYPE_INVAL or + UMMUNOTIFY_EVENT_TYPE_LAST. Events of type INVAL describe + invalidation events as follows:
As follows where? Confused.
Documentation/ummunotify/ummunotify.txt line 117
Quoted 3 lines
Documentation/ummunotify/ummunotify.txt new file +3
-0+ user_cookie_counter contains the + cookie passed in when userspace registered the range that the event + is for.
Why does it have "_counter" in its name?
Documentation/ummunotify/ummunotify.txt
Quoted 7 lines
Documentation/ummunotify/ummunotify.txt new file +7
-0+ hint_start and hint_end contain the start address and end + address that were invalidated. + + The flags word contains bit flags, with only UMMUNOTIFY_EVENT_FLAG_HINT + defined at the moment. If HINT is set, then the invalidation event + invalidated less than the full address range and the kernel returns + the exact range invalidated;
So my registration now effectively covers a shorter address range? it may end up being very holey?
I wish you'd told us what "invalidate" means. If it means munmap() then presumably the monitored target can later start to fill those holes in again.
"hint" seems a strange name to use here. I don't understand why it is appropriate instead of, say, UMMUNOTIFY_EVENT_INVALIDATE.
Documentation/ummunotify/ummunotify.txt line 133
Quoted 11 lines
Documentation/ummunotify/ummunotify.txt new file +11
-0+ if HINT is not sent then hint_start and + hint_end are set to the original range registered by userspace. + (HINT will not be set if, for example, multiple events invalidated + disjoint parts of the range and so a single start/end pair cannot + represent the parts of the range that were invalidated) + + If the event type is LAST, then the read operation has emptied the + list of invalidated regions, and the flags, hint_start and hint_end + fields are not used. user_cookie_counter holds the value of the + kernel's generation counter (see below of more details) when the + empty list occurred.
Ah. So user_cookie_counter is a union. C has support for unions - why not use one??
Documentation/ummunotify/ummunotify.txt line 143
Quoted 9 lines
Documentation/ummunotify/ummunotify.txt new file +9
-0+Generation Count + + Userspace may mmap() a page on a ummunotify file descriptor via + + mmap(NULL, sizeof (__u64), PROT_READ, MAP_SHARED, ummunotify_fd, 0); + + to get a read-only mapping of the kernel's 64-bit generation + counter. The kernel will increment this generation counter each + time an event report is queued.
So we have one CPU writing a memory location and another CPU reading it without any locking?
What are the weird-architecture memory-barrier requirements here and how are they handled?
How does the code handle the non-atomicity of u64 writes on 32-bit CPUs?
Documentation/ummunotify/ummunotify.txt line 150
Quoted 6 lines
Documentation/ummunotify/ummunotify.txt new file +6
-0+ Userspace can use the generation counter as a quick check to avoid + system calls; if the value read from the mapped kernel counter is + still equal to the value returned in user_cookie_counter for the + most recent LAST event retrieved, then no further events have been + queued and there is no need to try a read() on the ummunotify file + descriptor.
I _guess_ that works OK on 32-bit, as long as userspace _only_ compares this value with some previous one.
umm, no, there's still a race I think. If the counter increases from 0x00000000ffffffff to 0x0000000100000000 then userspace could see this as two events when using this scheme.
I didn't get around to reading the code yet ;)
Quoted 10 lines · Andrew Morton
Quoted 6 lines
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping viafree(),munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.But this info could be reassembled by tracking syscall activity, yes? Perhaps some discussion here explaining why the (possibly enhanced) ptrace, audit, etc interfaces are unsuitable.
Just to summarize some of the key points of this thingy, as related to your comments:
1) It is really very narrowly focused on a particular problem MPI and RDMA have due to the way their APIs don't really match. Roland tried to make the interface general.. Maybe that is a mistake ..
2) A 'self-tracing' scheme is used, again, because of an API mistmatching between a MPI library and it's own applications. Attempting to hook the appropriate calls has proven unsatisfactory (missing cases, and slow).
3) Being intended for MPI applications, performance is a huge concern. Synchronous operation is very undesirable. Tracing APIs are lossy - and there is no recovery option if an event is lost.
4) Realistically the only thing MPI cares about is if a virtual page is unmapped/remapped. Loosing events is unacceptable.
5) This isn't really tracing. There is no queue. There aren't really events. This works more like the diry/access bit in a page table, it doesn't matter how many times something has been modified, only that it has at least once since last time you looked.
This means the memory used is proportional to the number of page-ranges you watch, and the number of events against those page-ranges doesn't matter. No other API has this property.
Basically, this entire scheme is designed to detect that when a == b, the internal state held by some_mpi_call is no longer valid, in this kind of situation:
a = mmap(ONE_PAGE);
some_mpi_call(a);
munmap(a);
b = mmap(ONE_PAGE); // Kernel picks b == a
some_mpi_call(b);
All the races you point out, just don't matter for the MPI use case. Essentially, if the app hits those races, then it is using the MPI library in a buggy way.
That said, this could be explained better in the documentation file. :)
I'm sure Eric can go through the rest of your questions in greater detail..
Quoted 7 lines
Documentation/ummunotify/ummunotify.txt line 150
Quoted 6 lines
Documentation/ummunotify/ummunotify.txt new file +6
-0+ Userspace can use the generation counter as a quick check to avoid + system calls; if the value read from the mapped kernel counter is + still equal to the value returned in user_cookie_counter for the + most recent LAST event retrieved, then no further events have been + queued and there is no need to try a read() on the ummunotify file + descriptor.
Quoted 6 lines
I _guess_ that works OK on 32-bit, as long as userspace _only_ compares this value with some previous one.
umm, no, there's still a race I think. If the counter increases from
0x00000000ffffffffto0x0000000100000000then userspace could see this as two events when using this scheme.
The only case that matters for the generation counter optimization is a false negative. As long as user space does:
u64 val = *counter;
if (val != last_counter)
last_counter = val;
Then you can get false positives as you point out, but never a false negative. A false positive results in an extra syscall and the kernel just returns no data.
Regards,
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 8 lines · Jason Gunthorpe
Quoted 6 lines · Andrew Morton
Quoted 6 lines
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping viafree(),munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.
I am not sure I agree with the premises here. ptMalloc and malloc hooks are not related to the issue in my opinion. User space library calls do not change virtual to physical mapping, system calls do. The following sys calls might change virtual to physical mapping: munmap(), mremap(), sbrk(), madvice(). What we need is glibc to provide hooks for these 4 sys calls and the general syscall() when its argument is one of the four mentioned syscalls. To me, that is what is needed, and the ummunotify direction seems way too complicated to me.
It is further claimed that "… other tricks are not robust". I wrote the code used in Scali/Platform MPI handling the issue. I do not think its fair to claim that this MPI is not robust in this matter nor that is performance is bad.
Thanks, Håkon
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 9 lines
I am not sure I agree with the premises here. ptMalloc and malloc hooks are not related to the issue in my opinion. User space library calls do not change virtual to physical mapping, system calls do. The following sys calls might change virtual to physical mapping:
munmap(),mremap(),sbrk(),madvice(). What we need is glibc to provide hooks for these 4 sys calls and the generalsyscall()when its argument is one of the four mentioned syscalls. To me, that is what is needed, and the ummunotify direction seems way too complicated to me.
Are those system calls the only possible way that virtual to physical mappings can change? Can't page migration or something like that potentially affect things? And even if you did have hooks into every system call that mattered (keep in mind that relying on glibc is not enough, since an MPI application may not use glibc) would decoding them and figuring out what happened really be preferable to a single event type that tells you exactly what address range was affected?
Quoted 4 lines
It is further claimed that "… other tricks are not robust". I wrote the code used in Scali/Platform MPI handling the issue. I do not think its fair to claim that this MPI is not robust in this matter nor that is performance is bad.
The Open MPI developers have spent a lot of effort trying to handle this purely in userspace and still do not believe that a truly robust solution is possible without kernel help. Perhaps they can expand on what the obstacles are.
- R.
Signature · 6 lines
Roland Dreier <[email protected]> || For corporate legal information go to: http://www.cisco.com/web/about/doing_business/legal/cri/index.html -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 7 lines · Roland Dreier
Are those system calls the only possible way that virtual to physical mappings can change? Can't page migration or something like that potentially affect things? And even if you did have hooks into every system call that mattered (keep in mind that relying on glibc is not enough, since an MPI application may not use glibc) would decoding them and figuring out what happened really be preferable to a single event type that tells you exactly what address range was affected?
Yeah, virtual<->physical maps can change through swapping, page migration, memory compaction, huge-page aggregation (the latter two not yet being upstream).
Even mlock() doesn't pin virtual<->physical maps.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · Peter Zijlstra
Yeah, virtual<->physical maps can change through swapping, page migration, memory compaction, huge-page aggregation (the latter two not yet being upstream).
Assuming this holds true, RDMA will not work. And with no RDMA, we do not need ummunotify. Is that your argument?
Seriously, RDMA requires the virtual to physical mapping to remain constant for a period of time. And that time period is from memory registration to de-registration. If the virtual to physical mapping changes in that period for the registered memory area, I can't see how an HCA can handle that.
For MPI applications, the MPI API defines that the buffers used in communication cannot be changed or freed while a non-blocking transfer is in progress. So far, we are good. But memory registration (and in particular de-registration) is a costly process. Since MPI is about performance, the MPI library would like to re-use earlier memory registrations for other transfers. The MPI library records earlier memory mappings (VA+bound) and checks if the VA+bound of a new transfer is already contained in memory revisions registered earlier.
The problem with this approach is that _normal_ activity _between_ the transfers changes the virtual to physical mapping and ruins previous memory registrations. The problem is to catch these. I simply argue that they should be caught the simplest possible way; a call-back from the system calls affecting the virtual to physical mapping.
Quoted 2 lines
Even
mlock()doesn't pin virtual<->physical maps.
Can you elaborate on what you mean here?
Thanks, Håkon
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 9 lines · Peter Zijlstra
Quoted 7 lines · Roland Dreier
Are those system calls the only possible way that virtual to physical mappings can change? Can't page migration or something like that potentially affect things? And even if you did have hooks into every system call that mattered (keep in mind that relying on glibc is not enough, since an MPI application may not use glibc) would decoding them and figuring out what happened really be preferable to a single event type that tells you exactly what address range was affected?
Quoted 5 lines
Yeah, virtual<->physical maps can change through swapping, page migration, memory compaction, huge-page aggregation (the latter two not yet being upstream).
Even
mlock()doesn't pin virtual<->physical maps.
Pages registered for RDMA are GUPed so no method above should touch them. Fork+cow or unmap/map on the other hand can change virtual<->physical maps. GUPed pages are still GUPed, but they are no longer mapped into process' virtual address space. MPI copes with Fork+cow by marking registered memory as MADV_DONTFORK.
--
Gleb.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 14 lines · Gleb Natapov
Quoted 13 lines · Peter Zijlstra
Quoted 7 lines · Roland Dreier
Are those system calls the only possible way that virtual to physical mappings can change? Can't page migration or something like that potentially affect things? And even if you did have hooks into every system call that mattered (keep in mind that relying on glibc is not enough, since an MPI application may not use glibc) would decoding them and figuring out what happened really be preferable to a single event type that tells you exactly what address range was affected?
Yeah, virtual<->physical maps can change through swapping, page migration, memory compaction, huge-page aggregation (the latter two not yet being upstream).
Quoted 6 lines
Quoted 1 line
Even
mlock()doesn't pin virtual<->physical maps.Pages registered for RDMA are GUPed so no method above should touch them. Fork+cow or unmap/map on the other hand can change virtual<->physical maps. GUPed pages are still GUPed, but they are no longer mapped into process' virtual address space. MPI copes with Fork+cow by marking registered memory as
MADV_DONTFORK.
Sure, holding a page-ref will pin the physical page, but that is not something userspace usually has means to.
Quoted 10 lines · Roland Dreier
Quoted 4 lines
It is further claimed that "… other tricks are not robust". I wrote the code used in Scali/Platform MPI handling the issue. I do not think its fair to claim that this MPI is not robust in this matter nor that is performance is bad.
The Open MPI developers have spent a lot of effort trying to handle this purely in userspace and still do not believe that a truly robust solution is possible without kernel help. Perhaps they can expand on what the obstacles are.
The problem is that glibc doesn't provide correct type of hooks for MPI to use. You can hook into free(), but the hook is called when application frees memory, not when memory is returned back to the kernel and since MPI wants to cache registration across free()/malloc() if possible those hooks are not good enough. To overcome this MPI tries to provide its own memory management library (luckily glibc defines most/all memory management functions as weak) with proper hooks present, but that poses a whole lot of other problems and memory management is really not MPI's job. Even if glibc will provide proper hooks some day HPC users may want to use other, more performance oriented, memory management libraries instead of using build in glibc one. Relying on glibc hooks will prevent them from doing so.
--
Gleb.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · Gleb Natapov
Quoted 4 lines
The Open MPI developers have spent a lot of effort trying to handle this purely in userspace and still do not believe that a truly robust solution is possible without kernel help. Perhaps they can expand on what the obstacles are.
By "truly robust" we mean that some other user-level code can't override the hooks installed by the MPI (user level) middleware. All current glibc hooks are overridable by other user-level code -- and sometimes real applications do this (for their own good reasons). Most of the time, apps blithely override our hooks because they either don't know or can't know that our hooks are installed. It can be dicey to know what you can and cannot override pre-main(), for example (e.g., via the __malloc_initialize_hook).
Opening up a direct channel to the kernel and saying "hey, tell me when something changes" is robust because no other entity can hijack your notifications. It also allows us to avoid using pre-main hooks, and makes it so that we don't have to hook into the memory subsystem (usually replacing it with our own). Both of these things are extremely distasteful -- fixing these two things alone make doing something like ummunotify worthwhile, IMHO.
Signature · 9 lines
Jeff Squyres [email protected] For corporate legal information go to: http://www.cisco.com/web/about/doing_business/legal/cri/ -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 63 lines · Andrew Morton
Quoted 4 lines · On Mon, 12 Apr 2010 07:22:17 +0100 Eric B Munson…
Andrew,
I am resubmitting this patch because I believe that the discussion has shown this to be an acceptable solution.
To whom? Some acked-by's would clarify.
Quoted 4 lines
I have fixed the 32 bit
build errors, but other than that change, the code is the same as Roland's V3 patch.Quoted 8 lines
From: Roland Dreier <[email protected]>
As discussed in <http://article.gmane.org/gmane.linux.drivers.openib/61925>
and follow-up messages, libraries using RDMA would like to track precisely when application code changes memory mapping viafree(),munmap(), etc. Current pure-userspace solutions using malloc hooks and other tricks are not robust, and the feeling among experts is that the issue is unfixable without kernel help.But this info could be reassembled by tracking syscall activity, yes? Perhaps some discussion here explaining why the (possibly enhanced) ptrace, audit, etc interfaces are unsuitable.
Quoted 15 lines
We solve this not by implementing the full API proposed in the email linked above but rather with a simpler and more generic interface, which may be useful in other contexts. Specifically, we implement a new character device driver, ummunotify, that creates a
/dev/ummunotifynode. A userspace process can open this node read-only and use the fd as follows:1.
ioctl()to register/unregister an address range to watch in the kernel (cf structummunotify_register_ioctlin <linux/ummunotify.h>).2.
read()to retrieve events generated when a mapping in a watched address range is invalidated (cf structummunotify_eventin <linux/ummunotify.h>). select()/poll()/epoll() and SIGIO are handled for this IO.Quoted 4 lines
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.OK, what's missing from this whole description and from ummunotify.txt
is: how does one specify the target process? Does/dev/ummunotifyimplicitly attach tocurrent->mm? If so, why, and what are the implications of this?If instead it is possible to attach to some other process's mmu activity (/proc/<pid>/ummunotity?) then how is that done and what are the
security/permissionsimplications?Also, the whole thing is obviously racy: by the time userspace finds out that something has happened, it might have changed. This inevitably reduces the applicability/usefulness of the whole thing as compared to some synchronous mechanism which halts the monitored thread until the request has been processed and acked. All this should (IMO) be explored, explained and justified.
Quoted 7 lines
Also, what prevents the obvious DoS which occurs when I register for events and just let them queue up until the kernel runs out of memory? presumably events get dropped - what are the reliability implications of this and how is the max queue length managed?
Also, ioctls are unpopular. Were other intefaces considered?
I am reworking the Documentation to address all these questions and will resubmit when finished.
Thanks for the feedback,
Eric
PATCH 1/1 ummunotify: fix umn-test build
In reply to Eric B MunsonFrom: Randy Dunlap <[email protected]>
Add ummunotify.h to Kbuild list for export to userspace, fixing 27 build errors in umn-test.c when O=builddir is used.
--- include/linux/Kbuild | 1 + 1 file changed, 1 insertion(+)
maybe another item to add to SubmitChecklist :(
include/linux/Kbuild +1 -0
@@ -163,6 +163,7 @@ header-y += tipc_config.h header-y += toshiba.h header-y += udf_fs_i.h header-y += ultrasound.h +header-y += ummunotify.h header-y += un.h header-y += utime.h header-y += veth.h
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ummunotify: fix umn-test build
Quoted 6 lines · Randy Dunlap
From: Randy Dunlap <[email protected]>
Add
ummunotify.htoKbuildlist for export to userspace, fixing 27 build errors inumn-test.cwhen O=builddir is used.Signed-off-by Randy Dunlap <[email protected]>
Thanks, will wrap this into V2.
Eric
Re: [PATCH] ummunotify: fix umn-test build
Eric, sorry for not seeing this earlier, but it looks like the last patch I emailed out did not include all the tiny changes I made prior to asking Linus to pull this (which he ended up not doing). For example this fix to the include Kbuild file was there.
You could look at:
http://git.kernel.org/?p=linux/kernel/git/roland/infiniband.git;a=commit;h=cfe60a43c3434907a47323fb82d2960e915a9538
to see what was actually in my pull request. There may be other trivial tweaks worth including.
Thanks for resurrecting this work BTW.
- R.
Signature · 6 lines
Roland Dreier <[email protected]> || For corporate legal information go to: http://www.cisco.com/web/about/doing_business/legal/cri/index.html -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html