* [PATCHv2 1/1] Documentation: describe how to add a system call
From: David Drysdale @ 2015-07-30 7:52 UTC (permalink / raw)
To: linux-api, Michael Kerrisk, Andrew Morton, Arnd Bergmann,
Shuah Khan, Jonathan Corbet, Eric B Munson, Randy Dunlap
Cc: Andrea Arcangeli, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Oleg Nesterov, Linus Torvalds, Greg Kroah-Hartman,
Andy Lutomirski, Al Viro, Rusty Russell, Peter Zijlstra,
Vivek Goyal, Alexei Starovoitov, David Herrmann,
Theodore Ts'o, Kees Cook, Miklos Szeredi, Milosz Tanski,
Fam Zheng, Josh Triplett, Mathieu Desnoyers, linux-doc,
linux-kernel, David Drysdale
In-Reply-To: <1438242731-27756-1-git-send-email-drysdale@google.com>
Add a document describing the process of adding a new system call,
including the need for a flags argument for future compatibility, and
covering 32-bit/64-bit concerns (albeit in an x86-centric way).
Signed-off-by: David Drysdale <drysdale@google.com>
Reviewed-by: Michael Kerrisk <mtk.manpages@gmail.com>
Reviewed-by: Eric B Munson <emunson@akamai.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
---
Documentation/adding-syscalls.txt | 463 ++++++++++++++++++++++++++++++++++++++
1 file changed, 463 insertions(+)
create mode 100644 Documentation/adding-syscalls.txt
diff --git a/Documentation/adding-syscalls.txt b/Documentation/adding-syscalls.txt
new file mode 100644
index 000000000000..f5fc26f6dc97
--- /dev/null
+++ b/Documentation/adding-syscalls.txt
@@ -0,0 +1,463 @@
+Adding a New System Call
+========================
+
+This document describes what's involved in adding a new system call to the
+Linux kernel, over and above the normal submission advice in
+Documentation/SubmittingPatches.
+
+
+System Call Alternatives
+------------------------
+
+The first thing to consider when adding a new system call is whether one of
+the alternatives might be suitable instead. Although system calls are the
+most traditional and most obvious interaction points between userspace and the
+kernel, there are other possibilities -- choose what fits best for your
+interface.
+
+ - If the operations involved can be made to look like a filesystem-like
+ object, it may make more sense to create a new filesystem or device. This
+ also makes it easier to encapsulate the new functionality in a kernel module
+ rather than requiring it to be built into the main kernel.
+ - If the new functionality involves operations where the kernel notifies
+ userspace that something has happened, then returning a new file
+ descriptor for the relevant object allows userspace to use
+ poll/select/epoll to receive that notification.
+ - However, operations that don't map to read(2)/write(2)-like operations
+ have to be implemented as ioctl(2) requests, which can lead to a
+ somewhat opaque API.
+ - If you're just exposing runtime system information, a new node in sysfs
+ (see Documentation/filesystems/sysfs.txt) or the /proc filesystem may be
+ more appropriate. However, access to these mechanisms requires that the
+ relevant filesystem is mounted, which might not always be the case (e.g.
+ in a namespaced/sandboxed/chrooted environment). Avoid adding anything to
+ debugfs, as this is not considered a 'production' interface to userspace.
+ - If the operation is specific to a particular file or file descriptor, then
+ an additional fcntl(2) command option may be more appropriate. However,
+ fcntl(2) is a multiplexing system call that hides a lot of complexity, so
+ this option is best for when the new function is closely analogous to
+ existing fcntl(2) functionality, or the new functionality is very simple
+ (for example, getting/setting a simple flag related to a file descriptor).
+ - If the operation is specific to a particular task or process, then an
+ additional prctl(2) command option may be more appropriate. As with
+ fcntl(2), this system call is a complicated multiplexor so is best reserved
+ for near-analogs of existing prctl() commands or getting/setting a simple
+ flag related to a process.
+
+
+Designing the API
+-----------------
+
+A new system call forms part of the API of the kernel, and has to be supported
+indefinitely. As such, it's a very good idea to explicitly discuss the
+interface on the kernel mailing list, and to plan for future extensions of the
+interface. In particular:
+
+ **Include a flags argument for every new system call**
+
+The syscall table is littered with historical examples where this wasn't done,
+together with the corresponding follow-up system calls (eventfd/eventfd2,
+dup2/dup3, inotify_init/inotify_init1, pipe/pipe2, renameat/renameat2), so
+learn from the history of the kernel and include a flags argument from the
+start.
+
+Also, to make sure that userspace programs can safely use flags between kernel
+versions, check whether the flags value holds any unknown flags, and reject the
+sycall (with EINVAL) if it does:
+
+ if (flags & ~(THING_FLAG1 | THING_FLAG2 | THING_FLAG3))
+ return -EINVAL;
+
+(If no flags values are used yet, check that the flags argument is zero.)
+
+If your new xyzzy(2) system call returns a new file descriptor, then the flags
+argument should include a value that is equivalent to setting O_CLOEXEC on the
+new FD. This makes it possible for userspace to close the timing window
+between xyzzy() and calling fcntl(fd, F_SETFD, FD_CLOEXEC), where an
+unexpected fork() and execve() in another thread could leak a descriptor to
+the exec'ed program. (However, resist the temptation to re-use the actual value
+of the O_CLOEXEC constant, as it is architecture-specific and is part of a
+numbering space of O_* flags that is fairly full.)
+
+If your new xyzzy(2) system call involves a filename argument:
+
+ int sys_xyzzy(const char __user *path, ..., unsigned int flags);
+
+you should also consider whether an xyzzyat(2) version is more appropriate:
+
+ int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags);
+
+This allows more flexibility for how userspace specifies the file in question;
+in particular it allows userspace to request the functionality for an
+already-opened file descriptor using the AT_EMPTY_PATH flag, effectively giving
+an fxyzzy(3) operation for free:
+
+ - xyzzyat(AT_FDCWD, path, ..., 0) is equivalent to xyzzy(path,...)
+ - xyzzyat(fd, "", ..., AT_EMPTY_PATH) is equivalent to fxyzzy(fd, ...)
+
+(For more details on the rationale of the *at() calls, see the openat(2) man
+page; for an example of AT_EMPTY_PATH, see the statat(2) man page.)
+
+If your new xyzzy(2) system call involves a parameter describing an offset
+within a file, make its type loff_t so that 64-bit offsets can be supported
+even on 32-bit architectures.
+
+If your new xyzzy(2) system call involves administrative functionality, it
+needs to be governed by the appropriate Linux capability bit (checked with a
+call to capable()), as described in the capabilities(7) man page.
+
+ - If there is an existing capability that governs related functionality, then
+ use that. However, avoid combining lots of only vaguely related functions
+ together under the same bit, as this goes against capabilities' purpose of
+ splitting the power of root. In particular, avoid adding new uses of the
+ already overly-general CAP_SYS_ADMIN capability.
+ - If there is no related capability, then consider adding a new capability
+ bit -- but bear in mind that the numbering space is limited, and each new
+ bit needs to be understood and administered by sysadmins.
+
+Finally, be aware that some non-x86 architectures have an easier time if
+system call parameters that are explicitly 64-bit fall on odd-numbered
+arguments (i.e. parameter 1, 3, 5), to allow use of contiguous pairs of 32-bit
+registers.
+
+
+Proposing the API
+-----------------
+
+To make new system calls easy to review, it's best to divide up the patchset
+into separate chunks. These should include at least the following items as
+distinct commits (each of which is described further below):
+
+ - The core implementation of the system call together with prototypes, generic
+ numbering and fallback stub implementation.
+ - Wiring up of the new system call for one particular architecture, usually
+ x86 (including all of x86_64, x86_32 and x32).
+ - A demonstration of the use of the new system call in userspace via a
+ selftest in tools/testing/selftests/.
+ - A draft man-page for the new system call.
+
+New system call proposals, like any change to the kernel's API, should always
+be cc'ed to linux-api@vger.kernel.org
+
+
+Generic System Call Implementation
+----------------------------------
+
+The main entry point for your new xyzzy(2) system call will be called
+sys_xyzzy(), but you add this entry point with the appropriate
+SYSCALL_DEFINEn() macro rather than explicitly. The 'n' indicates the number
+of arguments to the system call, and the macro takes the system call name
+followed by the (type, name) pairs for the parameters as arguments. Using
+this macro allows metadata about the new system call to be made available for
+other tools.
+
+The new entry point also needs a corresponding function prototype, in
+include/linux/syscalls.h, marked as asmlinkage to match the way that system
+calls are invoked:
+
+ asmlinkage long sys_xyzzy(...);
+
+Some architectures (e.g. x86) have their own architecture-specific syscall
+tables, but several other architectures share a generic syscall table. Add your
+new system call to the generic list by adding an entry to the list in
+include/uapi/asm-generic/unistd.h:
+
+ #define __NR_xyzzy 292
+ __SYSCALL(__NR_xyzzy, sys_xyzzy)
+
+Also update the __NR_syscalls count to reflect the additional system call, and
+note that if multiple new system calls are added in the same merge window,
+your new syscall number may get adjusted to resolve conflicts.
+
+The file kernel/sys_ni.c provides a fallback stub implementation of each system
+call, returning -ENOSYS. Add your new system call here too:
+
+ cond_syscall(sys_xyzzy);
+
+To summarize, you need a commit that includes:
+
+ - SYSCALL_DEFINEn(xyzzy, ...) for the entry point
+ - corresponding prototype in include/linux/syscalls.h
+ - generic table entry in include/uapi/asm-generic/unistd.h
+ - fallback stub in kernel/sys_ni.c
+
+
+x86 System Call Implementation
+------------------------------
+
+To wire up your new system call for x86 platforms, you need to update the
+master syscall tables. Assuming your new system call isn't special in some
+way (see below), this involves a "common" entry (for x86_64 and x32) in
+arch/x86/entry/syscalls/syscall_64.tbl:
+
+ 333 common xyzzy sys_xyzzy
+
+and an "i386" entry in arch/x86/entry/syscalls/syscall_32.tbl:
+
+ 380 i386 xyzzy sys_xyzzy
+
+Again, these numbers are liable to be changed if there are conflicts in the
+relevant merge window.
+
+
+Compatibility System Calls (Generic)
+------------------------------------
+
+For most system calls the same 64-bit implementation can be invoked even when
+the userspace program is itself 32-bit; even if the system call's parameters
+include an explicit pointer, this is handled transparently.
+
+However, there are a couple of situations where a compatibility layer is
+needed to cope with size differences between 32-bit and 64-bit.
+
+The first is if the 64-bit kernel also supports 32-bit userspace programs, and
+so needs to parse areas of (__user) memory that could hold either 32-bit or
+64-bit values. In particular, this is needed whenever a system call argument
+is:
+
+ - a pointer to a pointer
+ - a pointer to a struct containing a pointer (e.g. struct iovec __user *)
+ - a pointer to a varying sized integral type (time_t, off_t, long, ...)
+ - a pointer to a struct containing a varying sized integral type.
+
+The second situation that requires a compatibility layer is if one of the
+system call's arguments has a type that is explicitly 64-bit even on a 32-bit
+architecture, for example loff_t or __u64. In this case, a value that arrives
+at a 64-bit kernel from a 32-bit application will be split into two 32-bit
+values, which then need to be re-assembled in the compatibility layer.
+
+(Note that a system call argument that's a pointer to an explicit 64-bit type
+does *not* need a compatibility layer; for example, splice(2)'s arguments of
+type loff_t __user * do not trigger the need for a compat_ system call.)
+
+The compatibility version of the system call is called compat_sys_xyzzy(), and
+is added with the COMPAT_SYSCALL_DEFINEn() macro, analogously to
+SYSCALL_DEFINEn. This version of the implementation runs as part of a 64-bit
+kernel, but expects to receive 32-bit parameter values and does whatever is
+needed to deal with them. (Typically, the compat_sys_ version converts the
+values to 64-bit versions and either calls on to the sys_ version, or both of
+them call a common inner implementation function.)
+
+The compat entry point also needs a corresponding function prototype, in
+include/linux/compat.h, marked as asmlinkage to match the way that system
+calls are invoked:
+
+ asmlinkage long compat_sys_xyzzy(...);
+
+If the system call involves a structure that is laid out differently on 32-bit
+and 64-bit systems, say struct xyzzy_args, then the include/linux/compat.h
+header file should also include a compat version of the structure (struct
+compat_xyzzy_args) where each variable-size field has the appropriate compat_
+type that corresponds to the type in struct xyzzy_args. The
+compat_sys_xyzzy() routine can then use this compat_ structure to parse the
+arguments from a 32-bit invocation.
+
+For example, if there are fields:
+
+ struct xyzzy_args {
+ const char __user *ptr;
+ __kernel_long_t varying_val;
+ u64 fixed_val;
+ /* ... */
+ };
+
+in struct xyzzy_args, then struct compat_xyzzy_args would have:
+
+ struct compat_xyzzy_args {
+ compat_uptr_t ptr;
+ compat_long_t varying_val;
+ u64 fixed_val;
+ /* ... */
+ };
+
+The generic system call list also needs adjusting to allow for the compat
+version; the entry in include/uapi/asm-generic/unistd.h should use
+__SC_COMP rather than __SYSCALL:
+
+ #define __NR_xyzzy 292
+ __SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy)
+
+To summarize, you need:
+
+ - a COMPAT_SYSCALL_DEFINEn(xyzzy, ...) for the compat entry point
+ - corresponding prototype in include/linux/compat.h
+ - (if needed) 32-bit mapping struct in include/linux/compat.h
+ - instance of __SC_COMP not __SYSCALL in include/uapi/asm-generic/unistd.h
+
+
+Compatibility System Calls (x86)
+--------------------------------
+
+To wire up the x86 architecture of a system call with a compatibility version,
+the entries in the syscall tables need to be adjusted.
+
+First, the entry in arch/x86/entry/syscalls/syscall_32.tbl gets an extra
+column to indicate that a 32-bit userspace program running on a 64-bit kernel
+should hit the compat entry point:
+
+ 380 i386 xyzzy sys_xyzzy compat_sys_xyzzy
+
+Second, you need to figure out what should happen for the x32 ABI version of
+the new system call. There's a choice here: the layout of the arguments
+should either match the 64-bit version or the 32-bit version.
+
+If there's a pointer-to-a-pointer involved, the decision is easy: x32 is
+ILP32, so the layout should match the 32-bit version, and the entry in
+arch/x86/entry/syscalls/syscall_64.tbl is split so that x32 programs hit the
+compatibility wrapper:
+
+ 333 64 xyzzy sys_xyzzy
+ ...
+ 555 x32 xyzzy compat_sys_xyzzy
+
+If no pointers are involved, then it is preferable to re-use the 64-bit system
+call for the x32 ABI (and consequently the entry in
+arch/x86/entry/syscalls/syscall_64.tbl is unchanged).
+
+In either case, you should check that the types involved in your argument
+layout do indeed map exactly from x32 (-mx32) to either the 32-bit (-m32) or
+64-bit (-m64) equivalents.
+
+
+System Calls Returning Elsewhere
+--------------------------------
+
+For most system calls, once the system call is complete the user program
+continues exactly where it left off -- at the next instruction, with the same
+stack and registers as before the system call, and with the same virtual
+memory space.
+
+However, a few system calls do things differently. They might return to a
+different location (rt_sigreturn) or change the memory space (fork/vfork/clone)
+or even architecture (execve/execveat) of the program.
+
+To allow for this, the kernel implementation of the system call may need to
+save and restore additional registers to the kernel stack, allowing complete
+control of where and how execution continues after the system call.
+
+This is arch-specific, but typically involves defining assembly entry points
+that save/restore additional registers and invoke the real system call entry
+point.
+
+For x86_64, this is implemented as a stub_xyzzy entry point in
+arch/x86/entry/entry_64.S, and the entry in the syscall table
+(arch/x86/entry/syscalls/syscall_64.tbl) is adjusted to match:
+
+ 333 common xyzzy stub_xyzzy
+
+The equivalent for 32-bit programs running on a 64-bit kernel is normally
+called stub32_xyzzy and implemented in arch/x86/entry/entry_64_compat.S,
+with the corresponding syscall table adjustment in
+arch/x86/entry/syscalls/syscall_32.tbl:
+
+ 380 i386 xyzzy sys_xyzzy stub32_xyzzy
+
+If the system call needs a compatibility layer (as in the previous section)
+then the stub32_ version needs to call on to the compat_sys_ version of the
+system call rather than the native 64-bit version. Also, if the x32 ABI
+implementation is not common with the x86_64 version, then its syscall
+table will also need to invoke a stub that calls on to the compat_sys_
+version.
+
+For completeness, it's also nice to set up a mapping so that user-mode Linux
+still works -- its syscall table will reference stub_xyzzy, but the UML build
+doesn't include arch/x86/entry/entry_64.S implementation (because UML
+simulates registers etc). Fixing this is as simple as adding a #define to
+arch/x86/um/sys_call_table_64.c:
+
+ #define stub_xyzzy sys_xyzzy
+
+
+Other Details
+-------------
+
+Most of the kernel treats system calls in a generic way, but there is the
+occasional exception that may need updating for your particular system call.
+
+The audit subsystem is one such special case; it includes (arch-specific)
+functions that classify some special types of system call -- specifically
+file open (open/openat), program execution (execve/exeveat) or socket
+multiplexor (socketcall) operations. If your new system call is analogous to
+one of these, then the audit system should be updated.
+
+More generally, if there is an existing system call that is analogous to your
+new system call, it's worth doing a kernel-wide grep for the existing system
+call to check there are no other special cases.
+
+
+Testing
+-------
+
+A new system call should obviously be tested; it is also useful to provide
+reviewers with a demonstration of how user space programs will use the system
+call. A good way to combine these aims is to include a simple self-test
+program in a new directory under tools/testing/selftests/.
+
+For a new system call, there will obviously be no libc wrapper function and so
+the test will need to invoke it using syscall(); also, if the system call
+involves a new userspace-visible structure, the corresponding header will need
+to be installed to compile the test.
+
+Make sure the selftest runs successfully on all supported architectures. For
+example, check that it works when compiled as an x86_64 (-m64), x86_32 (-m32)
+and x32 (-mx32) ABI program.
+
+
+Man Page
+--------
+
+All new system calls should come with a complete man page, ideally using groff
+markup, but plain text will do. If groff is used, it's helpful to include a
+pre-rendered ASCII version of the man page in the cover email for the
+patchset, for the convenience of reviewers.
+
+The man page should be cc'ed to linux-man@vger.kernel.org
+For more details, see https://www.kernel.org/doc/man-pages/patches.html
+
+References and Sources
+----------------------
+
+ - LWN article from Michael Kerrisk on use of flags argument in system calls:
+ https://lwn.net/Articles/585415/
+ - LWN article from Michael Kerrisk on how to handle unknown flags in a system
+ call: https://lwn.net/Articles/588444/
+ - LWN article from Jake Edge describing constraints on 64-bit system call
+ arguments: https://lwn.net/Articles/311630/
+ - Pair of LWN articles from David Drysdale that describe the system call
+ implementation paths in detail for v3.14:
+ - https://lwn.net/Articles/604287/
+ - https://lwn.net/Articles/604515/
+ - Architecture-specific requirements for system calls are discussed in the
+ syscall(2) man-page:
+ http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES
+ - Collated emails from Linus Torvalds discussing the problems with ioctl():
+ http://yarchive.net/comp/linux/ioctl.html
+ - "How to not invent kernel interfaces", Arnd Bergmann,
+ http://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf
+ - LWN article from Michael Kerrisk on avoiding new uses of CAP_SYS_ADMIN:
+ https://lwn.net/Articles/486306/
+
+ - Recommendation from Andrew Morton that all related information for a new
+ system call should come in the same email thread:
+ https://lkml.org/lkml/2014/7/24/641
+ - Recommendation from Michael Kerrisk that a new system call should come with
+ a man page: https://lkml.org/lkml/2014/6/13/309
+ - Suggestion from Thomas Gleixner that x86 wire-up should be in a separate
+ commit: https://lkml.org/lkml/2014/11/19/254
+ - Suggestion from Greg Kroah-Hartman that it's good for new system calls to
+ come with a man-page & selftest: https://lkml.org/lkml/2014/3/19/710
+ - Discussion from Michael Kerrisk of new system call vs. prctl(2) extension:
+ https://lkml.org/lkml/2014/6/3/411
+ - Numbering oddities arising from (re-)use of O_* numbering space flags:
+ - commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness
+ check")
+ - commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc
+ conflict")
+ - commit bb458c644a59 ("Safer ABI for O_TMPFILE")
+ - Discussion from Matthew Wilcox about restrictions on 64-bit arguments:
+ https://lkml.org/lkml/2008/12/12/187
+ - Recommendation from Greg Kroah-Hartman that unknown flags should be
+ policed: https://lkml.org/lkml/2014/7/17/577
+ - Recommendation from Linus Torvalds that x32 system calls should prefer
+ compatibility with 64-bit versions rather than 32-bit versions:
+ https://lkml.org/lkml/2011/8/31/244
--
2.5.0.rc2.392.g76e840b
^ permalink raw reply related
* Re: [PATCH v7 4/6] block: loop: prepare for supporing direct IO
From: Ming Lei @ 2015-07-30 8:01 UTC (permalink / raw)
To: Dave Chinner
Cc: Christoph Hellwig, Jens Axboe, Linux Kernel Mailing List,
Justin M. Forbes, Jeff Moyer, Tejun Heo,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150729220829.GM3902@dastard>
On Wed, Jul 29, 2015 at 6:08 PM, Dave Chinner <david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org> wrote:
> On Wed, Jul 29, 2015 at 07:21:47AM -0400, Ming Lei wrote:
>> On Wed, Jul 29, 2015 at 4:41 AM, Dave Chinner <david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org> wrote:
>> > On Wed, Jul 29, 2015 at 03:33:52AM -0400, Ming Lei wrote:
>> >> On Mon, Jul 27, 2015 at 1:33 PM, Christoph Hellwig <hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> wrote:
>> >> > On Mon, Jul 27, 2015 at 05:53:33AM -0400, Ming Lei wrote:
>> >> >> Because size has to be 4k aligned too.
>> >> >
>> >> > Yes. But again I don't see any reason to limit us to a hardcoded 512
>> >> > byte block size here, especially considering the patches to finally
>> >>
>> >> From loop block's view, the request size can be any count of 512-byte
>> >> sectors, then the transfer size to backing device can't guarantee to be
>> >> 4k aligned always.
>> >
>> > In theory, yes. In practise, doesn't happen very often.
>> >
>> >> > allow enabling other block sizes from userspace.
>> >>
>> >> I have some questions about the patchset, and looks the author doesn't
>> >> reply it yet.
>> >>
>> >> On Mon, Jul 27, 2015 at 6:06 PM, Dave Chinner <david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org> wrote:
>> >> >> Because size has to be 4k aligned too.
>> >> >
>> >> > So check that, too. Any >= 4k block size filesystem should be doing
>> >> > mostly 4k aligned and sized IO...
>> >>
>> >> I guess you mean we only use direct IO for the 4k aligned and sized IO?
>> >> If so, that won't be efficient because the page cache has to be flushed
>> >> during the switch.
>> >
>> > It will be extremely rare for a 4k block size filesystem to do
>> > anything other than 4k aligned and sized IO. Think about it for a
>> > minute: what does the page cache do to unaligned IO patterns (i.e.
>> > buffered IO)? It does IO in page sizes, and so if the application
>> > if doing badly aligned or sized IO with buffered IO, then the
>> > underlying device will only ever size page sized and aligned IO.
>> >
>> > Hence sector aligned IO will only come from applications doing
>> > direct IO. If the application is doing direct IO and it's not
>> > properly aligned, then it already is going to get sucky performance
>> > because most filesystem serialise sub-block size direct IO because
>> > concurrent sub-block IOs to the same block usually leads to data
>> > corruption.
>>
>> The blocksize of filesysten over loop can be 512, 1024, 2048, and
>> suppose sector size of backing device is 4096, then filesystem
>> can see aligned direct IO when IO size/offset from application is aligned
>> with fs block size, but loop still can't do direct IO for all this
>> kind of requests
>> against backing file.
>
> Sure, but again you're talking about a fairly rare configuration.
> The vast majority of filesystems use 4k block sizes, just like the
> vast majority of applications use buffered IO. Don't jump through
> hoops to optimise a case that probably doesn't need optimising. Make
> it work correctly first, then optimise performance later when
> someone has a need for it to be really fast.
OK, I will support 1024, 2048 and 4096 sector size in v8.
>
>> Another case is that application may access loop block directly, such
>> as 'dd if=/dev/loopN', but it may not be common, and maybe it needn't
>> to consider.
>
> 'dd if=/dev/loopN bs=4k....'
>
> Cheers,
>
> Dave.
> --
> Dave Chinner
> david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: Next round: revised futex(2) man page for review
From: Michael Kerrisk (man-pages) @ 2015-07-30 8:19 UTC (permalink / raw)
To: Darren Hart, Thomas Gleixner
Cc: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w, Torvald Riegel,
Carlos O'Donell, Ingo Molnar, Jakub Jelinek, linux-man, lkml,
Davidlohr Bueso, Arnd Bergmann, Steven Rostedt, Peter Zijlstra,
Linux API, Roland McGrath, Anton Blanchard, Eric Dumazet,
bill o gallmeister, Jan Kiszka, Daniel Wagner, Rich Felker,
Andy Lutomirski, bert hubert, Rusty Russell, Heinrich Schuchardt
In-Reply-To: <20150729042141.GA62059@vmdeb7>
On 07/29/2015 06:21 AM, Darren Hart wrote:
> On Tue, Jul 28, 2015 at 09:11:41PM -0700, Darren Hart wrote:
>> On Tue, Jul 28, 2015 at 10:23:51PM +0200, Thomas Gleixner wrote:
>>> On Mon, 27 Jul 2015, Michael Kerrisk (man-pages) wrote:
>>
>> ...
>>
>>>> FUTEX_REQUEUE (since Linux 2.6.0)
>>>> .\" FIXME(Torvald) Is there some indication that FUTEX_REQUEUE is broken
>>>> .\" in general, or is this comment implicitly speaking about the
>>>> .\" condvar (?) use case? If the latter we might want to weaken the
>>>> .\" advice below a little.
>>>> .\" [Anyone else have input on this?]
>>>
>>> The condvar use case exposes the flaw nicely, but that's pretty much
>>> true for everything which wants a sane requeue operation.
>>
>> In an earlier discussion I argued this point (that FUTURE_REQUEUE is broken and
>> should not be used in new code) and someone argued strongly against... stating
>> that there were legitimate uses for it. Of course I'm struggling to find the
>> thread and the reference at the moment - immensely useful, I know.
>>
>> I'll continue trying to find it and see if it can be useful here. I believe
>> Torvald was on the thread as well.
>>
>
> Found it on libc-alpha, here it is for reference:
>
> From: Rich Felker <dalias-8zAoT0mYgF4@public.gmane.org>
> Date: Wed, 29 Oct 2014 22:43:17 -0400
> To: Darren Hart <dvhart-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
> Cc: Carlos O'Donell <carlos-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>, Roland McGrath <roland-/Z5OmTQCD9xF6kxbq+BtvQ@public.gmane.org>,
> Torvald Riegel <triegel-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>, GLIBC Devel <libc-alpha-9JcytcrH/bA+uJoB2kUjGw@public.gmane.org>,
> Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Subject: Re: Add futex wrapper to glibc?
>
> On Wed, Oct 29, 2014 at 06:59:15PM -0700, Darren Hart wrote:
> > > We are IMO at the stage where futex is stable, few things are
> > > changing, and with documentation in place, I would consider adding a
> > > futex wrapper.
> >
> > Yes, at least for the defined OP codes. New OPs may be added of
> > course, but that isn't a concern for supporting what exists today, and
> > doesn't break compatibility.
> >
> > I wonder though... can we not wrap FUTEX_REQUEUE? It's fundamentally
> > broken. FUTEX_CMP_REQUEUE should *always* be used instead. The glibc
> > wrapper is one way to encourage developers to do the right thing
> > (don't expose the bad op in the header).
>
> You're mistaken here. There are plenty of valid ways to use
> FUTEX_REQUEUE - for example if the calling thread is requeuing the
> target(s) to a lock that the calling thread owns. Just because it
> doesn't meet the needs of the way glibc was using it internally
> doesn't mean it's useless for other applications.
>
> In any case, I don't think there's a proposal to intercept/modify the
> commands to futex, just to pass them through (and possibly do a
> cancellable syscall for some of them).
>
> Rich
>
>
>>>
>>>> Avoid using this operation. It is broken for its intended
>>>> purpose. Use FUTEX_CMP_REQUEUE instead.
>>>>
>>>> This operation performs the same task as
>>>> FUTEX_CMP_REQUEUE, except that no check is made using the
>>>> value in val3. (The argument val3 is ignored.)
Thanks, Darren, that's really helpful! I've removed the statement in the man
page that FUTEX_REQUEUE is broken.
By the way, Darren. There were a couple of FIXMEs in the page where you are
explicitly mentioned by name. Could you take a look at those? Specifically,
the large block of text starting at:
>> .\" FIXME XXX The following is my attempt at a definition of PI futexes,
>> .\" based on mail discussions with Darren Hart. Does it seem okay?
(tglx looked at this and blessed it, but I'd like you also to check.)
Cheers,
Michael
--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
^ permalink raw reply
* Re: [RFC v3 1/4] fs: Add generic file system event notifications
From: Beata Michalska @ 2015-07-30 8:22 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz
Cc: linux-kernel, linux-fsdevel, linux-api, greg, jack, tytso,
adilger.kernel, hughd, lczerner, hch, linux-ext4, linux-mm,
kyungmin.park, kmpark
In-Reply-To: <6913836.Rhse3j9PM4@amdc1976>
On 07/22/2015 05:55 PM, Bartlomiej Zolnierkiewicz wrote:
>
> Hi,
>
> Some comments below.
>
> On Tuesday, June 16, 2015 03:09:30 PM Beata Michalska wrote:
>> Introduce configurable generic interface for file
>> system-wide event notifications, to provide file
>> systems with a common way of reporting any potential
>> issues as they emerge.
>>
>> The notifications are to be issued through generic
>> netlink interface by newly introduced multicast group.
>>
>> Threshold notifications have been included, allowing
>> triggering an event whenever the amount of free space drops
>> below a certain level - or levels to be more precise as two
>> of them are being supported: the lower and the upper range.
>> The notifications work both ways: once the threshold level
>> has been reached, an event shall be generated whenever
>> the number of available blocks goes up again re-activating
>> the threshold.
>>
>> The interface has been exposed through a vfs. Once mounted,
>> it serves as an entry point for the set-up where one can
>> register for particular file system events.
>>
>> Signed-off-by: Beata Michalska <b.michalska@samsung.com>
>> ---
>> Documentation/filesystems/events.txt | 232 ++++++++++
>> fs/Kconfig | 2 +
>> fs/Makefile | 1 +
>> fs/events/Kconfig | 7 +
>> fs/events/Makefile | 5 +
>> fs/events/fs_event.c | 809 ++++++++++++++++++++++++++++++++++
>> fs/events/fs_event.h | 22 +
>> fs/events/fs_event_netlink.c | 104 +++++
>> fs/namespace.c | 1 +
>> include/linux/fs.h | 6 +-
>> include/linux/fs_event.h | 72 +++
>> include/uapi/linux/Kbuild | 1 +
>> include/uapi/linux/fs_event.h | 58 +++
>> 13 files changed, 1319 insertions(+), 1 deletion(-)
>> create mode 100644 Documentation/filesystems/events.txt
>> create mode 100644 fs/events/Kconfig
>> create mode 100644 fs/events/Makefile
>> create mode 100644 fs/events/fs_event.c
>> create mode 100644 fs/events/fs_event.h
>> create mode 100644 fs/events/fs_event_netlink.c
>> create mode 100644 include/linux/fs_event.h
>> create mode 100644 include/uapi/linux/fs_event.h
>>
>> diff --git a/Documentation/filesystems/events.txt b/Documentation/filesystems/events.txt
>> new file mode 100644
>> index 0000000..c2e6227
>> --- /dev/null
>> +++ b/Documentation/filesystems/events.txt
>> @@ -0,0 +1,232 @@
>> +
>> + Generic file system event notification interface
>> +
>> +Document created 23 April 2015 by Beata Michalska <b.michalska@samsung.com>
>> +
>> +1. The reason behind:
>> +=====================
>> +
>> +There are many corner cases when things might get messy with the filesystems.
>> +And it is not always obvious what and when went wrong. Sometimes you might
>> +get some subtle hints that there is something going on - but by the time
>> +you realise it, it might be too late as you are already out-of-space
>> +or the filesystem has been remounted as read-only (i.e.). The generic
>> +interface for the filesystem events fills the gap by providing a rather
>> +easy way of real-time notifications triggered whenever something interesting
>> +happens, allowing filesystems to report events in a common way, as they occur.
>> +
>> +2. How does it work:
>> +====================
>> +
>> +The interface itself has been exposed as fstrace-type Virtual File System,
>> +primarily to ease the process of setting up the configuration for the
>> +notifications. So for starters, it needs to get mounted (obviously):
>> +
>> + mount -t fstrace none /sys/fs/events
>> +
>> +This will unveil the single fstrace filesystem entry - the 'config' file,
>> +through which the notification are being set-up.
>
> The patch creates a separate virtual filesystem for single file,
> this is an overkill IMHO and a new sysfs or debugfs entry should
> be sufficient.
>
>> +
>> +Activating notifications for particular filesystem is as straightforward
>> +as writing into the 'config' file. Note that by default all events, despite
>> +the actual filesystem type, are being disregarded.
>> +
>> +Synopsis of config:
>> +------------------
>> +
>> + MOUNT EVENT_TYPE [L1] [L2]
>
> OTOH Why not use the advantages of having a separate virtual
> filesystem and create separate directories for each mount point
> (+ maybe even extra parent directories for mount namespaces) and
> put separate entries for each event type in these directories.
>
> This would also allow usage of eventfd() notification interface
> on such files.
>
> Please take look at:
>
> tools/cgroup/cgroup_event_listener.c
>
> and
>
> Documentation/cgroups/memcg_test.txt (point 9.10)
>
> to see how much easier it is to observe memory usage thresholds
> on memory cgroups compared to available blocks on filesystems
> using fs events..
>
I'll give it some thoughts as the solution you are proposing eliminates
some issues related with the generic netlink (mostly the one concerning the
network namespaces) though I'd rather avoid creating numerous entries
for each mount/mount namespace. I guess the best option is to meet halfway.
> Also while at it please add your example user-space code (posted
> on request in a some other mail) to tools/fs_events/ (preferably
> in a separate patch).
>
Will do, once there is an overall agreement on the form of the
events interface.
>> +
>> + MOUNT : the filesystem's mount point
>> + EVENT_TYPE : event types - currently two of them are being supported:
>> +
>> + * generic events ("G") covering most common warnings
>> + and errors that might be reported by any filesystem;
>> + this option does not take any arguments;
>
> fs_event.h in uapi dir allows following events:
>
> /*
> * Supported set of FS events
> */
> enum {
> FS_EVENT_NONE,
> FS_WARN_ENOSPC, /* No space left to reserve data blks */
> FS_WARN_ENOSPC_META, /* No space left for metadata */
> FS_THR_LRBELOW, /* The threshold lower range has been reached */
> FS_THR_LRABOVE, /* The threshold lower range re-activcated*/
> FS_THR_URBELOW,
> FS_THR_URABOVE,
> FS_ERR_REMOUNT_RO, /* The file system has been remounted as RO */
> FS_ERR_CORRUPTED /* Critical error - fs corrupted */
>
> };
>
> For non-threshold related events the current interface allows
> only configuration of all or none events to be anabled, i.e.
> you cannot selectively enable notification on FS_WARN_ENOSPC
> but not on FS_ERR_REMOUNT_RO.
>
> I also think that configuration interface should be made to
> match the notification interface when it comes to event types.
>
Will take it into consideration - thanks.
>> +
>> + * threshold notifications ("T") - events sent whenever
>> + the amount of available space drops below certain level;
>> + it is possible to specify two threshold levels though
>> + only one is required to properly setup the notifications;
>> + as those refer to the number of available blocks, the lower
>> + level [L1] needs to be higher than the upper one [L2]
>
> Why is there a limitation of only two thresholds?
>
> It should be relatively easy to make the code support
> unlimited number of thresholds.
>
>> +
>> +Sample request could look like the following:
>> +
>> + echo /sample/mount/point G T 710000 500000 > /sys/fs/events/config
>> +
>> +Multiple request might be specified provided they are separated with semicolon.
>
> s/request/requests/
>
> I think that allowing multiple event types and requests in one
> configuration request is not a good idea. Currently parsing
> code is relatively simple but once somebody decides to enhance
> the interface with new event types the parsing code may get
> complex & ugly.
>
Noted.
>> +
>> +The configuration itself might be modified at any time. One can add/remove
>> +particular event types for given fielsystem, modify the threshold levels,
>
> s/fielsystem/filesystem/
>
>> +and remove single or all entries from the 'config' file.
>> +
>> + - Adding new event type:
>> +
>> + $ echo MOUNT EVENT_TYPE > /sys/fs/events/config
>> +
>> +(Note that is is enough to provide the event type to be enabled without
>
> s/is is/is/
>
>> +the already set ones.)
>> +
>> + - Removing event type:
>> +
>> + $ echo '!MOUNT EVENT_TYPE' > /sys/fs/events/config
>> +
>> + - Updating threshold limits:
>> +
>> + $ echo MOUNT T L1 L2 > /sys/fs/events/config
>> +
>> + - Removing single entry:
>> +
>> + $ echo '!MOUNT' > /sys/fs/events/config
>> +
>> + - Removing all entries:
>> +
>> + $ echo > /sys/fs/events/config
>> +
>> +Reading the file will list all registered entries with their current set-up
>> +along with some additional info like the filesystem type and the backing device
>> +name if available.
>> +
>> +Final, though a very important note on the configuration: when and if the
>> +actual events are being triggered falls way beyond the scope of the generic
>> +filesystem events interface. It is up to a particular filesystem
>> +implementation which events are to be supported - if any at all. So if
>> +given filesystem does not support the event notifications, an attempt to
>> +enable those through 'config' file will fail.
>> +
>> +
>> +3. The generic netlink interface support:
>> +=========================================
>> +
>> +Whenever an event notification is triggered (by given filesystem) the current
>> +configuration is being validated to decide whether a userpsace notification
>
> s/userpsace/userspace/
>
>> +should be launched. If there has been no request (in a mean of 'config' file
>> +entry) for given event, one will be silently disregarded. If, on the other
>> +hand, someone is 'watching' given filesystem for specific events, a generic
>> +netlink message will be sent. A dedicated multicast group has been provided
>> +solely for this purpose so in order to receive such notifications, one should
>> +subscribe to this new multicast group. As for now only the init network
>> +namespace is being supported.
>> +
>> +3.1 Message format
>> +
>> +The FS_NL_C_EVENT shall be stored within the generic netlink message header
>> +as the command field. The message payload will provide more detailed info:
>> +the backing device major and minor numbers, the event code and the id of
>> +the process which action led to the event occurrence. In case of threshold
>> +notifications, the current number of available blocks will be included
>> +in the payload as well.
>> +
>> +
>> + 0 1 2 3
>> + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
>> + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>> + | NETLINK MESSAGE HEADER |
>> + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>> + | GENERIC NETLINK MESSAGE HEADER |
>> + | (with FS_NL_C_EVENT as genlmsghdr cdm field) |
>> + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>> + | Optional user specific message header |
>> + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>> + | GENERIC MESSAGE PAYLOAD: |
>> + +---------------------------------------------------------------+
>> + | FS_NL_A_EVENT_ID (NLA_U32) |
>> + +---------------------------------------------------------------+
>> + | FS_NL_A_DEV_MAJOR (NLA_U32) |
>> + +---------------------------------------------------------------+
>> + | FS_NL_A_DEV_MINOR (NLA_U32) |
>> + +---------------------------------------------------------------+
>> + | FS_NL_A_CAUSED_ID (NLA_U32) |
>> + +---------------------------------------------------------------+
>> + | FS_NL_A_DATA (NLA_U64) |
>> + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>> +
>> +
>> +The above figure is based on:
>> + http://www.linuxfoundation.org/collaborate/workgroups/networking/generic_netlink_howto#Message_Format
>> +
>> +
>> +4. API Reference:
>> +=================
>> +
>> + 4.1 Generic file system event interface data & operations
>> +
>> + #include <linux/fs_event.h>
>> +
>> + struct fs_trace_info {
>> + void __rcu *e_priv /* READ ONLY */
>
> It should be marked as private for fs events core code and
> not for use by filesystems' code. If possible it would be
> the best to move it out of this struct,
>
>> + unsigned int events_cap_mask; /* Supported notifications */
>> + const struct fs_trace_operations *ops;
>> + };
>> +
>> + struct fs_trace_operations {
>> + void (*query)(struct super_block *, u64 *);
>> + };
>> +
>> + In order to get the fireworks and stuff, each filesystem needs to setup
>> + the events_cap_mask field of the fs_trace_info structure, which has been
>> + embedded within the super_block structure. This should reflect the type of
>> + events the filesystem wants to support. In case of threshold notifications,
>> + apart from setting the FS_EVENT_THRESH flag, the 'query' callback should
>> + be provided as this enables the events interface to get the up-to-date
>> + state of the number of available blocks whenever those notifications are
>> + being requested.
>> +
>> + The 'e_priv' field of the fs_trace_info structure should be completely ignored
>> + as it's for INTERNAL USE ONLY. So don't even think of messing with it, if you
>> + do not want to get yourself into some real trouble. If still, you are tempted
>> + to do so - feel free, it's gonna be pure fun. Consider yourself warned.
>> +
>> +
>> + 4.2 Event notification:
>> +
>> + #include <linux/fs_event.h>
>> + void fs_event_notify(struct super_block *sb, unsigned int event_id);
>> +
>> + Notify the generic FS event interface of an occurring event.
>> + This shall be used by any file system that wishes to inform any potential
>> + listeners/watchers of a particular event.
>> + - sb: the filesystem's super block
>> + - event_id: an event identifier
>> +
>> + 4.3 Threshold notifications:
>> +
>> + #include <linux/fs_event.h>
>> + void fs_event_alloc_space(struct super_block *sb, u64 ncount);
>> + void fs_event_free_space(struct super_block *sb, u64 ncount);
>> +
>> + Each filesystme supporting the threshold notifications should call
>> + fs_event_alloc_space/fs_event_free_space respectively whenever the
>> + amount of available blocks changes.
>> + - sb: the filesystem's super block
>> + - ncount: number of blocks being acquired/released
>> +
>> + Note that to properly handle the threshold notifications the fs events
>> + interface needs to be kept up to date by the filesystems. Each should
>> + register fs_trace_operations to enable querying the current number of
>> + available blocks.
>> +
>> + 4.4 Sending message through generic netlink interface
>> +
>> + #include <linux/fs_event.h>
>> +
>> + int fs_netlink_send_event(size_t size, unsigned int event_id,
>> + int (*compose_msg)(struct sk_buff *skb, void *data), void *cbdata);
>> +
>> + Although the fs event interface is fully responsible for sending the messages
>> + over the netlink, filesystems might use the FS_EVENT multicast group to send
>> + their own custom messages.
>> + - size: the size of the message payload
>> + - event_id: the event identifier
>> + - compose_msg: a callback responsible for filling-in the message payload
>> + - cbdata: message custom data
>> +
>> + Calling fs_netlink_send_event will result in a message being sent by
>> + the FS_EVENT multicast group. Note that the body of the message should be
>> + prepared (set-up )by the caller - through compose_msg callback. The message's
>
> (set-up)
>
>> + sk_buff will be allocated on behalf of the caller (thus the size parameter).
>> + The compose_msg should only fill the payload with proper data. Unless
>> + the event id is specified as FS_EVENT_NONE, it's value shall be added
>> + to the payload prior to calling the compose_msg.
>> +
>> +
>> diff --git a/fs/Kconfig b/fs/Kconfig
>> index ec35851..a89e678 100644
>> --- a/fs/Kconfig
>> +++ b/fs/Kconfig
>> @@ -69,6 +69,8 @@ config FILE_LOCKING
>> for filesystems like NFS and for the flock() system
>> call. Disabling this option saves about 11k.
>>
>> +source "fs/events/Kconfig"
>> +
>> source "fs/notify/Kconfig"
>>
>> source "fs/quota/Kconfig"
>> diff --git a/fs/Makefile b/fs/Makefile
>> index a88ac48..bcb3048 100644
>> --- a/fs/Makefile
>> +++ b/fs/Makefile
>> @@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules
>> obj-$(CONFIG_CEPH_FS) += ceph/
>> obj-$(CONFIG_PSTORE) += pstore/
>> obj-$(CONFIG_EFIVAR_FS) += efivarfs/
>> +obj-$(CONFIG_FS_EVENTS) += events/
>> diff --git a/fs/events/Kconfig b/fs/events/Kconfig
>> new file mode 100644
>> index 0000000..1c60195
>> --- /dev/null
>> +++ b/fs/events/Kconfig
>> @@ -0,0 +1,7 @@
>> +# Generic Files System events interface
>> +config FS_EVENTS
>> + bool "Generic filesystem events"
>> + select NET
>> + default y
>
> Do we really want to default to yes?
>
> [ If so then maybe we want to make the config option visible
> only when EXPERT mode is enabled? ]
>
>> + help
>> + Enable generic filesystem events interface
>
> Please enhance the help entry.
>
>> diff --git a/fs/events/Makefile b/fs/events/Makefile
>> new file mode 100644
>> index 0000000..9c98337
>> --- /dev/null
>> +++ b/fs/events/Makefile
>> @@ -0,0 +1,5 @@
>> +#
>> +# Makefile for the Linux Generic File System Event Interface
>> +#
>> +
>> +obj-y := fs_event.o fs_event_netlink.o
>> diff --git a/fs/events/fs_event.c b/fs/events/fs_event.c
>> new file mode 100644
>> index 0000000..1037311
>> --- /dev/null
>> +++ b/fs/events/fs_event.c
>> @@ -0,0 +1,809 @@
>> +/*
>> + * Generic File System Evens Interface
>> + *
>> + * Copyright(c) 2015 Samsung Electronics. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2.
>> + *
>> + * The full GNU General Public License is included in this distribution in the
>> + * file called COPYING.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + */
>> +#include <linux/fs.h>
>> +#include <linux/module.h>
>> +#include <linux/mount.h>
>> +#include <linux/namei.h>
>> +#include <linux/nsproxy.h>
>> +#include <linux/parser.h>
>> +#include <linux/seq_file.h>
>> +#include <linux/slab.h>
>> +#include <linux/rcupdate.h>
>> +#include <net/genetlink.h>
>> +#include "../pnode.h"
>> +#include "fs_event.h"
>> +
>> +static LIST_HEAD(fs_trace_list);
>> +static DEFINE_MUTEX(fs_trace_lock);
>> +
>> +static struct kmem_cache *fs_trace_cachep __read_mostly;
>> +
>> +static atomic_t stray_traces = ATOMIC_INIT(0);
>> +static DECLARE_WAIT_QUEUE_HEAD(trace_wq);
>> +/*
>> + * Threshold notification state bits.
>> + * Note the reverse as this refers to the number
>> + * of available blocks.
>> + */
>> +#define THRESH_LR_BELOW 0x0001 /* Falling below the lower range */
>> +#define THRESH_LR_BEYOND 0x0002
>> +#define THRESH_UR_BELOW 0x0004
>> +#define THRESH_UR_BEYOND 0x0008 /* Going beyond the upper range */
>> +
>> +#define THRESH_LR_ON (THRESH_LR_BELOW | THRESH_LR_BEYOND)
>> +#define THRESH_UR_ON (THRESH_UR_BELOW | THRESH_UR_BEYOND)
>> +
>> +#define FS_TRACE_ADD 0x100000
>> +
>> +struct fs_trace_entry {
>> + struct kref count;
>> + atomic_t active;
>> + struct super_block *sb;
>> + unsigned int notify;
>> + struct path mnt_path;
>> + struct list_head node;
>> +
>> + struct fs_event_thresh {
>> + u64 avail_space;
>> + u64 lrange;
>> + u64 urange;
>> + unsigned int state;
>> + } th;
>> + struct rcu_head rcu_head;
>> + spinlock_t lock;
>> +};
>> +
>> +static const match_table_t fs_etypes = {
>> + { FS_EVENT_GENERIC, "G" },
>> + { FS_EVENT_THRESH, "T" },
>> + { 0, NULL },
>> +};
>> +
>> +static inline int fs_trace_query_data(struct super_block *sb,
>> + struct fs_trace_entry *en)
>> +{
>> + if (sb->s_etrace.ops && sb->s_etrace.ops->query) {
>> + sb->s_etrace.ops->query(sb, &en->th.avail_space);
>> + return 0;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static inline void fs_trace_entry_free(struct fs_trace_entry *en)
>
> I don't see a real need for this wrapper (it is used only once).
>
>> +{
>> + kmem_cache_free(fs_trace_cachep, en);
>> +}
>> +
>> +static void fs_destroy_trace_entry(struct kref *en_ref)
>> +{
>> + struct fs_trace_entry *en = container_of(en_ref,
>> + struct fs_trace_entry, count);
>> +
>> + /* Last reference has been dropped */
>> + fs_trace_entry_free(en);
>> + atomic_dec(&stray_traces);
>> +}
>> +
>> +static void fs_trace_entry_put(struct fs_trace_entry *en)
>> +{
>> + kref_put(&en->count, fs_destroy_trace_entry);
>> +}
>> +
>> +static void fs_release_trace_entry(struct rcu_head *rcu_head)
>> +{
>> + struct fs_trace_entry *en = container_of(rcu_head,
>> + struct fs_trace_entry,
>> + rcu_head);
>> + /*
>> + * As opposed to typical reference drop, this one is being
>> + * called from the rcu callback. This is to make sure all
>> + * readers have managed to safely grab the reference before
>> + * the change to rcu pointer is visible to all and before
>> + * the reference is dropped here.
>> + */
>> + fs_trace_entry_put(en);
>> +}
>> +
>> +static void fs_drop_trace_entry(struct fs_trace_entry *en)
>> +{
>> + struct super_block *sb;
>> +
>> + lockdep_assert_held(&fs_trace_lock);
>> + /*
>> + * The trace entry might have already been removed
>> + * from the list of active traces with the proper
>> + * ref drop, though it was still in use handling
>> + * one of the fs events. This means that the object
>> + * has been already scheduled for being released.
>> + * So leave...
>> + */
>> +
>> + if (!atomic_add_unless(&en->active, -1, 0))
>> + return;
>> + /*
>> + * At this point the trace entry is being marked as inactive
>> + * so no new references will be allowed.
>> + * Still it might be floating around somewhere
>> + * so drop the reference when the rcu readers are done.
>> + */
>> + spin_lock(&en->lock);
>> + list_del(&en->node);
>> + sb = en->sb;
>> + en->sb = NULL;
>> + spin_unlock(&en->lock);
>> +
>> + rcu_assign_pointer(sb->s_etrace.e_priv, NULL);
>> + call_rcu(&en->rcu_head, fs_release_trace_entry);
>> + /* It's safe now to drop the reference to the super */
>> + deactivate_super(sb);
>> + atomic_inc(&stray_traces);
>> +}
>> +
>> +static inline
>> +struct fs_trace_entry *fs_trace_entry_get(struct fs_trace_entry *en)
>> +{
>> + if (en) {
>> + if (!kref_get_unless_zero(&en->count))
>> + return NULL;
>> + /* Don't allow referencing inactive object */
>> + if (!atomic_read(&en->active)) {
>> + fs_trace_entry_put(en);
>> + return NULL;
>> + }
>> + }
>> + return en;
>> +}
>> +
>> +static struct fs_trace_entry *fs_trace_entry_get_rcu(struct super_block *sb)
>> +{
>> + struct fs_trace_entry *en;
>> +
>> + if (!sb)
>> + return NULL;
>> +
>> + rcu_read_lock();
>> + en = rcu_dereference(sb->s_etrace.e_priv);
>> + en = fs_trace_entry_get(en);
>> + rcu_read_unlock();
>> +
>> + return en;
>> +}
>> +
>> +static int fs_remove_trace_entry(struct super_block *sb)
>> +{
>> + struct fs_trace_entry *en;
>> +
>> + en = fs_trace_entry_get_rcu(sb);
>> + if (!en)
>> + return -EINVAL;
>> +
>> + mutex_lock(&fs_trace_lock);
>> + fs_drop_trace_entry(en);
>> + mutex_unlock(&fs_trace_lock);
>> + fs_trace_entry_put(en);
>> + return 0;
>> +}
>> +
>> +static void fs_remove_all_traces(void)
>> +{
>> + struct fs_trace_entry *en, *guard;
>> +
>> + mutex_lock(&fs_trace_lock);
>> + list_for_each_entry_safe(en, guard, &fs_trace_list, node)
>> + fs_drop_trace_entry(en);
>> + mutex_unlock(&fs_trace_lock);
>> +}
>> +
>> +static int create_common_msg(struct sk_buff *skb, void *data)
>> +{
>> + struct fs_trace_entry *en = (struct fs_trace_entry *)data;
>> + struct super_block *sb = en->sb;
>> +
>> + if (nla_put_u32(skb, FS_NL_A_DEV_MAJOR, MAJOR(sb->s_dev))
>> + || nla_put_u32(skb, FS_NL_A_DEV_MINOR, MINOR(sb->s_dev)))
>> + return -EINVAL;
>> +
>> + if (nla_put_u64(skb, FS_NL_A_CAUSED_ID, pid_vnr(task_pid(current))))
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +
>> +static int create_thresh_msg(struct sk_buff *skb, void *data)
>> +{
>> + struct fs_trace_entry *en = (struct fs_trace_entry *)data;
>> + int ret;
>> +
>> + ret = create_common_msg(skb, data);
>> + if (!ret)
>> + ret = nla_put_u64(skb, FS_NL_A_DATA, en->th.avail_space);
>> + return ret;
>> +}
>> +
>> +static void fs_event_send(struct fs_trace_entry *en, unsigned int event_id)
>> +{
>> + size_t size = nla_total_size(sizeof(u32)) * 2 +
>> + nla_total_size(sizeof(u64));
>> +
>> + fs_netlink_send_event(size, event_id, create_common_msg, en);
>> +}
>> +
>> +static void fs_event_send_thresh(struct fs_trace_entry *en,
>> + unsigned int event_id)
>> +{
>> + size_t size = nla_total_size(sizeof(u32)) * 2 +
>> + nla_total_size(sizeof(u64)) * 2;
>> +
>> + fs_netlink_send_event(size, event_id, create_thresh_msg, en);
>> +}
>> +
>> +void fs_event_notify(struct super_block *sb, unsigned int event_id)
>> +{
>> + struct fs_trace_entry *en;
>> +
>> + en = fs_trace_entry_get_rcu(sb);
>> + if (!en)
>> + return;
>> +
>> + spin_lock(&en->lock);
>> + if (atomic_read(&en->active) && (en->notify & FS_EVENT_GENERIC))
>> + fs_event_send(en, event_id);
>> + spin_unlock(&en->lock);
>> + fs_trace_entry_put(en);
>> +}
>> +EXPORT_SYMBOL(fs_event_notify);
>> +
>> +void fs_event_alloc_space(struct super_block *sb, u64 ncount)
>> +{
>> + struct fs_trace_entry *en;
>> + s64 count;
>> +
>> + en = fs_trace_entry_get_rcu(sb);
>> + if (!en)
>> + return;
>> +
>> + spin_lock(&en->lock);
>> +
>> + if (!atomic_read(&en->active) || !(en->notify & FS_EVENT_THRESH))
>> + goto leave;
>> + /*
>> + * we shouldn't drop below 0 here,
>> + * unless there is a sync issue somewhere (?)
>> + */
>> + count = en->th.avail_space - ncount;
>> + en->th.avail_space = count < 0 ? 0 : count;
>> +
>> + if (en->th.avail_space > en->th.lrange)
>> + /* Not 'even' close - leave */
>> + goto leave;
>> +
>> + if (en->th.avail_space > en->th.urange) {
>> + /* Close enough - the lower range has been reached */
>> + if (!(en->th.state & THRESH_LR_BEYOND)) {
>> + /* Send notification */
>> + fs_event_send_thresh(en, FS_THR_LRBELOW);
>> + en->th.state &= ~THRESH_LR_BELOW;
>> + en->th.state |= THRESH_LR_BEYOND;
>> + }
>> + goto leave;
>> + }
>> + if (!(en->th.state & THRESH_UR_BEYOND)) {
>> + fs_event_send_thresh(en, FS_THR_URBELOW);
>> + en->th.state &= ~THRESH_UR_BELOW;
>> + en->th.state |= THRESH_UR_BEYOND;
>> + }
>> +
>> +leave:
>> + spin_unlock(&en->lock);
>> + fs_trace_entry_put(en);
>> +}
>> +EXPORT_SYMBOL(fs_event_alloc_space);
>> +
>> +void fs_event_free_space(struct super_block *sb, u64 ncount)
>> +{
>> + struct fs_trace_entry *en;
>> +
>> + en = fs_trace_entry_get_rcu(sb);
>> + if (!en)
>> + return;
>> +
>> + spin_lock(&en->lock);
>> +
>> + if (!atomic_read(&en->active) || !(en->notify & FS_EVENT_THRESH))
>> + goto leave;
>> +
>> + en->th.avail_space += ncount;
>> +
>> + if (en->th.avail_space > en->th.lrange) {
>> + if (!(en->th.state & THRESH_LR_BELOW)
>> + && en->th.state & THRESH_LR_BEYOND) {
>> + /* Send notification */
>> + fs_event_send_thresh(en, FS_THR_LRABOVE);
>> + en->th.state &= ~(THRESH_LR_BEYOND|THRESH_UR_BEYOND);
>> + en->th.state |= THRESH_LR_BELOW;
>> + goto leave;
>> + }
>> + }
>> + if (en->th.avail_space > en->th.urange) {
>> + if (!(en->th.state & THRESH_UR_BELOW)
>> + && en->th.state & THRESH_UR_BEYOND) {
>> + /* Notify */
>> + fs_event_send_thresh(en, FS_THR_URABOVE);
>> + en->th.state &= ~THRESH_UR_BEYOND;
>> + en->th.state |= THRESH_UR_BELOW;
>> + }
>> + }
>> +leave:
>> + spin_unlock(&en->lock);
>> + fs_trace_entry_put(en);
>> +}
>> +EXPORT_SYMBOL(fs_event_free_space);
>> +
>> +void fs_event_mount_dropped(struct vfsmount *mnt)
>> +{
>> + /*
>> + * The mount is dropped but the super might not get released
>> + * at once so there is very small chance some notifications
>> + * will come through.
>> + * Note that the mount being dropped here might belong to a different
>> + * namespace - if this is the case, just ignore it.
>> + */
>> + struct fs_trace_entry *en = fs_trace_entry_get_rcu(mnt->mnt_sb);
>> + struct vfsmount *en_mnt;
>> +
>> + if (!en || !atomic_read(&en->active))
>> + return;
>> + /*
>> + * The entry once set, does not change the mountpoint it's being
>> + * pinned to, so no need to take the lock here.
>> + */
>> + en_mnt = en->mnt_path.mnt;
>> + if (!(real_mount(mnt)->mnt_ns != (real_mount(en_mnt))->mnt_ns))
>> + fs_remove_trace_entry(mnt->mnt_sb);
>> + fs_trace_entry_put(en);
>> +}
>> +
>> +static int fs_new_trace_entry(struct path *path, struct fs_event_thresh *thresh,
>> + unsigned int nmask)
>> +{
>> + struct fs_trace_entry *en;
>> + struct super_block *sb;
>> + struct mount *r_mnt;
>> +
>> + en = kmem_cache_zalloc(fs_trace_cachep, GFP_KERNEL);
>> + if (unlikely(!en))
>> + return -ENOMEM;
>> + /*
>> + * Note that no reference is being taken here for the path as it would
>> + * make the unmount unnecessarily puzzling (due to an extra 'valid'
>> + * reference for the mnt).
>> + * This is *rather* safe as the notification on mount being dropped
>> + * will get called prior to releasing the super block - so right
>> + * in time to perform appropriate clean-up
>> + */
>> + r_mnt = real_mount(path->mnt);
>> +
>> + en->mnt_path.dentry = r_mnt->mnt.mnt_root;
>> + en->mnt_path.mnt = &r_mnt->mnt;
>> +
>> + sb = path->mnt->mnt_sb;
>> + en->sb = sb;
>> + /*
>> + * Increase the refcount for sb to mark it's being relied on.
>> + * Note that the reference to path is taken by the caller, so it
>> + * is safe to assume there is at least single active reference
>> + * to super as well.
>> + */
>> + atomic_inc(&sb->s_active);
>> +
>> + nmask &= sb->s_etrace.events_cap_mask;
>> + if (!nmask)
>> + goto leave;
>> +
>> + spin_lock_init(&en->lock);
>> + INIT_LIST_HEAD(&en->node);
>> +
>> + en->notify = nmask;
>> + memcpy(&en->th, thresh, offsetof(struct fs_event_thresh, state));
>> + if (nmask & FS_EVENT_THRESH)
>> + fs_trace_query_data(sb, en);
>> +
>> + kref_init(&en->count);
>> +
>> + if (rcu_access_pointer(sb->s_etrace.e_priv) != NULL) {
>> + struct fs_trace_entry *prev_en;
>> +
>> + prev_en = fs_trace_entry_get_rcu(sb);
>> + if (prev_en) {
>> + WARN_ON(prev_en);
>> + fs_trace_entry_put(prev_en);
>> + goto leave;
>> + }
>> + }
>> + atomic_set(&en->active, 1);
>> +
>> + mutex_lock(&fs_trace_lock);
>> + list_add(&en->node, &fs_trace_list);
>> + mutex_unlock(&fs_trace_lock);
>> +
>> + rcu_assign_pointer(sb->s_etrace.e_priv, en);
>> + synchronize_rcu();
>> +
>> + return 0;
>> +leave:
>> + deactivate_super(sb);
>> + kmem_cache_free(fs_trace_cachep, en);
>> + return -EINVAL;
>> +}
>> +
>> +static int fs_update_trace_entry(struct path *path,
>> + struct fs_event_thresh *thresh,
>> + unsigned int nmask)
>> +{
>> + struct fs_trace_entry *en;
>> + struct super_block *sb;
>> + int extend = nmask & FS_TRACE_ADD;
>> + int ret = -EINVAL;
>> +
>> + en = fs_trace_entry_get_rcu(path->mnt->mnt_sb);
>> + if (!en)
>> + return (extend) ? fs_new_trace_entry(path, thresh, nmask)
>> + : -EINVAL;
>> +
>> + if (!atomic_read(&en->active))
>> + return -EINVAL;
>> +
>> + nmask &= ~FS_TRACE_ADD;
>> +
>> + spin_lock(&en->lock);
>> + sb = en->sb;
>> + if (!sb || !(nmask & sb->s_etrace.events_cap_mask))
>> + goto leave;
>> +
>> + if (nmask & FS_EVENT_THRESH) {
>> + if (extend) {
>> + /* Get the current state */
>> + if (!(en->notify & FS_EVENT_THRESH))
>> + if (fs_trace_query_data(sb, en))
>> + goto leave;
>> +
>> + if (thresh->state & THRESH_LR_ON) {
>> + en->th.lrange = thresh->lrange;
>> + en->th.state &= ~THRESH_LR_ON;
>> + }
>> +
>> + if (thresh->state & THRESH_UR_ON) {
>> + en->th.urange = thresh->urange;
>> + en->th.state &= ~THRESH_UR_ON;
>> + }
>> + } else {
>> + memset(&en->th, 0, sizeof(en->th));
>> + }
>> + }
>> +
>> + if (extend)
>> + en->notify |= nmask;
>> + else
>> + en->notify &= ~nmask;
>> + ret = 0;
>> +leave:
>> + spin_unlock(&en->lock);
>> + fs_trace_entry_put(en);
>> + return ret;
>> +}
>> +
>> +static int fs_parse_trace_request(int argc, char **argv)
>> +{
>> + struct fs_event_thresh thresh = {0};
>> + struct path path;
>> + substring_t args[MAX_OPT_ARGS];
>> + unsigned int nmask = FS_TRACE_ADD;
>> + int token;
>> + char *s;
>> + int ret = -EINVAL;
>> +
>> + if (!argc) {
>> + fs_remove_all_traces();
>> + return 0;
>> + }
>> +
>> + s = *(argv);
>> + if (*s == '!') {
>> + /* Clear the trace entry */
>> + nmask &= ~FS_TRACE_ADD;
>> + ++s;
>> + }
>> +
>> + if (kern_path_mountpoint(AT_FDCWD, s, &path, LOOKUP_FOLLOW))
>> + return -EINVAL;
>> +
>> + if (!(--argc)) {
>> + if (!(nmask & FS_TRACE_ADD))
>> + ret = fs_remove_trace_entry(path.mnt->mnt_sb);
>> + goto leave;
>> + }
>> +
>> +repeat:
>> + args[0].to = args[0].from = NULL;
>> + token = match_token(*(++argv), fs_etypes, args);
>> + if (!token && !nmask)
>> + goto leave;
>> +
>> + nmask |= token & FS_EVENTS_ALL;
>> + --argc;
>> + if ((token & FS_EVENT_THRESH) && (nmask & FS_TRACE_ADD)) {
>> + /*
>> + * Get the threshold config data:
>> + * lower range
>> + * upper range
>> + */
>> + if (!argc)
>> + goto leave;
>> +
>> + ret = kstrtoull(*(++argv), 10, &thresh.lrange);
>> + if (ret)
>> + goto leave;
>> + thresh.state |= THRESH_LR_ON;
>> + if ((--argc)) {
>> + ret = kstrtoull(*(++argv), 10, &thresh.urange);
>> + if (ret)
>> + goto leave;
>> + thresh.state |= THRESH_UR_ON;
>> + --argc;
>> + }
>> + /* The thresholds are based on number of available blocks */
>> + if (thresh.lrange < thresh.urange) {
>> + ret = -EINVAL;
>> + goto leave;
>> + }
>> + }
>> + if (argc)
>> + goto repeat;
>> +
>> + ret = fs_update_trace_entry(&path, &thresh, nmask);
>> +leave:
>> + path_put(&path);
>> + return ret;
>> +}
>> +
>> +#define DEFAULT_BUF_SIZE PAGE_SIZE
>> +
>> +static ssize_t fs_trace_write(struct file *file, const char __user *buffer,
>> + size_t count, loff_t *ppos)
>> +{
>> + char **argv;
>> + char *kern_buf, *next, *cfg;
>> + size_t size, dcount = 0;
>> + int argc;
>> +
>> + if (!count)
>> + return 0;
>> +
>> + kern_buf = kmalloc(DEFAULT_BUF_SIZE, GFP_KERNEL);
>> + if (!kern_buf)
>> + return -ENOMEM;
>> +
>> + while (dcount < count) {
>> +
>> + size = count - dcount;
>> + if (size >= DEFAULT_BUF_SIZE)
>> + size = DEFAULT_BUF_SIZE - 1;
>> + if (copy_from_user(kern_buf, buffer + dcount, size)) {
>> + dcount = -EINVAL;
>> + goto leave;
>> + }
>> +
>> + kern_buf[size] = '\0';
>> +
>> + next = cfg = kern_buf;
>> +
>> + do {
>> + next = strchr(cfg, ';');
>> + if (next)
>> + *next = '\0';
>> +
>> + argv = argv_split(GFP_KERNEL, cfg, &argc);
>> + if (!argv) {
>> + dcount = -ENOMEM;
>> + goto leave;
>> + }
>> +
>> + if (fs_parse_trace_request(argc, argv)) {
>> + dcount = -EINVAL;
>> + argv_free(argv);
>> + goto leave;
>> + }
>> +
>> + argv_free(argv);
>> + if (next)
>> + cfg = ++next;
>> +
>> + } while (next);
>> + dcount += size;
>> + }
>> +leave:
>> + kfree(kern_buf);
>> + return dcount;
>> +}
>> +
>> +static void *fs_trace_seq_start(struct seq_file *m, loff_t *pos)
>> +{
>> + mutex_lock(&fs_trace_lock);
>> + return seq_list_start(&fs_trace_list, *pos);
>> +}
>> +
>> +static void *fs_trace_seq_next(struct seq_file *m, void *v, loff_t *pos)
>> +{
>> + return seq_list_next(v, &fs_trace_list, pos);
>> +}
>> +
>> +static void fs_trace_seq_stop(struct seq_file *m, void *v)
>> +{
>> + mutex_unlock(&fs_trace_lock);
>> +}
>> +
>> +static int fs_trace_seq_show(struct seq_file *m, void *v)
>> +{
>> + struct fs_trace_entry *en;
>> + struct super_block *sb;
>> + struct mount *r_mnt;
>> + const struct match_token *match;
>> + unsigned int nmask;
>> +
>> + en = list_entry(v, struct fs_trace_entry, node);
>> + /* Do not show the entries outside current mount namespace */
>> + r_mnt = real_mount(en->mnt_path.mnt);
>> + if (r_mnt->mnt_ns != current->nsproxy->mnt_ns) {
>> + if (!__is_local_mountpoint(r_mnt->mnt_mountpoint))
>> + return 0;
>> + }
>> +
>> + sb = en->sb;
>> +
>> + seq_path(m, &en->mnt_path, "\t\n\\");
>> + seq_putc(m, ' ');
>> +
>> + seq_escape(m, sb->s_type->name, " \t\n\\");
>> + if (sb->s_subtype && sb->s_subtype[0]) {
>> + seq_putc(m, '.');
>> + seq_escape(m, sb->s_subtype, " \t\n\\");
>> + }
>> +
>> + seq_putc(m, ' ');
>> + if (sb->s_op->show_devname) {
>> + sb->s_op->show_devname(m, en->mnt_path.mnt->mnt_root);
>> + } else {
>> + seq_escape(m, r_mnt->mnt_devname ? r_mnt->mnt_devname : "none",
>> + " \t\n\\");
>> + }
>> + seq_puts(m, " (");
>> +
>> + nmask = en->notify;
>> + for (match = fs_etypes; match->pattern; ++match) {
>> + if (match->token & nmask) {
>> + seq_puts(m, match->pattern);
>> + nmask &= ~match->token;
>> + if (nmask)
>> + seq_putc(m, ',');
>> + }
>> + }
>> + seq_printf(m, " %llu %llu", en->th.lrange, en->th.urange);
>> + seq_puts(m, ")\n");
>> + return 0;
>> +}
>> +
>> +static const struct seq_operations fs_trace_seq_ops = {
>> + .start = fs_trace_seq_start,
>> + .next = fs_trace_seq_next,
>> + .stop = fs_trace_seq_stop,
>> + .show = fs_trace_seq_show,
>> +};
>> +
>> +static int fs_trace_open(struct inode *inode, struct file *file)
>> +{
>> + return seq_open(file, &fs_trace_seq_ops);
>> +}
>> +
>> +static const struct file_operations fs_trace_fops = {
>> + .owner = THIS_MODULE,
>> + .open = fs_trace_open,
>> + .write = fs_trace_write,
>> + .read = seq_read,
>> + .llseek = seq_lseek,
>> + .release = seq_release,
>> +};
>> +
>> +static int fs_trace_init(void)
>> +{
>> + fs_trace_cachep = KMEM_CACHE(fs_trace_entry, 0);
>> + if (!fs_trace_cachep)
>> + return -EINVAL;
>> + init_waitqueue_head(&trace_wq);
>> + return 0;
>> +}
>> +
>> +/* VFS support */
>> +static int fs_trace_fill_super(struct super_block *sb, void *data, int silen)
>> +{
>> + int ret;
>> + static struct tree_descr desc[] = {
>> + [2] = {
>> + .name = "config",
>> + .ops = &fs_trace_fops,
>> + .mode = S_IWUSR | S_IRUGO,
>> + },
>> + {""},
>> + };
>> +
>> + ret = simple_fill_super(sb, 0x7246332, desc);
>
> Please use a define for a magic number.
>
>> + return !ret ? fs_trace_init() : ret;
>> +}
>> +
>> +static struct dentry *fs_trace_do_mount(struct file_system_type *fs_type,
>> + int ntype, const char *dev_name, void *data)
>> +{
>> + return mount_single(fs_type, ntype, data, fs_trace_fill_super);
>> +}
>> +
>> +static void fs_trace_kill_super(struct super_block *sb)
>> +{
>> + /*
>> + * The rcu_barrier here will/should make sure all call_rcu
>> + * callbacks are completed - still there might be some active
>> + * trace objects in use which can make calling the
>> + * kmem_cache_destroy unsafe. So we wait until all traces
>> + * are finally released.
>> + */
>> + fs_remove_all_traces();
>> + rcu_barrier();
>> + wait_event(trace_wq, !atomic_read(&stray_traces));
>> +
>> + kmem_cache_destroy(fs_trace_cachep);
>> + kill_litter_super(sb);
>> +}
>> +
>> +static struct kset *fs_trace_kset;
>> +
>> +static struct file_system_type fs_trace_fstype = {
>> + .name = "fstrace",
>> + .mount = fs_trace_do_mount,
>> + .kill_sb = fs_trace_kill_super,
>> +};
>> +
>> +static void __init fs_trace_vfs_init(void)
>> +{
>> + fs_trace_kset = kset_create_and_add("events", NULL, fs_kobj);
>> +
>> + if (!fs_trace_kset)
>> + return;
>> +
>> + if (!register_filesystem(&fs_trace_fstype)) {
>> + if (!fs_event_netlink_register())
>> + return;
>> + unregister_filesystem(&fs_trace_fstype);
>> + }
>> + kset_unregister(fs_trace_kset);
>> +}
>> +
>> +static int __init fs_trace_evens_init(void)
>> +{
>> + fs_trace_vfs_init();
>> + return 0;
>> +};
>> +module_init(fs_trace_evens_init);
>> +
>> diff --git a/fs/events/fs_event.h b/fs/events/fs_event.h
>> new file mode 100644
>> index 0000000..23f24c8
>> --- /dev/null
>> +++ b/fs/events/fs_event.h
>> @@ -0,0 +1,22 @@
>> +/*
>> + * Copyright(c) 2015 Samsung Electronics. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2.
>> + *
>> + * The full GNU General Public License is included in this distribution in the
>> + * file called COPYING.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + */
>> +
>> +#ifndef __GENERIC_FS_EVENTS_H
>> +#define __GENERIC_FS_EVENTS_H
>> +
>> +int fs_event_netlink_register(void);
>> +void fs_event_netlink_unregister(void);
>> +
>> +#endif /* __GENERIC_FS_EVENTS_H */
>> diff --git a/fs/events/fs_event_netlink.c b/fs/events/fs_event_netlink.c
>> new file mode 100644
>> index 0000000..0c97eb7
>> --- /dev/null
>> +++ b/fs/events/fs_event_netlink.c
>> @@ -0,0 +1,104 @@
>> +/*
>> + * Copyright(c) 2015 Samsung Electronics. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2.
>> + *
>> + * The full GNU General Public License is included in this distribution in the
>> + * file called COPYING.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + */
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/sched.h>
>> +#include <linux/slab.h>
>> +#include <net/netlink.h>
>> +#include <net/genetlink.h>
>> +#include "fs_event.h"
>> +
>> +static const struct genl_multicast_group fs_event_mcgroups[] = {
>> + { .name = FS_EVENTS_MCAST_GRP_NAME, },
>> +};
>> +
>> +static struct genl_family fs_event_family = {
>> + .id = GENL_ID_GENERATE,
>> + .name = FS_EVENTS_FAMILY_NAME,
>> + .version = 1,
>> + .maxattr = FS_NL_A_MAX,
>> + .mcgrps = fs_event_mcgroups,
>> + .n_mcgrps = ARRAY_SIZE(fs_event_mcgroups),
>> +};
>> +
>> +int fs_netlink_send_event(size_t size, unsigned int event_id,
>> + int (*compose_msg)(struct sk_buff *skb, void *data),
>> + void *cbdata)
>> +{
>> + static atomic_t seq;
>> + struct sk_buff *skb;
>> + void *msg_head;
>> + int ret = 0;
>> +
>> + if (!size || !compose_msg)
>> + return -EINVAL;
>> +
>> + /* Skip if there are no listeners */
>> + if (!genl_has_listeners(&fs_event_family, &init_net, 0))
>> + return 0;
>> +
>> + if (event_id != FS_EVENT_NONE)
>> + size += nla_total_size(sizeof(u32));
>> + size += nla_total_size(sizeof(u64));
>> + skb = genlmsg_new(size, GFP_NOWAIT);
>> +
>> + if (!skb) {
>> + pr_debug("Failed to allocate new FS generic netlink message\n");
>> + return -ENOMEM;
>> + }
>> +
>> + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq),
>> + &fs_event_family, 0, FS_NL_C_EVENT);
>> + if (!msg_head)
>> + goto cleanup;
>> +
>> + if (event_id != FS_EVENT_NONE)
>> + if (nla_put_u32(skb, FS_NL_A_EVENT_ID, event_id))
>> + goto cancel;
>> +
>> + ret = compose_msg(skb, cbdata);
>> + if (ret)
>> + goto cancel;
>> +
>> + genlmsg_end(skb, msg_head);
>> + ret = genlmsg_multicast(&fs_event_family, skb, 0, 0, GFP_NOWAIT);
>> + if (ret && ret != -ENOBUFS && ret != -ESRCH)
>> + goto cleanup;
>> +
>> + return ret;
>> +
>> +cancel:
>> + genlmsg_cancel(skb, msg_head);
>> +cleanup:
>> + nlmsg_free(skb);
>> + return ret;
>> +}
>> +EXPORT_SYMBOL(fs_netlink_send_event);
>> +
>> +int fs_event_netlink_register(void)
>> +{
>> + int ret;
>> +
>> + ret = genl_register_family(&fs_event_family);
>> + if (ret)
>> + pr_err("Failed to register FS netlink interface\n");
>> + return ret;
>> +}
>> +
>> +void fs_event_netlink_unregister(void)
>> +{
>> + genl_unregister_family(&fs_event_family);
>> +}
>> diff --git a/fs/namespace.c b/fs/namespace.c
>> index 82ef140..ec6e2ef 100644
>> --- a/fs/namespace.c
>> +++ b/fs/namespace.c
>> @@ -1031,6 +1031,7 @@ static void cleanup_mnt(struct mount *mnt)
>> if (unlikely(mnt->mnt_pins.first))
>> mnt_pin_kill(mnt);
>> fsnotify_vfsmount_delete(&mnt->mnt);
>> + fs_event_mount_dropped(&mnt->mnt);
>> dput(mnt->mnt.mnt_root);
>> deactivate_super(mnt->mnt.mnt_sb);
>> mnt_free_id(mnt);
>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>> index b4d71b5..b7dadd9 100644
>> --- a/include/linux/fs.h
>> +++ b/include/linux/fs.h
>> @@ -263,6 +263,10 @@ struct iattr {
>> * Includes for diskquotas.
>> */
>> #include <linux/quota.h>
>> +/*
>> + * Include for Generic File System Events Interface
>> + */
>> +#include <linux/fs_event.h>
>>
>> /*
>> * Maximum number of layers of fs stack. Needs to be limited to
>> @@ -1253,7 +1257,7 @@ struct super_block {
>> struct hlist_node s_instances;
>> unsigned int s_quota_types; /* Bitmask of supported quota types */
>> struct quota_info s_dquot; /* Diskquota specific options */
>> -
>> + struct fs_trace_info s_etrace;
>> struct sb_writers s_writers;
>>
>> char s_id[32]; /* Informational name */
>> diff --git a/include/linux/fs_event.h b/include/linux/fs_event.h
>> new file mode 100644
>> index 0000000..83e22dd
>> --- /dev/null
>> +++ b/include/linux/fs_event.h
>> @@ -0,0 +1,72 @@
>> +/*
>> + * Generic File System Events Interface
>> + *
>> + * Copyright(c) 2015 Samsung Electronics. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2.
>> + *
>> + * The full GNU General Public License is included in this distribution in the
>> + * file called COPYING.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + */
>> +#ifndef _LINUX_GENERIC_FS_EVETS_
>> +#define _LINUX_GENERIC_FS_EVETS_
>
> EVETS?
>
> Also the define name usually corresponds to the header filename.
>
>> +#include <net/netlink.h>
>> +#include <uapi/linux/fs_event.h>
>> +
>> +/*
>> + * Currently supported event types
>> + */
>> +#define FS_EVENT_GENERIC 0x001
>> +#define FS_EVENT_THRESH 0x002
>> +
>> +#define FS_EVENTS_ALL (FS_EVENT_GENERIC | FS_EVENT_THRESH)
>> +
>> +struct fs_trace_operations {
>> + void (*query)(struct super_block *, u64 *);
>> +};
>> +
>> +struct fs_trace_info {
>> + void __rcu *e_priv; /* READ ONLY */
>> + unsigned int events_cap_mask; /* Supported notifications */
>> + const struct fs_trace_operations *ops;
>> +};
>> +
>> +#ifdef CONFIG_FS_EVENTS
>> +
>> +void fs_event_notify(struct super_block *sb, unsigned int event_id);
>> +void fs_event_alloc_space(struct super_block *sb, u64 ncount);
>> +void fs_event_free_space(struct super_block *sb, u64 ncount);
>> +void fs_event_mount_dropped(struct vfsmount *mnt);
>> +
>> +int fs_netlink_send_event(size_t size, unsigned int event_id,
>> + int (*compose_msg)(struct sk_buff *skb, void *data),
>> + void *cbdata);
>> +
>> +#else /* CONFIG_FS_EVENTS */
>> +
>> +static inline
>> +void fs_event_notify(struct super_block *sb, unsigned int event_id) {};
>> +static inline
>> +void fs_event_alloc_space(struct super_block *sb, u64 ncount) {};
>> +static inline
>> +void fs_event_free_space(struct super_block *sb, u64 ncount) {};
>> +static inline
>> +void fs_event_mount_dropped(struct vfsmount *mnt) {};
>> +
>> +static inline
>> +int fs_netlink_send_event(size_t size, unsigned int event_id,
>> + int (*compose_msig)(struct sk_buff *skb, void *data),
>> + void *cbdata)
>> +{
>> + return -ENOSYS;
>> +}
>> +#endif /* CONFIG_FS_EVENTS */
>> +
>> +#endif /* _LINUX_GENERIC_FS_EVENTS_ */
>> +
>> diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
>> index 68ceb97..dae0fab 100644
>> --- a/include/uapi/linux/Kbuild
>> +++ b/include/uapi/linux/Kbuild
>> @@ -129,6 +129,7 @@ header-y += firewire-constants.h
>> header-y += flat.h
>> header-y += fou.h
>> header-y += fs.h
>> +header-y += fs_event.h
>> header-y += fsl_hypervisor.h
>> header-y += fuse.h
>> header-y += futex.h
>> diff --git a/include/uapi/linux/fs_event.h b/include/uapi/linux/fs_event.h
>> new file mode 100644
>> index 0000000..d8b07da
>> --- /dev/null
>> +++ b/include/uapi/linux/fs_event.h
>> @@ -0,0 +1,58 @@
>> +/*
>> + * Generic netlink support for Generic File System Events Interface
>> + *
>> + * Copyright(c) 2015 Samsung Electronics. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2.
>> + *
>> + * The full GNU General Public License is included in this distribution in the
>> + * file called COPYING.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + */
>> +#ifndef _UAPI_LINUX_GENERIC_FS_EVENTS_
>> +#define _UAPI_LINUX_GENERIC_FS_EVENTS_
>
> Define name usually corresponds to the header filename.
>
>> +#define FS_EVENTS_FAMILY_NAME "fs_event"
>> +#define FS_EVENTS_MCAST_GRP_NAME "fs_event_mc_grp"
>> +
>> +/*
>> + * Generic netlink attribute types
>> + */
>> +enum {
>> + FS_NL_A_NONE,
>> + FS_NL_A_EVENT_ID,
>> + FS_NL_A_DEV_MAJOR,
>> + FS_NL_A_DEV_MINOR,
>> + FS_NL_A_CAUSED_ID,
>> + FS_NL_A_DATA,
>> + __FS_NL_A_MAX,
>> +};
>> +#define FS_NL_A_MAX (__FS_NL_A_MAX - 1)
>> +/*
>> + * Generic netlink commands
>> + */
>> +#define FS_NL_C_EVENT 1
>> +
>> +/*
>> + * Supported set of FS events
>> + */
>> +enum {
>> + FS_EVENT_NONE,
>> + FS_WARN_ENOSPC, /* No space left to reserve data blks */
>> + FS_WARN_ENOSPC_META, /* No space left for metadata */
>> + FS_THR_LRBELOW, /* The threshold lower range has been reached */
>> + FS_THR_LRABOVE, /* The threshold lower range re-activcated*/
>> + FS_THR_URBELOW,
>> + FS_THR_URABOVE,
>> + FS_ERR_REMOUNT_RO, /* The file system has been remounted as RO */
>> + FS_ERR_CORRUPTED /* Critical error - fs corrupted */
>> +
>> +};
>> +
>> +#endif /* _UAPI_LINUX_GENERIC_FS_EVENTS_ */
>> +
>
> Best regards,
> --
> Bartlomiej Zolnierkiewicz
> Samsung R&D Institute Poland
> Samsung Electronics
>
>
Thanks for Your comments.
Best Regards
Beata
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCHv2 1/1] Documentation: describe how to add a system call
From: Ingo Molnar @ 2015-07-30 8:38 UTC (permalink / raw)
To: David Drysdale
Cc: linux-api, Michael Kerrisk, Andrew Morton, Arnd Bergmann,
Shuah Khan, Jonathan Corbet, Eric B Munson, Randy Dunlap,
Andrea Arcangeli, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Oleg Nesterov, Linus Torvalds, Greg Kroah-Hartman,
Andy Lutomirski, Al Viro, Rusty Russell, Peter Zijlstra,
Vivek Goyal, Alexei Starovoitov, David Herrmann,
Theodore Ts'o, Kees Cook <keesc>
In-Reply-To: <1438242731-27756-2-git-send-email-drysdale@google.com>
* David Drysdale <drysdale@google.com> wrote:
> +Designing the API
> +-----------------
> +
> +A new system call forms part of the API of the kernel, and has to be supported
> +indefinitely. As such, it's a very good idea to explicitly discuss the
> +interface on the kernel mailing list, and to plan for future extensions of the
> +interface. In particular:
> +
> + **Include a flags argument for every new system call**
Sorry, but I think that's bad avice, because even a 'flags' field is inflexible
and stupid in many cases - it fosters an 'ioctl' kind of design.
> +The syscall table is littered with historical examples where this wasn't done,
> +together with the corresponding follow-up system calls (eventfd/eventfd2,
> +dup2/dup3, inotify_init/inotify_init1, pipe/pipe2, renameat/renameat2), so
> +learn from the history of the kernel and include a flags argument from the
> +start.
The syscall table is also littered with system calls that have an argument space
considerably larger than what 6 parameters can express, where various 'flags' are
used to bring in different parts of new APIs, in a rather messy way.
The right approach IMHO is to think about how extensible a system call is expected
to be, and to plan accordingly.
If you are anywhere close to 6 parameters, you should not introduce 'flags' but
you should _reduce_ the number of parameters to a clean essential of 2 or 3
parameters and should shuffle parameters out to a separate 'parameters/attributes'
structure that is passed in by pointer:
SYSCALL_DEFINE2(syscall, int, fd, struct params __user *, params);
And it's the design of 'struct params' that determines future flexibility of the
interface. A very flexible approach is to not use flags but a 'size' argument:
struct params {
u32 size;
u32 param_1;
u64 param_2;
u64 param_3;
};
Where 'size' is set by user-space to the size of 'struct params' known to it at
build time:
params->size = sizeof(*params);
In the normal case the kernel will get param->size == sizeof(*params) as known to
the kernel.
When the system call is extended in the future on the kernel side, with 'u64
param_4', then the structure expands from an old size of 24 to a new size of 32
bytes. The following scenarios might occur:
- the common case: new user-space calls the new kernel code, ->size is 32 on both
sides.
- old binaries might call the kernel with params->size == 24, in which case the
kernel sets the new fields to 0. The new feature should be written
accordingly, so that a value of 0 means the old behavior.
- new binaries might run on old kernels, with params->size == 32. In this case
the old kernel will check that all the new fields it does not know about are
set to 0 - if they are nonzero (if the new feature is used) it returns with
-ENOSYS or -EINVAL.
With this approach we have both backwards and forwards binary compatibility: new
binaries will run on old kernels just fine, even if they have ->size set to 32, as
long as they make use of the features.
This design simplifies application design considerably: as new code can mostly
forget about old ABIs, there's no multiple versions to be taken care of, there's
just a single 'struct param' known to both sides, and there's no version skew.
We are using such a design in perf_event_open(), see perf_copy_attr() in
kernel/events/core.c. And yes, ironically that system call still has a historic
'flags' argument, but it's not used anymore for extension: we've made over 30
extensions to the ABI in the last 3 years, which would have been impossible with a
'flags' approach.
Thanks,
Ingo
^ permalink raw reply
* Re: [PATCH -mm v9 0/8] idle memory tracking
From: Michal Hocko @ 2015-07-30 9:07 UTC (permalink / raw)
To: Vladimir Davydov
Cc: Andrew Morton, Andres Lagar-Cavilla, Minchan Kim, Raghavendra K T,
Johannes Weiner, Greg Thelen, Michel Lespinasse, David Rientjes,
Pavel Emelyanov, Cyrill Gorcunov, Jonathan Corbet,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
cgroups-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150729162908.GY8100@esperanza>
On Wed 29-07-15 19:29:08, Vladimir Davydov wrote:
> On Wed, Jul 29, 2015 at 05:47:18PM +0200, Michal Hocko wrote:
[...]
> > If you use the low limit for isolating an important load then you do not
> > have to care about the others that much. All you care about is to set
> > the reasonable protection level and let others to compete for the rest.
>
> That's a use case, you're right. Well, it's a natural limitation of this
> API - you just have to perform a full PFN scan then. You can avoid
> costly rmap walks for the cgroups you are not interested in by filtering
> them out using /proc/kpagecgroup though.
You still have to read through the whole memory and that is inherent to
the API and there no way for a better implementation later on other than
a new exported file.
[...]
> > > Because there is too much to be taken care of in the kernel with such an
> > > approach and chances are high that it won't satisfy everyone. What
> > > should the scan period be equal too?
> >
> > No, just gather the data on the read request and let the userspace
> > to decide when/how often etc. If we are clever enough we can cache
> > the numbers and prevent from the walk. Write to the file and do the
> > mark_idle stuff.
>
> Still, scan rate limiting would be an issue IMO.
Not sure what you mean here. Scan rate would be defined by the userspace
by reading/writing to the knob. No background kernel thread is really
necessary.
> > > Knob. How many kthreads do we want?
> > > Knob. I want to keep history for last N intervals (this was a part of
> > > Michel's implementation), what should N be equal to? Knob.
> >
> > This all relates to the kernel thread implementation which I wasn't
> > suggesting. I was referring to Michel's work which might induce that.
> > I was merely referring to a single number output. Sorry about the
> > confusion.
>
> Still, what about idle stats history? I mean having info about how many
> pages were idle for N scans. It might be useful for more robust/accurate
> wss estimation.
Why cannot userspace remember those numbers?
> > > I want to be
> > > able to choose between an instant scan and a scan distributed in time.
> > > Knob. I want to see stats for anon/locked/file/dirty memory separately,
> >
> > Why is this useful for the memcg limits setting or the wss estimation? I
> > can imagine that a further drop down numbers might be interesting
> > from the debugging POV but I fail to see what kind of decisions from
> > userspace you would do based on them.
>
> A couple examples that pop up in my mind:
>
> It's difficult to make wss estimation perfect. By mlocking pages, a
> workload might give a hint to the system that it will be really unhappy
> if they are evicted.
>
> One might want to consider anon pages and/or dirty pages as not idle in
> order to protect them and hence avoid expensive pageout/swapout.
I still seem to miss the point. How do you do that via the proposed
interface which doesn't influence the reclaim AFAIU and you do not have
means to achieve the above (except for swappiness). What am I missing?
> > [...]
> > > > Yes this is really tricky with the current LRU implementation. I
> > > > was playing with some ideas (do some checkpoints on the way) but
> > > > none of them was really working out on a busy systems. But the LRU
> > > > implementation might change in the future.
> > >
> > > It might. Then we could come up with a new /proc or /sys file which
> > > would do the same as /proc/kpageidle, but on per LRU^w whatever-it-is
> > > basis, and give people a choice which one to use.
> >
> > This just leads to proc files count explosion we are seeing
> > already... Proc ended up in dump ground for different things which
> > didn't fit elsewhere and I am not very much happy about it to be honest.
>
> Moving the API to memcg is not a good idea either IMO, because the
> feature can actually be useful with memcg disabled, e.g. it might help
> estimate if the system is over- or underloaded.
I agree and that's why I was referring to memcg/global knobs.
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* Re: [PATCH -mm v9 0/8] idle memory tracking
From: Vladimir Davydov @ 2015-07-30 9:12 UTC (permalink / raw)
To: Andrew Morton
Cc: Michal Hocko, Andres Lagar-Cavilla, Minchan Kim, Raghavendra K T,
Johannes Weiner, Greg Thelen, Michel Lespinasse, David Rientjes,
Pavel Emelyanov, Cyrill Gorcunov, Jonathan Corbet, linux-api,
linux-doc, linux-mm, cgroups, linux-kernel
In-Reply-To: <20150729143015.e8420eca17acbd36d1ce9242@linux-foundation.org>
On Wed, Jul 29, 2015 at 02:30:15PM -0700, Andrew Morton wrote:
> On Wed, 29 Jul 2015 19:29:08 +0300 Vladimir Davydov <vdavydov@parallels.com> wrote:
>
> > /proc/kpageidle should probably live somewhere in /sys/kernel/mm, but I
> > added it where similar files are located (kpagecount, kpageflags) to
> > keep things consistent.
>
> I think these files should be moved elsewhere. Consistency is good,
> but not when we're being consistent with a bad thing.
>
> So let's place these in /sys/kernel/mm and then start being consistent
> with that?
I really don't think we should separate kpagecgroup from kpagecount and
kpageflags, because they look very similar (each of them is read-only,
contains an array of u64 values referenced by PFN). Scattering these
files between different filesystems would look ugly IMO.
However, kpageidle is somewhat different (it's read-write, contains a
bitmap) so I think it's worth moving it to /sys/kernel/mm. We have to
move the code from fs/proc to mm/something then to remove dependency
from PROC_FS, which would be unnecessary. Let me give it a try.
Thanks,
Vladimir
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH -mm v9 0/8] idle memory tracking
From: Vladimir Davydov @ 2015-07-30 9:31 UTC (permalink / raw)
To: Michal Hocko
Cc: Andrew Morton, Andres Lagar-Cavilla, Minchan Kim, Raghavendra K T,
Johannes Weiner, Greg Thelen, Michel Lespinasse, David Rientjes,
Pavel Emelyanov, Cyrill Gorcunov, Jonathan Corbet,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
cgroups-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150730090708.GE9387-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
On Thu, Jul 30, 2015 at 11:07:09AM +0200, Michal Hocko wrote:
> On Wed 29-07-15 19:29:08, Vladimir Davydov wrote:
> > On Wed, Jul 29, 2015 at 05:47:18PM +0200, Michal Hocko wrote:
> [...]
> > > If you use the low limit for isolating an important load then you do not
> > > have to care about the others that much. All you care about is to set
> > > the reasonable protection level and let others to compete for the rest.
> >
> > That's a use case, you're right. Well, it's a natural limitation of this
> > API - you just have to perform a full PFN scan then. You can avoid
> > costly rmap walks for the cgroups you are not interested in by filtering
> > them out using /proc/kpagecgroup though.
>
> You still have to read through the whole memory and that is inherent to
> the API and there no way for a better implementation later on other than
> a new exported file.
I don't deny that. Nevertheless, PFN-walk is something that will always
be useful, simply because PFN-range is an invariant - it will always
exist. If one day a better page iterator appear (e.g. LRU walk) and the
need for it is justified well enough, we can add one more file. Note, it
won't deprecate the original PFN map - they both can be used for
different use cases then. If we move kpageidle to /sys/kernel/mm attr
group, which I'm doing now, it will be trivial to do and won't pollute
/proc.
>
> [...]
>
> > > > Because there is too much to be taken care of in the kernel with such an
> > > > approach and chances are high that it won't satisfy everyone. What
> > > > should the scan period be equal too?
> > >
> > > No, just gather the data on the read request and let the userspace
> > > to decide when/how often etc. If we are clever enough we can cache
> > > the numbers and prevent from the walk. Write to the file and do the
> > > mark_idle stuff.
> >
> > Still, scan rate limiting would be an issue IMO.
>
> Not sure what you mean here. Scan rate would be defined by the userspace
> by reading/writing to the knob. No background kernel thread is really
> necessary.
Nevertheless, it means more logic in the kernel (rate limiter) and a
wider interface (+ rate limit value).
>
> > > > Knob. How many kthreads do we want?
> > > > Knob. I want to keep history for last N intervals (this was a part of
> > > > Michel's implementation), what should N be equal to? Knob.
> > >
> > > This all relates to the kernel thread implementation which I wasn't
> > > suggesting. I was referring to Michel's work which might induce that.
> > > I was merely referring to a single number output. Sorry about the
> > > confusion.
> >
> > Still, what about idle stats history? I mean having info about how many
> > pages were idle for N scans. It might be useful for more robust/accurate
> > wss estimation.
>
> Why cannot userspace remember those numbers?
Because they must be per-page - you have to remember for how many
periods *each particular* page has been idle. To achieve this, Michel
had to introduce a byte array referenced by PFN in his work. With
kpageidle file one can store this array in the userspace.
>
> > > > I want to be
> > > > able to choose between an instant scan and a scan distributed in time.
> > > > Knob. I want to see stats for anon/locked/file/dirty memory separately,
> > >
> > > Why is this useful for the memcg limits setting or the wss estimation? I
> > > can imagine that a further drop down numbers might be interesting
> > > from the debugging POV but I fail to see what kind of decisions from
> > > userspace you would do based on them.
> >
> > A couple examples that pop up in my mind:
> >
> > It's difficult to make wss estimation perfect. By mlocking pages, a
> > workload might give a hint to the system that it will be really unhappy
> > if they are evicted.
> >
> > One might want to consider anon pages and/or dirty pages as not idle in
> > order to protect them and hence avoid expensive pageout/swapout.
>
> I still seem to miss the point. How do you do that via the proposed
> interface which doesn't influence the reclaim AFAIU and you do not have
> means to achieve the above (except for swappiness). What am I missing?
You can consider idle only those pages that are clean, and then set the
low limit appropriately for your workload. You can find out which pages
are clean by reading /proc/kpageflags. Of course, this won't stop the
reclaimer from evicting them, but it will make the reclaimer less
aggressive with respect to your workload.
Thanks,
Vladimir
^ permalink raw reply
* Re: [PATCHv2 1/1] Documentation: describe how to add a system call
From: David Drysdale @ 2015-07-30 11:10 UTC (permalink / raw)
To: Ingo Molnar
Cc: Linux API, Michael Kerrisk, Andrew Morton, Arnd Bergmann,
Shuah Khan, Jonathan Corbet, Eric B Munson, Randy Dunlap,
Andrea Arcangeli, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Oleg Nesterov, Linus Torvalds, Greg Kroah-Hartman,
Andy Lutomirski, Al Viro, Rusty Russell, Peter Zijlstra,
Vivek Goyal, Alexei Starovoitov, David Herrmann,
Theodore Ts'o, Kee
In-Reply-To: <20150730083831.GA22182-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, Jul 30, 2015 at 9:38 AM, Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>
> * David Drysdale <drysdale-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
>
>> +Designing the API
>> +-----------------
>> +
>> +A new system call forms part of the API of the kernel, and has to be supported
>> +indefinitely. As such, it's a very good idea to explicitly discuss the
>> +interface on the kernel mailing list, and to plan for future extensions of the
>> +interface. In particular:
>> +
>> + **Include a flags argument for every new system call**
>
> Sorry, but I think that's bad avice, because even a 'flags' field is inflexible
> and stupid in many cases - it fosters an 'ioctl' kind of design.
>
>> +The syscall table is littered with historical examples where this wasn't done,
>> +together with the corresponding follow-up system calls (eventfd/eventfd2,
>> +dup2/dup3, inotify_init/inotify_init1, pipe/pipe2, renameat/renameat2), so
>> +learn from the history of the kernel and include a flags argument from the
>> +start.
>
> The syscall table is also littered with system calls that have an argument space
> considerably larger than what 6 parameters can express, where various 'flags' are
> used to bring in different parts of new APIs, in a rather messy way.
>
> The right approach IMHO is to think about how extensible a system call is expected
> to be, and to plan accordingly.
>
> If you are anywhere close to 6 parameters, you should not introduce 'flags' but
> you should _reduce_ the number of parameters to a clean essential of 2 or 3
> parameters and should shuffle parameters out to a separate 'parameters/attributes'
> structure that is passed in by pointer:
>
> SYSCALL_DEFINE2(syscall, int, fd, struct params __user *, params);
>
> And it's the design of 'struct params' that determines future flexibility of the
> interface. A very flexible approach is to not use flags but a 'size' argument:
>
> struct params {
> u32 size;
> u32 param_1;
> u64 param_2;
> u64 param_3;
> };
>
> Where 'size' is set by user-space to the size of 'struct params' known to it at
> build time:
>
> params->size = sizeof(*params);
>
> In the normal case the kernel will get param->size == sizeof(*params) as known to
> the kernel.
>
> When the system call is extended in the future on the kernel side, with 'u64
> param_4', then the structure expands from an old size of 24 to a new size of 32
> bytes. The following scenarios might occur:
>
> - the common case: new user-space calls the new kernel code, ->size is 32 on both
> sides.
>
> - old binaries might call the kernel with params->size == 24, in which case the
> kernel sets the new fields to 0. The new feature should be written
> accordingly, so that a value of 0 means the old behavior.
>
> - new binaries might run on old kernels, with params->size == 32. In this case
> the old kernel will check that all the new fields it does not know about are
> set to 0 - if they are nonzero (if the new feature is used) it returns with
> -ENOSYS or -EINVAL.
>
> With this approach we have both backwards and forwards binary compatibility: new
> binaries will run on old kernels just fine, even if they have ->size set to 32, as
> long as they make use of the features.
>
> This design simplifies application design considerably: as new code can mostly
> forget about old ABIs, there's no multiple versions to be taken care of, there's
> just a single 'struct param' known to both sides, and there's no version skew.
>
> We are using such a design in perf_event_open(), see perf_copy_attr() in
> kernel/events/core.c. And yes, ironically that system call still has a historic
> 'flags' argument, but it's not used anymore for extension: we've made over 30
> extensions to the ABI in the last 3 years, which would have been impossible with a
> 'flags' approach.
>
> Thanks,
>
> Ingo
Fair point, there are other ways to ensure extendability that just the
simple flags
approach -- and as you say, for more sophisticated interfaces flags might hinder
more than they help.
How about the attached text as an attempt to cover both bases?
Thanks,
David
------------------
Designing the API: Planning for Extension
-----------------------------------------
A new system call forms part of the API of the kernel, and has to be supported
indefinitely. As such, it's a very good idea to explicitly discuss the
interface on the kernel mailing list, and it's important to plan for future
extensions of the interface.
(The syscall table is littered with historical examples where this wasn't done,
together with the corresponding follow-up system calls -- eventfd/eventfd2,
dup2/dup3, inotify_init/inotify_init1, pipe/pipe2, renameat/renameat2 -- so
learn from the history of the kernel and plan for extensions from the start.)
For simpler system calls that only take a couple of arguments, the preferred way
to allow for future extensibility is to include a flags argument to the system
call. To make sure that userspace programs can safely use flags between kernel
versions, check whether the flags value holds any unknown flags, and reject the
sycall (with EINVAL) if it does:
if (flags & ~(THING_FLAG1 | THING_FLAG2 | THING_FLAG3))
return -EINVAL;
(If no flags values are used yet, check that the flags argument is zero.)
For more sophisticated system calls that involve a larger number of arguments,
it's preferred to encapsulate the majority of the arguments into a structure
that is passed in by pointer. Such a structure can cope with future extension
by including a size argument in the structure:
struct xyzzy_params {
u32 size; /* userspace sets p->size = sizeof(struct xyzzy_params) */
u32 param_1;
u64 param_2;
u64 param_3;
};
As long as any subsequently added field, say param_4, is designed so that a zero
value gives the previous behaviour, then this allows both directions of version
mismatch:
- To cope with a later userspace program calling an older kernel, the kernel
code should check that any memory beyond the size of the structure that it
expects is zero (effectively checking that param_4 == 0).
- To cope with an older userspace program calling a newer kernel, the kernel
code can zero-extend a smaller instance of the structure (effectively setting
param_4 = 0).
See perf_event_open(2) and the perf_copy_attr() function (in
kernel/events/core.c) for an example of this approach.
^ permalink raw reply
* [PATCH v8 4/6] block: loop: prepare for supporing direct IO
From: Ming Lei @ 2015-07-30 11:36 UTC (permalink / raw)
To: Jens Axboe, linux-kernel, Dave Kleikamp
Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
Alexander Viro, Tejun Heo, Dave Chinner, Ming Lei, linux-api
In-Reply-To: <1438256184-23645-1-git-send-email-ming.lei@canonical.com>
This patches provides one interface for enabling direct IO
from user space:
- userspace(such as losetup) can pass 'file' which is
opened/fcntl as O_DIRECT
Also __loop_update_dio() is introduced to check if direct I/O
can be used on current loop setting.
The last big change is to introduce LO_FLAGS_DIRECT_IO flag
for userspace to know if direct IO is used to access backing
file.
Cc: linux-api@vger.kernel.org
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
drivers/block/loop.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/block/loop.h | 2 ++
include/uapi/linux/loop.h | 1 +
3 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1875aad..799cc23 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
return get_size(lo->lo_offset, lo->lo_sizelimit, file);
}
+static void __loop_update_dio(struct loop_device *lo, bool dio)
+{
+ struct file *file = lo->lo_backing_file;
+ struct inode *inode = file->f_mapping->host;
+ bool use_dio;
+ unsigned dio_align = inode->i_sb->s_bdev ?
+ (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
+
+ /*
+ * We support direct I/O only if lo_offset is aligned
+ * with the min I/O size of backing device.
+ *
+ * Request's offset and size will be checked in I/O path.
+ */
+ if (dio) {
+ if (!dio_align || (lo->lo_offset & dio_align))
+ use_dio = false;
+ else
+ use_dio = true;
+ } else {
+ use_dio = false;
+ }
+
+ /* flush dirty pages before changing direct IO */
+ vfs_fsync(file, 0);
+
+ /*
+ * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
+ * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
+ * will get updated by ioctl(LOOP_GET_STATUS)
+ */
+ blk_mq_freeze_queue(lo->lo_queue);
+ lo->use_dio = use_dio;
+ lo->dio_align = dio_align;
+ if (use_dio)
+ lo->lo_flags |= LO_FLAGS_DIRECT_IO;
+ else
+ lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
+ blk_mq_unfreeze_queue(lo->lo_queue);
+}
+
static int
figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
{
@@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
if (unlikely((loff_t)x != size))
return -EFBIG;
- if (lo->lo_offset != offset)
+ if (lo->lo_offset != offset) {
lo->lo_offset = offset;
+
+ /* update dio if lo_offset is changed*/
+ __loop_update_dio(lo, lo->use_dio);
+ }
if (lo->lo_sizelimit != sizelimit)
lo->lo_sizelimit = sizelimit;
set_capacity(lo->lo_disk, x);
@@ -421,6 +466,11 @@ struct switch_request {
struct completion wait;
};
+static inline void loop_update_dio(struct loop_device *lo)
+{
+ __loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
+}
+
/*
* Do the actual switch; called from the BIO completion routine
*/
@@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
lo->old_gfp_mask = mapping_gfp_mask(mapping);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+ loop_update_dio(lo);
}
/*
@@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
return sprintf(buf, "%s\n", partscan ? "1" : "0");
}
+static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
+{
+ int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
+
+ return sprintf(buf, "%s\n", dio ? "1" : "0");
+}
+
LOOP_ATTR_RO(backing_file);
LOOP_ATTR_RO(offset);
LOOP_ATTR_RO(sizelimit);
LOOP_ATTR_RO(autoclear);
LOOP_ATTR_RO(partscan);
+LOOP_ATTR_RO(dio);
static struct attribute *loop_attrs[] = {
&loop_attr_backing_file.attr,
@@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
&loop_attr_sizelimit.attr,
&loop_attr_autoclear.attr,
&loop_attr_partscan.attr,
+ &loop_attr_dio.attr,
NULL,
};
@@ -783,6 +843,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
blk_queue_flush(lo->lo_queue, REQ_FLUSH);
+ loop_update_dio(lo);
set_capacity(lo->lo_disk, size);
bd_set_size(bdev, size << 9);
loop_sysfs_init(lo);
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index b6c7d21..63f8e14 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -58,6 +58,8 @@ struct loop_device {
struct mutex lo_ctl_mutex;
struct kthread_worker worker;
struct task_struct *worker_task;
+ unsigned dio_align;
+ bool use_dio;
struct request_queue *lo_queue;
struct blk_mq_tag_set tag_set;
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
index e0cecd2..949851c 100644
--- a/include/uapi/linux/loop.h
+++ b/include/uapi/linux/loop.h
@@ -21,6 +21,7 @@ enum {
LO_FLAGS_READ_ONLY = 1,
LO_FLAGS_AUTOCLEAR = 4,
LO_FLAGS_PARTSCAN = 8,
+ LO_FLAGS_DIRECT_IO = 16,
};
#include <asm/posix_types.h> /* for __kernel_old_dev_t */
--
1.9.1
^ permalink raw reply related
* [PATCH v8 5/6] block: loop: introduce ioctl command of LOOP_SET_DIRECT_IO
From: Ming Lei @ 2015-07-30 11:36 UTC (permalink / raw)
To: Jens Axboe, linux-kernel, Dave Kleikamp
Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
Alexander Viro, Tejun Heo, Dave Chinner, Ming Lei, linux-api
In-Reply-To: <1438256184-23645-1-git-send-email-ming.lei@canonical.com>
If loop block is mounted via 'mount -o loop', it isn't easy
to pass file descriptor opened as O_DIRECT, so this patch
introduces a new command to support direct IO for this case.
Cc: linux-api@vger.kernel.org
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
drivers/block/loop.c | 19 +++++++++++++++++++
include/uapi/linux/loop.h | 1 +
2 files changed, 20 insertions(+)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 799cc23..133e4c7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1212,6 +1212,20 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
return figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
}
+static int loop_set_dio(struct loop_device *lo, unsigned long arg)
+{
+ int error = -ENXIO;
+ if (lo->lo_state != Lo_bound)
+ goto out;
+
+ __loop_update_dio(lo, !!arg);
+ if (lo->use_dio == !!arg)
+ return 0;
+ error = -EINVAL;
+ out:
+ return error;
+}
+
static int lo_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
@@ -1255,6 +1269,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
err = loop_set_capacity(lo, bdev);
break;
+ case LOOP_SET_DIRECT_IO:
+ err = -EPERM;
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+ err = loop_set_dio(lo, arg);
+ break;
default:
err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
}
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
index 949851c..c8125ec 100644
--- a/include/uapi/linux/loop.h
+++ b/include/uapi/linux/loop.h
@@ -87,6 +87,7 @@ struct loop_info64 {
#define LOOP_GET_STATUS64 0x4C05
#define LOOP_CHANGE_FD 0x4C06
#define LOOP_SET_CAPACITY 0x4C07
+#define LOOP_SET_DIRECT_IO 0x4C08
/* /dev/loop-control interface */
#define LOOP_CTL_ADD 0x4C80
--
1.9.1
^ permalink raw reply related
* Re: [PATCH nf-next v2] netfilter: nf_ct_sctp: minimal multihoming support
From: Pablo Neira Ayuso @ 2015-07-30 11:54 UTC (permalink / raw)
To: Michal Kubecek
Cc: netfilter-devel, coreteam, linux-api, netdev, linux-kernel,
Patrick McHardy, Jozsef Kadlecsik, David S. Miller,
Florian Westphal, Marcelo Ricardo Leitner
In-Reply-To: <20150717141757.01EBFA0A84@unicorn.suse.cz>
On Fri, Jul 17, 2015 at 04:17:56PM +0200, Michal Kubecek wrote:
> Currently nf_conntrack_proto_sctp module handles only packets between
> primary addresses used to establish the connection. Any packets between
> secondary addresses are classified as invalid so that usual firewall
> configurations drop them. Allowing HEARTBEAT and HEARTBEAT-ACK chunks to
> establish a new conntrack would allow traffic between secondary
> addresses to pass through. A more sophisticated solution based on the
> addresses advertised in the initial handshake (and possibly also later
> dynamic address addition and removal) would be much harder to implement.
> Moreover, in general we cannot assume to always see the initial
> handshake as it can be routed through a different path.
Applied, thanks.
I have remove the chunks below though, see explanation below.
> @@ -705,6 +756,18 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
> .mode = 0644,
> .proc_handler = proc_dointvec_jiffies,
> },
> + {
> + .procname = "ip_conntrack_sctp_timeout_heartbeat_sent",
> + .maxlen = sizeof(unsigned int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec_jiffies,
> + },
> + {
> + .procname = "ip_conntrack_sctp_timeout_heartbeat_acked",
> + .maxlen = sizeof(unsigned int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec_jiffies,
> + },
> { }
> };
> #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
[...]
> @@ -752,6 +817,8 @@ static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
> pn->ctl_compat_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT];
> pn->ctl_compat_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD];
> pn->ctl_compat_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT];
> + pn->ctl_compat_table[7].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_SENT];
> + pn->ctl_compat_table[8].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_ACKED];
> #endif
> #endif
> return 0;
These are part of the compat sysctl interface (those entries that are
prefixed by "ip_conntrack_*) that we should remove at some point (the
new entries that are prefixed by "nf_conntrack_*" has been already
there for a bit less than ~10 years and we got a netlink interface to
configure this for several years already), so better skip those spots.
^ permalink raw reply
* [RFC PATCH] mtd: add an MTD_IS_PARTITION flag
From: Boris Brezillon @ 2015-07-30 12:14 UTC (permalink / raw)
To: David Woodhouse, Brian Norris, linux-mtd
Cc: linux-kernel, linux-api, Boris Brezillon
Add an MTD_IS_PARTITION flag so that the test to check whether an
MTD device is a partition or not is faster.
This also allows user-space programs to know whether they are
manipulating a partition or a real device.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/mtd/mtdpart.c | 14 ++------------
include/uapi/mtd/mtd-abi.h | 1 +
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 919a936..3dc479f 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -370,6 +370,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
/* set up the MTD object for this partition */
slave->mtd.type = master->type;
slave->mtd.flags = master->flags & ~part->mask_flags;
+ slave->mtd.flags |= MTD_IS_PARTITION;
slave->mtd.size = part->size;
slave->mtd.writesize = master->writesize;
slave->mtd.writebufsize = master->writebufsize;
@@ -779,18 +780,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
int mtd_is_partition(const struct mtd_info *mtd)
{
- struct mtd_part *part;
- int ispart = 0;
-
- mutex_lock(&mtd_partitions_mutex);
- list_for_each_entry(part, &mtd_partitions, list)
- if (&part->mtd == mtd) {
- ispart = 1;
- break;
- }
- mutex_unlock(&mtd_partitions_mutex);
-
- return ispart;
+ return mtd->flags & MTD_IS_PARTITION;
}
EXPORT_SYMBOL_GPL(mtd_is_partition);
diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index 763bb69..ffc1903 100644
--- a/include/uapi/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
@@ -103,6 +103,7 @@ struct mtd_write_req {
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
+#define MTD_IS_PARTITION 0x4000 /* Device is an MTD partition */
/* Some common devices / combinations of capabilities */
#define MTD_CAP_ROM 0
--
1.9.1
^ permalink raw reply related
* Re: [PATCH -mm v9 0/8] idle memory tracking
From: Vladimir Davydov @ 2015-07-30 13:01 UTC (permalink / raw)
To: Andrew Morton
Cc: Michal Hocko, Andres Lagar-Cavilla, Minchan Kim, Raghavendra K T,
Johannes Weiner, Greg Thelen, Michel Lespinasse, David Rientjes,
Pavel Emelyanov, Cyrill Gorcunov, Jonathan Corbet,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
cgroups-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150730091212.GA8100@esperanza>
On Thu, Jul 30, 2015 at 12:12:12PM +0300, Vladimir Davydov wrote:
> On Wed, Jul 29, 2015 at 02:30:15PM -0700, Andrew Morton wrote:
> > On Wed, 29 Jul 2015 19:29:08 +0300 Vladimir Davydov <vdavydov-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org> wrote:
> >
> > > /proc/kpageidle should probably live somewhere in /sys/kernel/mm, but I
> > > added it where similar files are located (kpagecount, kpageflags) to
> > > keep things consistent.
> >
> > I think these files should be moved elsewhere. Consistency is good,
> > but not when we're being consistent with a bad thing.
> >
> > So let's place these in /sys/kernel/mm and then start being consistent
> > with that?
>
> I really don't think we should separate kpagecgroup from kpagecount and
> kpageflags, because they look very similar (each of them is read-only,
> contains an array of u64 values referenced by PFN). Scattering these
> files between different filesystems would look ugly IMO.
>
> However, kpageidle is somewhat different (it's read-write, contains a
> bitmap) so I think it's worth moving it to /sys/kernel/mm. We have to
> move the code from fs/proc to mm/something then to remove dependency
> from PROC_FS, which would be unnecessary. Let me give it a try.
Here it goes:
From: Vladimir Davydov <vdavydov-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Subject: [PATCH] Move /proc/kpageidle to /sys/kernel/mm/page_idle/bitmap
Since IDLE_PAGE_TRACKING does not need to depend on PROC_FS anymore,
this patch also moves the code from fs/proc/page.c to mm/page_idle.c and
introduces a dedicated header file include/linux/page_idle.h.
Signed-off-by: Vladimir Davydov <vdavydov-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
diff --git a/Documentation/vm/idle_page_tracking.txt b/Documentation/vm/idle_page_tracking.txt
index d0f332d544c4..85dcc3bb85dc 100644
--- a/Documentation/vm/idle_page_tracking.txt
+++ b/Documentation/vm/idle_page_tracking.txt
@@ -6,10 +6,12 @@ estimating the workload's working set size, which, in turn, can be taken into
account when configuring the workload parameters, setting memory cgroup limits,
or deciding where to place the workload within a compute cluster.
+It is enabled by CONFIG_IDLE_PAGE_TRACKING=y.
+
USER API
-If CONFIG_IDLE_PAGE_TRACKING was enabled on compile time, a new read-write file
-is present on the proc filesystem, /proc/kpageidle.
+The idle page tracking API is located at /sys/kernel/mm/page_idle. Currently,
+it consists of the only read-write file, /sys/kernel/mm/page_idle/bitmap.
The file implements a bitmap where each bit corresponds to a memory page. The
bitmap is represented by an array of 8-byte integers, and the page at PFN #i is
@@ -30,24 +32,25 @@ and hence such pages are never reported idle.
For huge pages the idle flag is set only on the head page, so one has to read
/proc/kpageflags in order to correctly count idle huge pages.
-Reading from or writing to /proc/kpageidle will return -EINVAL if you are not
-starting the read/write on an 8-byte boundary, or if the size of the read/write
-is not a multiple of 8 bytes. Writing to this file beyond max PFN will return
--ENXIO.
+Reading from or writing to /sys/kernel/mm/page_idle/bitmap will return
+-EINVAL if you are not starting the read/write on an 8-byte boundary, or
+if the size of the read/write is not a multiple of 8 bytes. Writing to
+this file beyond max PFN will return -ENXIO.
That said, in order to estimate the amount of pages that are not used by a
workload one should:
- 1. Mark all the workload's pages as idle by setting corresponding bits in the
- /proc/kpageidle bitmap. The pages can be found by reading /proc/pid/pagemap
- if the workload is represented by a process, or by filtering out alien pages
- using /proc/kpagecgroup in case the workload is placed in a memory cgroup.
+ 1. Mark all the workload's pages as idle by setting corresponding bits in
+ /sys/kernel/mm/page_idle/bitmap. The pages can be found by reading
+ /proc/pid/pagemap if the workload is represented by a process, or by
+ filtering out alien pages using /proc/kpagecgroup in case the workload is
+ placed in a memory cgroup.
2. Wait until the workload accesses its working set.
- 3. Read /proc/kpageidle and count the number of bits set. If one wants to
- ignore certain types of pages, e.g. mlocked pages since they are not
- reclaimable, he or she can filter them out using /proc/kpageflags.
+ 3. Read /sys/kernel/mm/page_idle/bitmap and count the number of bits set. If
+ one wants to ignore certain types of pages, e.g. mlocked pages since they
+ are not reclaimable, he or she can filter them out using /proc/kpageflags.
See Documentation/vm/pagemap.txt for more information about /proc/pid/pagemap,
/proc/kpageflags, and /proc/kpagecgroup.
@@ -74,8 +77,9 @@ When a dirty page is written to swap or disk as a result of memory reclaim or
exceeding the dirty memory limit, it is not marked referenced.
The idle memory tracking feature adds a new page flag, the Idle flag. This flag
-is set manually, by writing to /proc/kpageidle (see the USER API section), and
-cleared automatically whenever a page is referenced as defined above.
+is set manually, by writing to /sys/kernel/mm/page_idle/bitmap (see the USER API
+section), and cleared automatically whenever a page is referenced as defined
+above.
When a page is marked idle, the Accessed bit must be cleared in all PTEs it is
mapped to, otherwise we will not be able to detect accesses to the page coming
@@ -90,5 +94,5 @@ Since the idle memory tracking feature is based on the memory reclaimer logic,
it only works with pages that are on an LRU list, other pages are silently
ignored. That means it will ignore a user memory page if it is isolated, but
since there are usually not many of them, it should not affect the overall
-result noticeably. In order not to stall scanning of /proc/kpageidle, locked
-pages may be skipped too.
+result noticeably. In order not to stall scanning of the idle page bitmap,
+locked pages may be skipped too.
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt
index 8ed148d17c2e..0e1e55588b59 100644
--- a/Documentation/vm/pagemap.txt
+++ b/Documentation/vm/pagemap.txt
@@ -5,7 +5,7 @@ pagemap is a new (as of 2.6.25) set of interfaces in the kernel that allow
userspace programs to examine the page tables and related information by
reading files in /proc.
-There are five components to pagemap:
+There are four components to pagemap:
* /proc/pid/pagemap. This file lets a userspace process find out which
physical frame each virtual page is mapped to. It contains one 64-bit
@@ -76,9 +76,6 @@ There are five components to pagemap:
memory cgroup each page is charged to, indexed by PFN. Only available when
CONFIG_MEMCG is set.
- * /proc/kpageidle. This file comprises API of the idle page tracking feature.
- See Documentation/vm/idle_page_tracking.txt for more details.
-
Short descriptions to the page flags:
0. LOCKED
@@ -125,9 +122,10 @@ Short descriptions to the page flags:
zero page for pfn_zero or huge_zero page
25. IDLE
- page has not been accessed since it was marked idle (see /proc/kpageidle)
- Note that this flag may be stale in case the page was accessed via a PTE.
- To make sure the flag is up-to-date one has to read /proc/kpageidle first.
+ page has not been accessed since it was marked idle (see
+ Documentation/vm/idle_page_tracking.txt). Note that this flag may be
+ stale in case the page was accessed via a PTE. To make sure the flag
+ is up-to-date one has to read /sys/kernel/mm/page_idle/bitmap first.
[IO related page flags]
1. ERROR IO error occurred
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 4191ddb79b84..72c604b876e4 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -5,20 +5,18 @@
#include <linux/ksm.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
-#include <linux/rmap.h>
-#include <linux/mmu_notifier.h>
#include <linux/huge_mm.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/hugetlb.h>
#include <linux/memcontrol.h>
+#include <linux/page_idle.h>
#include <linux/kernel-page-flags.h>
#include <asm/uaccess.h>
#include "internal.h"
#define KPMSIZE sizeof(u64)
#define KPMMASK (KPMSIZE - 1)
-#define KPMBITS (KPMSIZE * BITS_PER_BYTE)
/* /proc/kpagecount - an array exposing page counts
*
@@ -287,223 +285,6 @@ static const struct file_operations proc_kpagecgroup_operations = {
};
#endif /* CONFIG_MEMCG */
-#ifdef CONFIG_IDLE_PAGE_TRACKING
-/*
- * Idle page tracking only considers user memory pages, for other types of
- * pages the idle flag is always unset and an attempt to set it is silently
- * ignored.
- *
- * We treat a page as a user memory page if it is on an LRU list, because it is
- * always safe to pass such a page to rmap_walk(), which is essential for idle
- * page tracking. With such an indicator of user pages we can skip isolated
- * pages, but since there are not usually many of them, it will hardly affect
- * the overall result.
- *
- * This function tries to get a user memory page by pfn as described above.
- */
-static struct page *kpageidle_get_page(unsigned long pfn)
-{
- struct page *page;
- struct zone *zone;
-
- if (!pfn_valid(pfn))
- return NULL;
-
- page = pfn_to_page(pfn);
- if (!page || !PageLRU(page) ||
- !get_page_unless_zero(page))
- return NULL;
-
- zone = page_zone(page);
- spin_lock_irq(&zone->lru_lock);
- if (unlikely(!PageLRU(page))) {
- put_page(page);
- page = NULL;
- }
- spin_unlock_irq(&zone->lru_lock);
- return page;
-}
-
-static int kpageidle_clear_pte_refs_one(struct page *page,
- struct vm_area_struct *vma,
- unsigned long addr, void *arg)
-{
- struct mm_struct *mm = vma->vm_mm;
- spinlock_t *ptl;
- pmd_t *pmd;
- pte_t *pte;
- bool referenced = false;
-
- if (unlikely(PageTransHuge(page))) {
- pmd = page_check_address_pmd(page, mm, addr,
- PAGE_CHECK_ADDRESS_PMD_FLAG, &ptl);
- if (pmd) {
- referenced = pmdp_clear_young_notify(vma, addr, pmd);
- spin_unlock(ptl);
- }
- } else {
- pte = page_check_address(page, mm, addr, &ptl, 0);
- if (pte) {
- referenced = ptep_clear_young_notify(vma, addr, pte);
- pte_unmap_unlock(pte, ptl);
- }
- }
- if (referenced) {
- clear_page_idle(page);
- /*
- * We cleared the referenced bit in a mapping to this page. To
- * avoid interference with page reclaim, mark it young so that
- * page_referenced() will return > 0.
- */
- set_page_young(page);
- }
- return SWAP_AGAIN;
-}
-
-static void kpageidle_clear_pte_refs(struct page *page)
-{
- /*
- * Since rwc.arg is unused, rwc is effectively immutable, so we
- * can make it static const to save some cycles and stack.
- */
- static const struct rmap_walk_control rwc = {
- .rmap_one = kpageidle_clear_pte_refs_one,
- .anon_lock = page_lock_anon_vma_read,
- };
- bool need_lock;
-
- if (!page_mapped(page) ||
- !page_rmapping(page))
- return;
-
- need_lock = !PageAnon(page) || PageKsm(page);
- if (need_lock && !trylock_page(page))
- return;
-
- rmap_walk(page, (struct rmap_walk_control *)&rwc);
-
- if (need_lock)
- unlock_page(page);
-}
-
-static ssize_t kpageidle_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- u64 __user *out = (u64 __user *)buf;
- struct page *page;
- unsigned long pfn, end_pfn;
- ssize_t ret = 0;
- u64 idle_bitmap = 0;
- int bit;
-
- if (*ppos & KPMMASK || count & KPMMASK)
- return -EINVAL;
-
- pfn = *ppos * BITS_PER_BYTE;
- if (pfn >= max_pfn)
- return 0;
-
- end_pfn = pfn + count * BITS_PER_BYTE;
- if (end_pfn > max_pfn)
- end_pfn = ALIGN(max_pfn, KPMBITS);
-
- for (; pfn < end_pfn; pfn++) {
- bit = pfn % KPMBITS;
- page = kpageidle_get_page(pfn);
- if (page) {
- if (page_is_idle(page)) {
- /*
- * The page might have been referenced via a
- * pte, in which case it is not idle. Clear
- * refs and recheck.
- */
- kpageidle_clear_pte_refs(page);
- if (page_is_idle(page))
- idle_bitmap |= 1ULL << bit;
- }
- put_page(page);
- }
- if (bit == KPMBITS - 1) {
- if (put_user(idle_bitmap, out)) {
- ret = -EFAULT;
- break;
- }
- idle_bitmap = 0;
- out++;
- }
- cond_resched();
- }
-
- *ppos += (char __user *)out - buf;
- if (!ret)
- ret = (char __user *)out - buf;
- return ret;
-}
-
-static ssize_t kpageidle_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- const u64 __user *in = (const u64 __user *)buf;
- struct page *page;
- unsigned long pfn, end_pfn;
- ssize_t ret = 0;
- u64 idle_bitmap = 0;
- int bit;
-
- if (*ppos & KPMMASK || count & KPMMASK)
- return -EINVAL;
-
- pfn = *ppos * BITS_PER_BYTE;
- if (pfn >= max_pfn)
- return -ENXIO;
-
- end_pfn = pfn + count * BITS_PER_BYTE;
- if (end_pfn > max_pfn)
- end_pfn = ALIGN(max_pfn, KPMBITS);
-
- for (; pfn < end_pfn; pfn++) {
- bit = pfn % KPMBITS;
- if (bit == 0) {
- if (copy_from_user(&idle_bitmap, in, sizeof(u64))) {
- ret = -EFAULT;
- break;
- }
- in++;
- }
- if ((idle_bitmap >> bit) & 1) {
- page = kpageidle_get_page(pfn);
- if (page) {
- kpageidle_clear_pte_refs(page);
- set_page_idle(page);
- put_page(page);
- }
- }
- cond_resched();
- }
-
- *ppos += (const char __user *)in - buf;
- if (!ret)
- ret = (const char __user *)in - buf;
- return ret;
-}
-
-static const struct file_operations proc_kpageidle_operations = {
- .llseek = mem_lseek,
- .read = kpageidle_read,
- .write = kpageidle_write,
-};
-
-#ifndef CONFIG_64BIT
-static bool need_page_idle(void)
-{
- return true;
-}
-struct page_ext_operations page_idle_ops = {
- .need = need_page_idle,
-};
-#endif
-#endif /* CONFIG_IDLE_PAGE_TRACKING */
-
static int __init proc_page_init(void)
{
proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
@@ -511,10 +292,6 @@ static int __init proc_page_init(void)
#ifdef CONFIG_MEMCG
proc_create("kpagecgroup", S_IRUSR, NULL, &proc_kpagecgroup_operations);
#endif
-#ifdef CONFIG_IDLE_PAGE_TRACKING
- proc_create("kpageidle", S_IRUSR | S_IWUSR, NULL,
- &proc_kpageidle_operations);
-#endif
return 0;
}
fs_initcall(proc_page_init);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7c9a17414106..bdd7e48a85f0 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -13,6 +13,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/mmu_notifier.h>
+#include <linux/page_idle.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5e08787c92df..363ea2cda35f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2199,103 +2199,5 @@ void __init setup_nr_node_ids(void);
static inline void setup_nr_node_ids(void) {}
#endif
-#ifdef CONFIG_IDLE_PAGE_TRACKING
-#ifdef CONFIG_64BIT
-static inline bool page_is_young(struct page *page)
-{
- return PageYoung(page);
-}
-
-static inline void set_page_young(struct page *page)
-{
- SetPageYoung(page);
-}
-
-static inline bool test_and_clear_page_young(struct page *page)
-{
- return TestClearPageYoung(page);
-}
-
-static inline bool page_is_idle(struct page *page)
-{
- return PageIdle(page);
-}
-
-static inline void set_page_idle(struct page *page)
-{
- SetPageIdle(page);
-}
-
-static inline void clear_page_idle(struct page *page)
-{
- ClearPageIdle(page);
-}
-#else /* !CONFIG_64BIT */
-/*
- * If there is not enough space to store Idle and Young bits in page flags, use
- * page ext flags instead.
- */
-extern struct page_ext_operations page_idle_ops;
-
-static inline bool page_is_young(struct page *page)
-{
- return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
-}
-
-static inline void set_page_young(struct page *page)
-{
- set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
-}
-
-static inline bool test_and_clear_page_young(struct page *page)
-{
- return test_and_clear_bit(PAGE_EXT_YOUNG,
- &lookup_page_ext(page)->flags);
-}
-
-static inline bool page_is_idle(struct page *page)
-{
- return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
-}
-
-static inline void set_page_idle(struct page *page)
-{
- set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
-}
-
-static inline void clear_page_idle(struct page *page)
-{
- clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
-}
-#endif /* CONFIG_64BIT */
-#else /* !CONFIG_IDLE_PAGE_TRACKING */
-static inline bool page_is_young(struct page *page)
-{
- return false;
-}
-
-static inline void set_page_young(struct page *page)
-{
-}
-
-static inline bool test_and_clear_page_young(struct page *page)
-{
- return false;
-}
-
-static inline bool page_is_idle(struct page *page)
-{
- return false;
-}
-
-static inline void set_page_idle(struct page *page)
-{
-}
-
-static inline void clear_page_idle(struct page *page)
-{
-}
-#endif /* CONFIG_IDLE_PAGE_TRACKING */
-
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h
new file mode 100644
index 000000000000..bf268fa92c5b
--- /dev/null
+++ b/include/linux/page_idle.h
@@ -0,0 +1,110 @@
+#ifndef _LINUX_MM_PAGE_IDLE_H
+#define _LINUX_MM_PAGE_IDLE_H
+
+#include <linux/bitops.h>
+#include <linux/page-flags.h>
+#include <linux/page_ext.h>
+
+#ifdef CONFIG_IDLE_PAGE_TRACKING
+
+#ifdef CONFIG_64BIT
+static inline bool page_is_young(struct page *page)
+{
+ return PageYoung(page);
+}
+
+static inline void set_page_young(struct page *page)
+{
+ SetPageYoung(page);
+}
+
+static inline bool test_and_clear_page_young(struct page *page)
+{
+ return TestClearPageYoung(page);
+}
+
+static inline bool page_is_idle(struct page *page)
+{
+ return PageIdle(page);
+}
+
+static inline void set_page_idle(struct page *page)
+{
+ SetPageIdle(page);
+}
+
+static inline void clear_page_idle(struct page *page)
+{
+ ClearPageIdle(page);
+}
+#else /* !CONFIG_64BIT */
+/*
+ * If there is not enough space to store Idle and Young bits in page flags, use
+ * page ext flags instead.
+ */
+extern struct page_ext_operations page_idle_ops;
+
+static inline bool page_is_young(struct page *page)
+{
+ return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
+}
+
+static inline void set_page_young(struct page *page)
+{
+ set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags);
+}
+
+static inline bool test_and_clear_page_young(struct page *page)
+{
+ return test_and_clear_bit(PAGE_EXT_YOUNG,
+ &lookup_page_ext(page)->flags);
+}
+
+static inline bool page_is_idle(struct page *page)
+{
+ return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+}
+
+static inline void set_page_idle(struct page *page)
+{
+ set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+}
+
+static inline void clear_page_idle(struct page *page)
+{
+ clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags);
+}
+#endif /* CONFIG_64BIT */
+
+#else /* !CONFIG_IDLE_PAGE_TRACKING */
+
+static inline bool page_is_young(struct page *page)
+{
+ return false;
+}
+
+static inline void set_page_young(struct page *page)
+{
+}
+
+static inline bool test_and_clear_page_young(struct page *page)
+{
+ return false;
+}
+
+static inline bool page_is_idle(struct page *page)
+{
+ return false;
+}
+
+static inline void set_page_idle(struct page *page)
+{
+}
+
+static inline void clear_page_idle(struct page *page)
+{
+}
+
+#endif /* CONFIG_IDLE_PAGE_TRACKING */
+
+#endif /* _LINUX_MM_PAGE_IDLE_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index 7482b60e927f..fe133a98a9ef 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -651,8 +651,7 @@ config DEFERRED_STRUCT_PAGE_INIT
config IDLE_PAGE_TRACKING
bool "Enable idle page tracking"
- depends on PROC_FS && MMU
- select PROC_PAGE_MONITOR
+ depends on SYSFS
select PAGE_EXTENSION if !64BIT
help
This feature allows to estimate the amount of user pages that have
diff --git a/mm/Makefile b/mm/Makefile
index b424d5e5b6ff..56f8eed73f1a 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -79,3 +79,4 @@ obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
+obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index aa58a326d238..1ce276ac4e0c 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -25,6 +25,7 @@
#include <linux/migrate.h>
#include <linux/hashtable.h>
#include <linux/userfaultfd_k.h>
+#include <linux/page_idle.h>
#include <asm/tlb.h>
#include <asm/pgalloc.h>
diff --git a/mm/migrate.c b/mm/migrate.c
index d86cec005aa6..1f887f594cc6 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -37,6 +37,7 @@
#include <linux/gfp.h>
#include <linux/balloon_compaction.h>
#include <linux/mmu_notifier.h>
+#include <linux/page_idle.h>
#include <asm/tlbflush.h>
diff --git a/mm/page_ext.c b/mm/page_ext.c
index e4b3af054bf2..292ca7b8debd 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -6,6 +6,7 @@
#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
#include <linux/page_owner.h>
+#include <linux/page_idle.h>
/*
* struct page extension
diff --git a/mm/page_idle.c b/mm/page_idle.c
new file mode 100644
index 000000000000..d5dd79041484
--- /dev/null
+++ b/mm/page_idle.c
@@ -0,0 +1,232 @@
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/pagemap.h>
+#include <linux/rmap.h>
+#include <linux/mmu_notifier.h>
+#include <linux/page_ext.h>
+#include <linux/page_idle.h>
+
+#define BITMAP_CHUNK_SIZE sizeof(u64)
+#define BITMAP_CHUNK_BITS (BITMAP_CHUNK_SIZE * BITS_PER_BYTE)
+
+/*
+ * Idle page tracking only considers user memory pages, for other types of
+ * pages the idle flag is always unset and an attempt to set it is silently
+ * ignored.
+ *
+ * We treat a page as a user memory page if it is on an LRU list, because it is
+ * always safe to pass such a page to rmap_walk(), which is essential for idle
+ * page tracking. With such an indicator of user pages we can skip isolated
+ * pages, but since there are not usually many of them, it will hardly affect
+ * the overall result.
+ *
+ * This function tries to get a user memory page by pfn as described above.
+ */
+static struct page *page_idle_get_page(unsigned long pfn)
+{
+ struct page *page;
+ struct zone *zone;
+
+ if (!pfn_valid(pfn))
+ return NULL;
+
+ page = pfn_to_page(pfn);
+ if (!page || !PageLRU(page) ||
+ !get_page_unless_zero(page))
+ return NULL;
+
+ zone = page_zone(page);
+ spin_lock_irq(&zone->lru_lock);
+ if (unlikely(!PageLRU(page))) {
+ put_page(page);
+ page = NULL;
+ }
+ spin_unlock_irq(&zone->lru_lock);
+ return page;
+}
+
+static int page_idle_clear_pte_refs_one(struct page *page,
+ struct vm_area_struct *vma,
+ unsigned long addr, void *arg)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ spinlock_t *ptl;
+ pmd_t *pmd;
+ pte_t *pte;
+ bool referenced = false;
+
+ if (unlikely(PageTransHuge(page))) {
+ pmd = page_check_address_pmd(page, mm, addr,
+ PAGE_CHECK_ADDRESS_PMD_FLAG, &ptl);
+ if (pmd) {
+ referenced = pmdp_clear_young_notify(vma, addr, pmd);
+ spin_unlock(ptl);
+ }
+ } else {
+ pte = page_check_address(page, mm, addr, &ptl, 0);
+ if (pte) {
+ referenced = ptep_clear_young_notify(vma, addr, pte);
+ pte_unmap_unlock(pte, ptl);
+ }
+ }
+ if (referenced) {
+ clear_page_idle(page);
+ /*
+ * We cleared the referenced bit in a mapping to this page. To
+ * avoid interference with page reclaim, mark it young so that
+ * page_referenced() will return > 0.
+ */
+ set_page_young(page);
+ }
+ return SWAP_AGAIN;
+}
+
+static void page_idle_clear_pte_refs(struct page *page)
+{
+ /*
+ * Since rwc.arg is unused, rwc is effectively immutable, so we
+ * can make it static const to save some cycles and stack.
+ */
+ static const struct rmap_walk_control rwc = {
+ .rmap_one = page_idle_clear_pte_refs_one,
+ .anon_lock = page_lock_anon_vma_read,
+ };
+ bool need_lock;
+
+ if (!page_mapped(page) ||
+ !page_rmapping(page))
+ return;
+
+ need_lock = !PageAnon(page) || PageKsm(page);
+ if (need_lock && !trylock_page(page))
+ return;
+
+ rmap_walk(page, (struct rmap_walk_control *)&rwc);
+
+ if (need_lock)
+ unlock_page(page);
+}
+
+static ssize_t page_idle_bitmap_read(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ u64 *out = (u64 *)buf;
+ struct page *page;
+ unsigned long pfn, end_pfn;
+ int bit;
+
+ if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE)
+ return -EINVAL;
+
+ pfn = pos * BITS_PER_BYTE;
+ if (pfn >= max_pfn)
+ return 0;
+
+ end_pfn = pfn + count * BITS_PER_BYTE;
+ if (end_pfn > max_pfn)
+ end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+
+ for (; pfn < end_pfn; pfn++) {
+ bit = pfn % BITMAP_CHUNK_BITS;
+ if (!bit)
+ *out = 0ULL;
+ page = page_idle_get_page(pfn);
+ if (page) {
+ if (page_is_idle(page)) {
+ /*
+ * The page might have been referenced via a
+ * pte, in which case it is not idle. Clear
+ * refs and recheck.
+ */
+ page_idle_clear_pte_refs(page);
+ if (page_is_idle(page))
+ *out |= 1ULL << bit;
+ }
+ put_page(page);
+ }
+ if (bit == BITMAP_CHUNK_BITS - 1)
+ out++;
+ cond_resched();
+ }
+ return (char *)out - buf;
+}
+
+static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ const u64 *in = (u64 *)buf;
+ struct page *page;
+ unsigned long pfn, end_pfn;
+ int bit;
+
+ if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE)
+ return -EINVAL;
+
+ pfn = pos * BITS_PER_BYTE;
+ if (pfn >= max_pfn)
+ return -ENXIO;
+
+ end_pfn = pfn + count * BITS_PER_BYTE;
+ if (end_pfn > max_pfn)
+ end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS);
+
+ for (; pfn < end_pfn; pfn++) {
+ bit = pfn % BITMAP_CHUNK_BITS;
+ if ((*in >> bit) & 1) {
+ page = page_idle_get_page(pfn);
+ if (page) {
+ page_idle_clear_pte_refs(page);
+ set_page_idle(page);
+ put_page(page);
+ }
+ }
+ if (bit == BITMAP_CHUNK_BITS - 1)
+ in++;
+ cond_resched();
+ }
+ return (char *)in - buf;
+}
+
+static struct bin_attribute page_idle_bitmap_attr =
+ __BIN_ATTR(bitmap, S_IRUSR | S_IWUSR,
+ page_idle_bitmap_read, page_idle_bitmap_write, 0);
+
+static struct bin_attribute *page_idle_bin_attrs[] = {
+ &page_idle_bitmap_attr,
+ NULL,
+};
+
+static struct attribute_group page_idle_attr_group = {
+ .bin_attrs = page_idle_bin_attrs,
+ .name = "page_idle",
+};
+
+#ifndef CONFIG_64BIT
+static bool need_page_idle(void)
+{
+ return true;
+}
+struct page_ext_operations page_idle_ops = {
+ .need = need_page_idle,
+};
+#endif
+
+static int __init page_idle_init(void)
+{
+ int err;
+
+ err = sysfs_create_group(mm_kobj, &page_idle_attr_group);
+ if (err) {
+ pr_err("page_idle: register sysfs failed\n");
+ return err;
+ }
+ return 0;
+}
+subsys_initcall(page_idle_init);
diff --git a/mm/rmap.c b/mm/rmap.c
index b6db6a676f6f..dcaad464aab0 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -59,6 +59,7 @@
#include <linux/migrate.h>
#include <linux/hugetlb.h>
#include <linux/backing-dev.h>
+#include <linux/page_idle.h>
#include <asm/tlbflush.h>
diff --git a/mm/swap.c b/mm/swap.c
index db43c9b4891d..4a6aec976ab1 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -32,6 +32,7 @@
#include <linux/gfp.h>
#include <linux/uio.h>
#include <linux/hugetlb.h>
+#include <linux/page_idle.h>
#include "internal.h"
^ permalink raw reply related
* Re: [PATCH V6 6/6] mips: Add entry for new mlock2 syscall
From: Ralf Baechle @ 2015-07-30 14:32 UTC (permalink / raw)
To: Eric B Munson
Cc: Andrew Morton, linux-mips, linux-api, linux-arch, linux-mm,
linux-kernel
In-Reply-To: <1438184575-10537-7-git-send-email-emunson@akamai.com>
On Wed, Jul 29, 2015 at 11:42:55AM -0400, Eric B Munson wrote:
> A previous commit introduced the new mlock2 syscall, add entries for the
> MIPS architecture.
Looking good, so
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Recently somebody else was floating around a patch that was adding
three syscalls. Not sure if in the end the adding the syscall part to
non-x86 was dropped. Just mentioning in case there are any conflicts;
in particulary nobody should rely on syscall numbers unless they're
for something in Linus' tree!
Ralf
^ permalink raw reply
* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
From: Christoph Hellwig @ 2015-07-30 15:09 UTC (permalink / raw)
To: Ming Lei
Cc: Jens Axboe, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dave Kleikamp,
Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
Alexander Viro, Tejun Heo, Dave Chinner,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
On Thu, Jul 30, 2015 at 07:36:22AM -0400, Ming Lei wrote:
> This patches provides one interface for enabling direct IO
> from user space:
>
> - userspace(such as losetup) can pass 'file' which is
> opened/fcntl as O_DIRECT
>
> Also __loop_update_dio() is introduced to check if direct I/O
> can be used on current loop setting.
>
> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
> for userspace to know if direct IO is used to access backing
> file.
Maybe i'm missing something because I was too busy to follow the
current discussion, but this still doesn't check that the loop
device sector size is aligned to the sector size of the underlying
filesystem.
E.g. with this you could create a loop device with a 512 byte
sector size on a filesystem with 4k sector size, and it would attempt
to use direct I/O and fail.
> + unsigned dio_align = inode->i_sb->s_bdev ?
> + (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
> +
> + /*
> + * We support direct I/O only if lo_offset is aligned
> + * with the min I/O size of backing device.
> + *
> + * Request's offset and size will be checked in I/O path.
> + */
> + if (dio) {
> + if (!dio_align || (lo->lo_offset & dio_align))
> + use_dio = false;
Also this means you'll never use direct I/O on network filesystems,
which really would benefit from it.
^ permalink raw reply
* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
From: Ming Lei @ 2015-07-30 15:21 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Jens Axboe, Linux Kernel Mailing List, Dave Kleikamp, Zach Brown,
Maxim Patlasov, Andrew Morton, Alexander Viro, Tejun Heo,
Dave Chinner, linux-api
In-Reply-To: <20150730150900.GA13082@infradead.org>
On Thu, Jul 30, 2015 at 11:09 AM, Christoph Hellwig <hch@infradead.org> wrote:
> On Thu, Jul 30, 2015 at 07:36:22AM -0400, Ming Lei wrote:
>> This patches provides one interface for enabling direct IO
>> from user space:
>>
>> - userspace(such as losetup) can pass 'file' which is
>> opened/fcntl as O_DIRECT
>>
>> Also __loop_update_dio() is introduced to check if direct I/O
>> can be used on current loop setting.
>>
>> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
>> for userspace to know if direct IO is used to access backing
>> file.
>
> Maybe i'm missing something because I was too busy to follow the
> current discussion, but this still doesn't check that the loop
> device sector size is aligned to the sector size of the underlying
> filesystem.
>
> E.g. with this you could create a loop device with a 512 byte
> sector size on a filesystem with 4k sector size, and it would attempt
> to use direct I/O and fail.
The I/O size & offset has to be checked in I/O path, see patch 6 please,
could you comment on that patch?
>
>> + unsigned dio_align = inode->i_sb->s_bdev ?
>> + (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
>> +
>> + /*
>> + * We support direct I/O only if lo_offset is aligned
>> + * with the min I/O size of backing device.
>> + *
>> + * Request's offset and size will be checked in I/O path.
>> + */
>> + if (dio) {
>> + if (!dio_align || (lo->lo_offset & dio_align))
>> + use_dio = false;
>
> Also this means you'll never use direct I/O on network filesystems,
> which really would benefit from it.
OK, that can be done by removing !dio_align in above check.
Thanks,
^ permalink raw reply
* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
From: Dave Kleikamp @ 2015-07-30 15:30 UTC (permalink / raw)
To: Ming Lei, Jens Axboe, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Zach Brown, Christoph Hellwig, Maxim Patlasov, Andrew Morton,
Alexander Viro, Tejun Heo, Dave Chinner,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1438256184-23645-5-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
On 07/30/2015 06:36 AM, Ming Lei wrote:
> This patches provides one interface for enabling direct IO
> from user space:
>
> - userspace(such as losetup) can pass 'file' which is
> opened/fcntl as O_DIRECT
>
> Also __loop_update_dio() is introduced to check if direct I/O
> can be used on current loop setting.
>
> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
> for userspace to know if direct IO is used to access backing
> file.
lo->use_dio and LO_FLAGS_DIRECT_IO seem redundant. Wouldn't it be
simpler to use one or the other?
>
> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Signed-off-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> ---
> drivers/block/loop.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
> drivers/block/loop.h | 2 ++
> include/uapi/linux/loop.h | 1 +
> 3 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 1875aad..799cc23 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
> return get_size(lo->lo_offset, lo->lo_sizelimit, file);
> }
>
> +static void __loop_update_dio(struct loop_device *lo, bool dio)
> +{
> + struct file *file = lo->lo_backing_file;
> + struct inode *inode = file->f_mapping->host;
> + bool use_dio;
> + unsigned dio_align = inode->i_sb->s_bdev ?
> + (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
> +
> + /*
> + * We support direct I/O only if lo_offset is aligned
> + * with the min I/O size of backing device.
> + *
> + * Request's offset and size will be checked in I/O path.
> + */
> + if (dio) {
> + if (!dio_align || (lo->lo_offset & dio_align))
> + use_dio = false;
> + else
> + use_dio = true;
> + } else {
> + use_dio = false;
> + }
> +
> + /* flush dirty pages before changing direct IO */
> + vfs_fsync(file, 0);
> +
> + /*
> + * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
> + * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
> + * will get updated by ioctl(LOOP_GET_STATUS)
> + */
> + blk_mq_freeze_queue(lo->lo_queue);
> + lo->use_dio = use_dio;
> + lo->dio_align = dio_align;
> + if (use_dio)
> + lo->lo_flags |= LO_FLAGS_DIRECT_IO;
> + else
> + lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
> + blk_mq_unfreeze_queue(lo->lo_queue);
> +}
> +
> static int
> figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
> {
> @@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>
> if (unlikely((loff_t)x != size))
> return -EFBIG;
> - if (lo->lo_offset != offset)
> + if (lo->lo_offset != offset) {
> lo->lo_offset = offset;
> +
> + /* update dio if lo_offset is changed*/
> + __loop_update_dio(lo, lo->use_dio);
> + }
> if (lo->lo_sizelimit != sizelimit)
> lo->lo_sizelimit = sizelimit;
> set_capacity(lo->lo_disk, x);
> @@ -421,6 +466,11 @@ struct switch_request {
> struct completion wait;
> };
>
> +static inline void loop_update_dio(struct loop_device *lo)
> +{
> + __loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
> +}
> +
> /*
> * Do the actual switch; called from the BIO completion routine
> */
> @@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
> mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
> lo->old_gfp_mask = mapping_gfp_mask(mapping);
> mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
> + loop_update_dio(lo);
> }
>
> /*
> @@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
> return sprintf(buf, "%s\n", partscan ? "1" : "0");
> }
>
> +static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
> +{
> + int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
> +
> + return sprintf(buf, "%s\n", dio ? "1" : "0");
> +}
> +
> LOOP_ATTR_RO(backing_file);
> LOOP_ATTR_RO(offset);
> LOOP_ATTR_RO(sizelimit);
> LOOP_ATTR_RO(autoclear);
> LOOP_ATTR_RO(partscan);
> +LOOP_ATTR_RO(dio);
>
> static struct attribute *loop_attrs[] = {
> &loop_attr_backing_file.attr,
> @@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
> &loop_attr_sizelimit.attr,
> &loop_attr_autoclear.attr,
> &loop_attr_partscan.attr,
> + &loop_attr_dio.attr,
> NULL,
> };
>
> @@ -783,6 +843,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
> if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
> blk_queue_flush(lo->lo_queue, REQ_FLUSH);
>
> + loop_update_dio(lo);
> set_capacity(lo->lo_disk, size);
> bd_set_size(bdev, size << 9);
> loop_sysfs_init(lo);
> diff --git a/drivers/block/loop.h b/drivers/block/loop.h
> index b6c7d21..63f8e14 100644
> --- a/drivers/block/loop.h
> +++ b/drivers/block/loop.h
> @@ -58,6 +58,8 @@ struct loop_device {
> struct mutex lo_ctl_mutex;
> struct kthread_worker worker;
> struct task_struct *worker_task;
> + unsigned dio_align;
> + bool use_dio;
>
> struct request_queue *lo_queue;
> struct blk_mq_tag_set tag_set;
> diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
> index e0cecd2..949851c 100644
> --- a/include/uapi/linux/loop.h
> +++ b/include/uapi/linux/loop.h
> @@ -21,6 +21,7 @@ enum {
> LO_FLAGS_READ_ONLY = 1,
> LO_FLAGS_AUTOCLEAR = 4,
> LO_FLAGS_PARTSCAN = 8,
> + LO_FLAGS_DIRECT_IO = 16,
> };
>
> #include <asm/posix_types.h> /* for __kernel_old_dev_t */
>
^ permalink raw reply
* [PATCH] userfaultfd: register syscall numbers for x86 32bit and x86-64 64bit
From: Andrea Arcangeli @ 2015-07-30 15:34 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Stephen Rothwell, Andrew Morton, Ingo Molnar,
\"H. Peter Anvin\", Peter Zijlstra, linux-next, linux-api,
linux-kernel, Andy Lutomirski, Eric B Munson, Pavel Emelyanov,
\"Dr. David Alan Gilbert\"
This registers the official numbers of the userfaultfd syscall for x86
32bit and x86-64 64bit. This registration allows to ship kernels in
production using these two syscall numbers for userfaultfd.
Acked-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
include/linux/syscalls.h | 1 +
kernel/sys_ni.c | 1 +
4 files changed, 4 insertions(+)
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 25e3cf1..178c5c2 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -380,3 +380,4 @@
371 i386 recvfrom sys_recvfrom compat_sys_recvfrom
372 i386 recvmsg sys_recvmsg compat_sys_recvmsg
373 i386 shutdown sys_shutdown
+374 i386 userfaultfd sys_userfaultfd
\ No newline at end of file
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 9ef32d5..81c4906 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -329,6 +329,7 @@
320 common kexec_file_load sys_kexec_file_load
321 common bpf sys_bpf
322 64 execveat stub_execveat
+323 common userfaultfd sys_userfaultfd
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index b45c45b..0800131 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -810,6 +810,7 @@ asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr);
asmlinkage long sys_eventfd(unsigned int count);
asmlinkage long sys_eventfd2(unsigned int count, int flags);
asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags);
+asmlinkage long sys_userfaultfd(int flags);
asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int);
asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 7995ef5..8b3e10ea 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -218,6 +218,7 @@ cond_syscall(compat_sys_timerfd_gettime);
cond_syscall(sys_eventfd);
cond_syscall(sys_eventfd2);
cond_syscall(sys_memfd_create);
+cond_syscall(sys_userfaultfd);
/* performance counters: */
cond_syscall(sys_perf_event_open);
^ permalink raw reply related
* Re: [PATCH v8 4/6] block: loop: prepare for supporing direct IO
From: Ming Lei @ 2015-07-30 15:45 UTC (permalink / raw)
To: Dave Kleikamp
Cc: Jens Axboe, Linux Kernel Mailing List, Zach Brown,
Christoph Hellwig, Maxim Patlasov, Andrew Morton, Alexander Viro,
Tejun Heo, Dave Chinner, linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <55BA432F.3050603-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
On Thu, Jul 30, 2015 at 11:30 AM, Dave Kleikamp
<dave.kleikamp-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org> wrote:
> On 07/30/2015 06:36 AM, Ming Lei wrote:
>> This patches provides one interface for enabling direct IO
>> from user space:
>>
>> - userspace(such as losetup) can pass 'file' which is
>> opened/fcntl as O_DIRECT
>>
>> Also __loop_update_dio() is introduced to check if direct I/O
>> can be used on current loop setting.
>>
>> The last big change is to introduce LO_FLAGS_DIRECT_IO flag
>> for userspace to know if direct IO is used to access backing
>> file.
>
> lo->use_dio and LO_FLAGS_DIRECT_IO seem redundant. Wouldn't it be
> simpler to use one or the other?
losetup is a stateless utility, which means it need to retrieve the dio status
via the flag of LO_FLAGS_DIRECT_IO, which is one API change.
>
>>
>> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> Signed-off-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
>> ---
>> drivers/block/loop.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-
>> drivers/block/loop.h | 2 ++
>> include/uapi/linux/loop.h | 1 +
>> 3 files changed, 65 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
>> index 1875aad..799cc23 100644
>> --- a/drivers/block/loop.c
>> +++ b/drivers/block/loop.c
>> @@ -164,6 +164,47 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
>> return get_size(lo->lo_offset, lo->lo_sizelimit, file);
>> }
>>
>> +static void __loop_update_dio(struct loop_device *lo, bool dio)
>> +{
>> + struct file *file = lo->lo_backing_file;
>> + struct inode *inode = file->f_mapping->host;
>> + bool use_dio;
>> + unsigned dio_align = inode->i_sb->s_bdev ?
>> + (bdev_io_min(inode->i_sb->s_bdev) - 1) : 0;
>> +
>> + /*
>> + * We support direct I/O only if lo_offset is aligned
>> + * with the min I/O size of backing device.
>> + *
>> + * Request's offset and size will be checked in I/O path.
>> + */
>> + if (dio) {
>> + if (!dio_align || (lo->lo_offset & dio_align))
>> + use_dio = false;
>> + else
>> + use_dio = true;
>> + } else {
>> + use_dio = false;
>> + }
>> +
>> + /* flush dirty pages before changing direct IO */
>> + vfs_fsync(file, 0);
>> +
>> + /*
>> + * The flag of LO_FLAGS_DIRECT_IO is handled similarly with
>> + * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
>> + * will get updated by ioctl(LOOP_GET_STATUS)
>> + */
>> + blk_mq_freeze_queue(lo->lo_queue);
>> + lo->use_dio = use_dio;
>> + lo->dio_align = dio_align;
>> + if (use_dio)
>> + lo->lo_flags |= LO_FLAGS_DIRECT_IO;
>> + else
>> + lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
>> + blk_mq_unfreeze_queue(lo->lo_queue);
>> +}
>> +
>> static int
>> figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>> {
>> @@ -173,8 +214,12 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
>>
>> if (unlikely((loff_t)x != size))
>> return -EFBIG;
>> - if (lo->lo_offset != offset)
>> + if (lo->lo_offset != offset) {
>> lo->lo_offset = offset;
>> +
>> + /* update dio if lo_offset is changed*/
>> + __loop_update_dio(lo, lo->use_dio);
>> + }
>> if (lo->lo_sizelimit != sizelimit)
>> lo->lo_sizelimit = sizelimit;
>> set_capacity(lo->lo_disk, x);
>> @@ -421,6 +466,11 @@ struct switch_request {
>> struct completion wait;
>> };
>>
>> +static inline void loop_update_dio(struct loop_device *lo)
>> +{
>> + __loop_update_dio(lo, io_is_direct(lo->lo_backing_file));
>> +}
>> +
>> /*
>> * Do the actual switch; called from the BIO completion routine
>> */
>> @@ -441,6 +491,7 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
>> mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
>> lo->old_gfp_mask = mapping_gfp_mask(mapping);
>> mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
>> + loop_update_dio(lo);
>> }
>>
>> /*
>> @@ -627,11 +678,19 @@ static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf)
>> return sprintf(buf, "%s\n", partscan ? "1" : "0");
>> }
>>
>> +static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf)
>> +{
>> + int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO);
>> +
>> + return sprintf(buf, "%s\n", dio ? "1" : "0");
>> +}
>> +
>> LOOP_ATTR_RO(backing_file);
>> LOOP_ATTR_RO(offset);
>> LOOP_ATTR_RO(sizelimit);
>> LOOP_ATTR_RO(autoclear);
>> LOOP_ATTR_RO(partscan);
>> +LOOP_ATTR_RO(dio);
>>
>> static struct attribute *loop_attrs[] = {
>> &loop_attr_backing_file.attr,
>> @@ -639,6 +698,7 @@ static struct attribute *loop_attrs[] = {
>> &loop_attr_sizelimit.attr,
>> &loop_attr_autoclear.attr,
>> &loop_attr_partscan.attr,
>> + &loop_attr_dio.attr,
>> NULL,
>> };
>>
>> @@ -783,6 +843,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
>> if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
>> blk_queue_flush(lo->lo_queue, REQ_FLUSH);
>>
>> + loop_update_dio(lo);
>> set_capacity(lo->lo_disk, size);
>> bd_set_size(bdev, size << 9);
>> loop_sysfs_init(lo);
>> diff --git a/drivers/block/loop.h b/drivers/block/loop.h
>> index b6c7d21..63f8e14 100644
>> --- a/drivers/block/loop.h
>> +++ b/drivers/block/loop.h
>> @@ -58,6 +58,8 @@ struct loop_device {
>> struct mutex lo_ctl_mutex;
>> struct kthread_worker worker;
>> struct task_struct *worker_task;
>> + unsigned dio_align;
>> + bool use_dio;
>>
>> struct request_queue *lo_queue;
>> struct blk_mq_tag_set tag_set;
>> diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
>> index e0cecd2..949851c 100644
>> --- a/include/uapi/linux/loop.h
>> +++ b/include/uapi/linux/loop.h
>> @@ -21,6 +21,7 @@ enum {
>> LO_FLAGS_READ_ONLY = 1,
>> LO_FLAGS_AUTOCLEAR = 4,
>> LO_FLAGS_PARTSCAN = 8,
>> + LO_FLAGS_DIRECT_IO = 16,
>> };
>>
>> #include <asm/posix_types.h> /* for __kernel_old_dev_t */
>>
^ permalink raw reply
* Re: [PATCHv2 1/1] Documentation: describe how to add a system call
From: Cyril Hrubis @ 2015-07-30 16:30 UTC (permalink / raw)
To: David Drysdale
Cc: linux-api, Michael Kerrisk, Andrew Morton, Arnd Bergmann,
Shuah Khan, Jonathan Corbet, Eric B Munson, Randy Dunlap,
Andrea Arcangeli, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Oleg Nesterov, Linus Torvalds, Greg Kroah-Hartman,
Andy Lutomirski, Al Viro, Rusty Russell, Peter Zijlstra,
Vivek Goyal, Alexei Starovoitov, David Herrmann,
Theodore Ts'o, Kees Cook <keesc>
In-Reply-To: <1438242731-27756-2-git-send-email-drysdale@google.com>
Hi!
> +Testing
> +-------
> +
> +A new system call should obviously be tested; it is also useful to provide
> +reviewers with a demonstration of how user space programs will use the system
> +call. A good way to combine these aims is to include a simple self-test
> +program in a new directory under tools/testing/selftests/.
I know that this is a bit off topic, but since the selftest is now the
official place to add kernel testcases to let me rant about it a bit.
It's a bit of a pain seeing people reinvent the wheel and trying to
figure out consistent test interface while most of the problems has been
solved in LTP[1] test library quite some time ago. Especially use of the
SAFE_MACROS[2] would simplify writing test setups quite a lot.
I wonder if we can at least share the test library, pulling it out of
LTP, or at least the interesting parts, wouldn't be hard at all.
[1]
https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#221-basic-test-structure
[2]
https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#224-safe-macros
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply
* Re: [PATCH] kdbus/samples: skip on CROSS_COMPILE
From: Greg Kroah-Hartman @ 2015-07-30 16:33 UTC (permalink / raw)
To: David Herrmann, Shuah Khan
Cc: linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Paul Gortmaker, Daniel Mack,
Djalal Harouni
In-Reply-To: <1438272805-19029-1-git-send-email-dh.herrmann-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, Jul 30, 2015 at 06:13:25PM +0200, David Herrmann wrote:
> Apparently we cannot rely on up-to-date kernel headers to be available
> when cross-compiling, not even for HOSTCC. That's sad, but it's how it
> is. Skip samples on cross-compiles as suggested by Paul, so allmodconfig
> runs smoothly again.
>
> Tested-by: Paul Gortmaker <paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ@public.gmane.org>
> Signed-off-by: David Herrmann <dh.herrmann-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> samples/kdbus/Makefile | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile
> index 137f842..dbd9de8 100644
> --- a/samples/kdbus/Makefile
> +++ b/samples/kdbus/Makefile
> @@ -1,9 +1,13 @@
> # kbuild trick to avoid linker error. Can be omitted if a module is built.
> obj- := dummy.o
>
> +ifndef CROSS_COMPILE
This really feels like the wrong solution.
> +
> hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers
>
> always := $(hostprogs-y)
>
> HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include
> HOSTLOADLIBES_kdbus-workers := -lrt
> +
> +endif
Shuah, how should we fix this "properly"? How is this resolved for the
kernel test scripts, it should have the same issue that the samples do.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCHv2 1/1] Documentation: describe how to add a system call
From: Greg Kroah-Hartman @ 2015-07-30 16:45 UTC (permalink / raw)
To: Cyril Hrubis
Cc: David Drysdale, linux-api, Michael Kerrisk, Andrew Morton,
Arnd Bergmann, Shuah Khan, Jonathan Corbet, Eric B Munson,
Randy Dunlap, Andrea Arcangeli, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Oleg Nesterov, Linus Torvalds, Andy Lutomirski,
Al Viro, Rusty Russell, Peter Zijlstra, Vivek Goyal,
Alexei Starovoitov, David Herrmann, Theodore Ts'o, Kees Cook
In-Reply-To: <20150730163007.GA10522@rei.suse.de>
On Thu, Jul 30, 2015 at 06:30:07PM +0200, Cyril Hrubis wrote:
> Hi!
> > +Testing
> > +-------
> > +
> > +A new system call should obviously be tested; it is also useful to provide
> > +reviewers with a demonstration of how user space programs will use the system
> > +call. A good way to combine these aims is to include a simple self-test
> > +program in a new directory under tools/testing/selftests/.
>
> I know that this is a bit off topic, but since the selftest is now the
> official place to add kernel testcases to let me rant about it a bit.
>
> It's a bit of a pain seeing people reinvent the wheel and trying to
> figure out consistent test interface while most of the problems has been
> solved in LTP[1] test library quite some time ago. Especially use of the
> SAFE_MACROS[2] would simplify writing test setups quite a lot.
>
> I wonder if we can at least share the test library, pulling it out of
> LTP, or at least the interesting parts, wouldn't be hard at all.
>
> [1]
> https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#221-basic-test-structure
>
> [2]
> https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#224-safe-macros
That would be great, please send patches to do so to the linux-api
mailing list and the test maintainer.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] kdbus/samples: skip on CROSS_COMPILE
From: David Herrmann @ 2015-07-30 17:00 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Shuah Khan, Linux API, linux-kernel, Paul Gortmaker, Daniel Mack,
Djalal Harouni
In-Reply-To: <20150730163307.GA20048-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Hi
On Thu, Jul 30, 2015 at 6:33 PM, Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> wrote:
> On Thu, Jul 30, 2015 at 06:13:25PM +0200, David Herrmann wrote:
>> Apparently we cannot rely on up-to-date kernel headers to be available
>> when cross-compiling, not even for HOSTCC. That's sad, but it's how it
>> is. Skip samples on cross-compiles as suggested by Paul, so allmodconfig
>> runs smoothly again.
>>
>> Tested-by: Paul Gortmaker <paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ@public.gmane.org>
>> Signed-off-by: David Herrmann <dh.herrmann-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> ---
>> samples/kdbus/Makefile | 4 ++++
>> 1 file changed, 4 insertions(+)
>>
>> diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile
>> index 137f842..dbd9de8 100644
>> --- a/samples/kdbus/Makefile
>> +++ b/samples/kdbus/Makefile
>> @@ -1,9 +1,13 @@
>> # kbuild trick to avoid linker error. Can be omitted if a module is built.
>> obj- := dummy.o
>>
>> +ifndef CROSS_COMPILE
>
> This really feels like the wrong solution.
>
>> +
>> hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers
>>
>> always := $(hostprogs-y)
>>
>> HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include
>> HOSTLOADLIBES_kdbus-workers := -lrt
>> +
>> +endif
>
> Shuah, how should we fix this "properly"? How is this resolved for the
> kernel test scripts, it should have the same issue that the samples do.
./samples/ is built as part of "make vmlinux", tests are not.
Therefore, tests don't break allmodconfig and friends. The underlying
issue is, that ./samples/ provides both: examples for kernel modules
*and* examples for user-space code.
Maybe the real fix is to eventually split user-space examples from
kernel-module-examples (./samples/kernel/ and ./samples/user/). But I
don't want to include such split in the kdbus tree. Instead, I tried
to follow the recent fixes that are already upstream: 65f6f092a6987,
f59514b6a8c5ca6dd, and 6a407a81a9abcf.
Suggestions welcome!
Thanks
David
^ permalink raw reply
* Re: [PATCH] kdbus/samples: skip on CROSS_COMPILE
From: Paul Gortmaker @ 2015-07-30 17:00 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: David Herrmann, Shuah Khan, linux-api, linux-kernel, Daniel Mack,
Djalal Harouni
In-Reply-To: <20150730163307.GA20048@kroah.com>
[Re: [PATCH] kdbus/samples: skip on CROSS_COMPILE] On 30/07/2015 (Thu 09:33) Greg Kroah-Hartman wrote:
> On Thu, Jul 30, 2015 at 06:13:25PM +0200, David Herrmann wrote:
> > Apparently we cannot rely on up-to-date kernel headers to be available
> > when cross-compiling, not even for HOSTCC. That's sad, but it's how it
> > is. Skip samples on cross-compiles as suggested by Paul, so allmodconfig
> > runs smoothly again.
> >
> > Tested-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> > Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> > ---
> > samples/kdbus/Makefile | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile
> > index 137f842..dbd9de8 100644
> > --- a/samples/kdbus/Makefile
> > +++ b/samples/kdbus/Makefile
> > @@ -1,9 +1,13 @@
> > # kbuild trick to avoid linker error. Can be omitted if a module is built.
> > obj- := dummy.o
> >
> > +ifndef CROSS_COMPILE
>
> This really feels like the wrong solution.
>
> > +
> > hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers
> >
> > always := $(hostprogs-y)
> >
> > HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include
> > HOSTLOADLIBES_kdbus-workers := -lrt
> > +
> > +endif
>
> Shuah, how should we fix this "properly"? How is this resolved for the
> kernel test scripts, it should have the same issue that the samples do.
If you guys want to reproduce it, in order to figure out what mips does
with its headers that no other arch does, it should be as simple as:
wget https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/x86_64-gcc-4.6.3-nolibc_mips-linux.tar.xz
<untar somewhere>
<add resulting bin dir to your $PATH>
export CROSS_COMPILE=mips-linux-
export ARCH=mips
cd kernel-source
make allmodconfig
make -j16 samples/
Paul.
--
>
> thanks,
>
> greg k-h
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox