|
|
Log in / Subscribe / Register

Kernel development

Brief items

Kernel release status

The current development kernel is 4.10-rc4, released on January 15. Linus said: "Things are still looking fairly normal, and this is the usual weekly Sunday rc release. We're up to rc4, and people are clearly starting to find the regressions. Good, good."

Stable updates: 4.9.3 and 4.4.42 were released on January 12, followed by 4.9.4 and 4.4.43 on January 15. The 4.9.5 and 4.4.44 updates are in the review process as of this writing; they can be expected on or after January 20.

Comments (none posted)

Kernel development news

kvmalloc()

By Jonathan Corbet
January 17, 2017
Patterns of code that repeat throughout the kernel are often a sign that a helper function may be appropriate. That is doubly true if those repeated patterns include repeated errors or other suboptimal techniques. The case of kvmalloc() would appear to be just one of those cases; it is the subject of a recent patch set from Michal Hocko that significantly cleans up a common memory-allocation pattern in the kernel.

The kernel offers two fundamental mechanisms for allocating memory, both of which are, in turn, built on top of the kernel's page allocator. One of them, the slab allocator, will obtain physically contiguous memory in the kernel's own address space; this allocator is typically accessed via kmalloc(), though there are a number of other entry points as well. The alternative to the slab allocator is vmalloc(), which will return memory in a separate address space; that memory will be virtually contiguous but may be physically scattered.

As a general rule, slab allocations are preferred for all but the largest of allocations. In the absence of memory pressure, the slab allocator will be faster, since it does not need to make address-space changes. The slab allocator works best with allocations that are less than one physical page (usually 4KB) in size, though. When memory gets fragmented, groups of physically contiguous pages can get hard to find, and system performance can suffer as the allocator struggles to create such groups.

Allocations with vmalloc() do not need physically contiguous pages and are thus much more likely to succeed when memory is tight. But excessive use of vmalloc() is discouraged due to the extra overhead involved; each allocation done with vmalloc() requires page-table changes and a translation lookaside buffer invalidation. vmalloc() can only allocate entire pages, so it is not suitable for small requests. The address range available for vmalloc() allocations is also limited on 32-bit systems, which has historically been another disincentive to use this interface; that limitation is not present on 64-bit systems, though.

There are a number of places in the kernel where a large allocation must be physically contiguous, but there are probably even more where that doesn't matter. In the latter case, the code doesn't have a reason to care which allocation method was used to obtain its memory, as long as the memory is available. For this sort of indifferent code, it can make sense to try an allocation first with the slab allocator, then fall back to vmalloc() should that attempt fail. And, indeed, the kernel is full of code fragments that do exactly that.

However, as Hocko points out in the introduction to the kvmalloc() patch set, some of those fragments are "really creative" and many of them do not work as intended. For example, consider the following simple attempt at a fallback:

    memory = kmalloc(allocation_size, GFP_KERNEL);
    if (!memory)
        memory = vmalloc(allocation_size);

The problem here is that, for relatively small allocations (eight pages or less), kmalloc() will retry indefinitely rather than return failure. In such cases, the fallback path using vmalloc() will never be executed. Perhaps worse, the above kmalloc() call will go far out of its way in its attempts to satisfy the request. That could, for example, involve unchaining the dreaded out-of-memory killer to wreak havoc among unsuspecting processes. There are times when such drastic actions are needed, but memory-allocation code that has an explicit fallback path does not generally comprise one of those times.

What is needed, of course, is a simple helper that implements an allocation using this fallback technique while taking care to minimize the amount of unnecessary collateral damage. To that end, Hocko's patch set introduces a few new functions:

    void *kvmalloc(size_t size, gfp_t flags);
    void *kvzalloc(size_t size, gfp_t flags);
    void *kvmalloc_node(size_t size, gfp_t flags, int node);
    void *kvzalloc_node(size_t size, gfp_t flags, int node);

As one might expect, kvmalloc() attempts to allocate size bytes from the slab allocator; it makes a point of using the __GFP_NOWARN and __GFP_NORETRY flags to minimize the cost (and avoid out-of-memory killer invocations) when the memory is not immediately available. If the attempt fails, kvmalloc() will fall back to vmalloc() to perform the allocation. The kvzalloc() variant will zero the memory before returning it. The _node versions request that the memory be allocated local to the given NUMA node. As with any other allocation function, these functions can still fail.

Note that it doesn't generally make sense to use any of these functions with allocation requests that are smaller than a single page. Memory from vmalloc() is not available in sub-page granularity, so the fallback to vmalloc() will not be done in such cases. They also will not work as desired if called from atomic context, since vmalloc() cannot be used then.

It is interesting to note that this is not the first attempt to add kvmalloc() to the kernel; a version was posted by Changli Gao in 2010. That version did not take the same level of care to avoid unfortunate side effects, though, and was never merged. Hocko's patch set, which also converts a large number of open-coded fallback implementations to the new functions, seems more likely to find its way into the mainline.

Comments (5 posted)

The Machine: Controlling storage with a filesystem

By Jonathan Corbet
January 17, 2017

linux.conf.au 2017
Keith Packard is the chief architect for The Machine project at HPE; we covered his talk on this project back in 2015. At the 2017 linux.conf.au Kernel Miniconf, Packard focused on one specific aspect of The Machine's hardware and software configuration: how storage is managed and presented to applications. Like much that is being done with this project, its storage architecture is an interesting combination of new ideas and long-established techniques.

Packard described The Machine as "memory-driven computing". Most computing systems are built around the CPU, but, on The Machine, the focus is on data instead. The architecture of The Machine is not aimed at providing fast processors; instead, it is built around connecting commodity CPUs to vast amounts of user data, and providing "load-and-store" access (i.e. all of the data is addressable like main memory). Traditional Linux systems route data access through filesystems and disk drivers; The Machine will remove those layers and connect applications directly to their data.

The CPUs in The Machine are ARM64 processors — reasonably fast, but far from the strongest CPUs out there. They have "a little bit of DRAM, about a quarter terabyte" directly attached to them. But the core of the Machine is a large array of persistent memory attached to each CPU. Those memory arrays are then connected into a fabric that makes all of the memory available to all CPUs in the system. This fabric is implemented with the "Gen-Z" memory controller, a now-open project complete with its own consortium to further its development.

One of the key features of The Machine is that security is built in at every level; its components do not trust each other. So it is not possible to just allow every CPU to access any part of the memory fabric; instead, there must be a layer of protection between the CPUs and that fabric. The Machine needs a way to name portions of memory, perform access control so that the appropriate processors can access the memory that is allowed to them, and so on.

Packard said that there is a well-established mechanism for doing this sort of work — the filesystem. The designers of The Machine had sketched out an API for the management of the system's memory, but he realized quickly that this API looked an awful lot like POSIX. So, rather than create a management module with a one-off interface, he set out to make a filesystem interface instead.

The memory in the fabric is managed in 8GB units called "books"; that is the minimum granularity in which memory can be assigned to any given processor. The plans for The Machine call for over 300TB of installed memory, which is a fair amount, but that is only about 40,000 books, which is not a huge number to keep track of. That simplifies the management of memory considerably, since there is no need for complex data structures to get the required level of performance.

That management is not actually done by The Machine at all; instead, there is a "librarian" system — a standard x86 server — connected via Ethernet to do that job. The librarian only handles metadata, it never sees the actual data itself and has no access to that data. Within The Machine, the Library Filesystem (LFS) implements a view of the memory fabric and provides an interface by which fabric-attached memory can be managed. The filesystem itself is implemented as a FUSE (filesystem in user space) module using a "hacked-up" version of the kernel's FUSE interface.

The Machine is all about high-performance access to storage, so some might find it amusing that the LFS implementation and the librarian are both written in Python; they communicate via JSON-formatted messages. That may not seem like a recipe for performance, but there are only 40,000 books to manage, so a faster implementation is not needed. The magic is in the fabric interconnect, not the metadata management system.

The system's security model requires that no CPU be given access to memory for which it is not authorized. So the fabric needs to have access control and a firewall built in. The original intention was for this functionality to be implemented outside of the processors themselves (since the intent was to protect the memory from the processors) but, in the real world, it is CPU-based. This privileged code is implemented using the ARM TrustZone security system; Packard allowed that making that setup work was not the most fun part of this job.

The core functionality of LFS is to manage access to 8GB books of memory, combining those books into larger virtual storage devices as needed. This is, of course, functionality that is also provided by the existing device-mapper code and the LVM2 tools. But, he said, the actual management of the books is trivial, there is no real need for the device mapper. And if this functionality is exposed by a filesystem, then ordinary shell commands can be used to perform the needed operations.

Thus, for example, a simple touch command will create a volume set; no need for lvmcreate. An invocation of fallocate can allocate books for this volume set. And so on. In each case, he said, the normal shell commands are far simpler and easier to use than the associated LVM2 commands, which he can never remember without rereading the man pages first. The result is a simple and scriptable interface to memory management within The Machine.

There is one challenge, though, in that applications often want control over where books of memory are allocated. The nature of the memory fabric necessarily means that there will be performance differences between local and remote memory, even if the remote access has been made as fast as possible. A common requirement is to spread the books across all CPUs on the system so that all CPUs see approximately equal performance overall. An application may also want to explicitly allocate memory on two separate nodes, running on separate power supplies, and mirror its data across the two; that way, the data remains available even if part of the system goes down. Other allocation policies can be easily imagined as well.

Maintaining the filesystem abstraction requires finding a way to express these policies in the filesystem interface; in this case, that was done by storing allocation policies as extended attributes. Once again, that makes it easy to manipulate these policies in scripts. The actual allocations obtained (which could differ from the requested policies) are also available as extended attributes. One big advantage of this approach is that those attributes will be saved in backups of the system, and will be preserved should there be a need to restore from the backups.

There is a cost to not using the device mapper, of course. For example, it is not possible to create RAID arrays. But storage in a RAID array cannot be made directly accessible to the CPU via the DAX subsystem (since there would be no way for the kernel to intervene and do the RAID management). Direct access to all storage is one of the key design features of the Machine, so using RAID is out of the picture — and not all that useful with fabric-attached memory in the first place. Avoiding the device mapper also sacrifices the ability to spread storage across multiple types of devices, but there is only one type of storage in The Machine, so that also matters little.

Instead, by using the filesystem interface (along with some trickery to implement a specialized block device in the same module), The Machine is able to map all of that storage directly into the processors' address spaces, and all of the management can be done with simple shell tools. That may well prove to be a winning combination — assuming The Machine ever becomes a commercial product available outside of HPE.

For those wanting to play with the code, including a virtualization-based emulation system, the FabricAttachedMemory GitHub repository has all the code.

[Your editor would like to thank linux.conf.au and the Linux Foundation for assisting with his travel to the event.]

Comments (1 posted)

Patches and updates

Kernel trees

Linus Torvalds Linux 4.10-rc4 Jan 15
Greg KH Linux 4.9.4 Jan 15
Greg KH Linux 4.9.3 Jan 12
Greg KH Linux 4.4.43 Jan 15
Greg KH Linux 4.4.42 Jan 12

Architecture-specific

Build system

Development tools

Device drivers

Device driver infrastructure

Luis R. Rodriguez firmware: add drvdata API Jan 12
Heikki Krogerus USB Type-C Connector class Jan 16

Filesystems and block I/O

Memory management

Michal Hocko kvmalloc Jan 12
js1304@gmail.com pro-active compaction Jan 13

Security-related

Jens Wiklander generic TEE subsystem Jan 18

Virtualization and containers

Marcelo Tosatti KVM virtual PTP driver (v2) Jan 13

Miscellaneous

Page editor: Jonathan Corbet
Next page: Distributions>>


Copyright © 2017, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds