18 hotfixes. 13 are cc:stable. 15 are for MM.

All are singletons - please see the changelogs for details.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCapoUuQAKCRDdBJ7gKXxA
 jgscAP9iRyonROgpsNKC9H8EsAL7QhZNxjwc5PWs0bN6J50LOwD/Um6G7b1P8cxs
 j7kGpxbQYI0RWxxLUBLTQiPbDrvn6wY=
 =TJzY
 -----END PGP SIGNATURE-----

Merge tag 'mm-hotfixes-stable-2026-09-03-17-45' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "18 hotfixes.  13 are cc:stable.  15 are for MM.

  All are singletons - please see the changelogs for details.

  There are no fixes (yet) for all the stuff we added in the most recent
  merge window. Hopefully a good sign"

* tag 'mm-hotfixes-stable-2026-09-03-17-45' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/secretmem: properly account locked pages
  mm/mremap: reset unfaulted VMA page offset for MREMAP_DONTUNMAP
  MAINTAINERS: add Kiryl as a THP reviewer
  MAINTAINERS: cover all of RAID
  MAINTAINERS: mailmap: update entries for Thorsten Blum
  MAINTAINERS: remove Lorenzo as THP co-maintainer
  Revert "once: don't use a work queue to reset sleepable static key"
  mm/hugetlb: fix missing migratable flag on same-node hugetlb migration
  mm/mempolicy: fix sleeping allocation in alloc_pages_bulk_weighted_interleave()
  mm/huge_memory: transfer the pmd dirty bit to the folio on zap
  MAINTAINERS: add Lance Yang as a hung task detector co-maintainer
  userfaultfd: reset err to be 0 when move_pages_ptes succeeded
  mm: fix incorrect vm_flags usage when checking allowable orders for tmpfs
  mm/hugetlb: keep max_huge_pages when dissolving surplus folios
  mm/migrate_device: avoid out-of-bounds writes for compound folios
  mm/hugetlb_cgroup: call page_counter_set_max() outside VM_BUG_ON()
  memcg: make the v1 soft limit knob inert
  mm/hugetlb_cma: fix null nodemask dereference in hugetlb_cma_alloc_frozen_folio
This commit is contained in:
Linus Torvalds 2026-09-03 17:59:19 -07:00
commit bc35965f69
18 changed files with 233 additions and 133 deletions

View File

@ -899,7 +899,8 @@ Thomas Graf <tgraf@suug.ch>
Thomas Gleixner <tglx@kernel.org> <tglx@linutronix.de>
Thomas Körper <socketcan@esd.eu> <thomas.koerper@esd.eu>
Thomas Pedersen <twp@codeaurora.org>
Thorsten Blum <thorsten.blum@linux.dev> <thorsten.blum@toblux.com>
Thorsten Blum <blum@kernel.org> <thorsten.blum@toblux.com>
Thorsten Blum <blum@kernel.org> <thorsten.blum@linux.dev>
Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com>
Tingwei Zhang <quic_tingwei@quicinc.com> <tingwei@codeaurora.org>
Tirupathi Reddy <quic_tirupath@quicinc.com> <tirupath@codeaurora.org>

View File

@ -47,7 +47,6 @@ Features:
- pages are linked to per-memcg LRU exclusively, and there is no global LRU.
- optionally, memory+swap usage can be accounted and limited.
- hierarchical accounting
- soft limit
- moving (recharging) account at moving a task is selectable.
- usage threshold notifier
- memory pressure notifier
@ -76,10 +75,9 @@ Brief summary of control files.
memory.memsw.failcnt show the number of memory+Swap hits limits
memory.max_usage_in_bytes show max memory usage recorded
memory.memsw.max_usage_in_bytes show max memory+Swap usage recorded
memory.soft_limit_in_bytes set/show soft limit of memory usage
This knob is not available on CONFIG_PREEMPT_RT systems.
This knob is deprecated and shouldn't be
used.
memory.soft_limit_in_bytes This knob is deprecated and has no effect.
Writes are ignored and reads always
return the maximum value.
memory.stat show various statistics
memory.use_hierarchy set/show hierarchical account enabled
This knob is deprecated and shouldn't be
@ -340,9 +338,6 @@ memory.kmem.usage_in_bytes, or in a separate counter when it makes sense.
The main "kmem" counter is fed into the main counter, so kmem charges will
also be visible from the user counter.
Currently no soft limit is implemented for kernel memory. It is future work
to trigger slab reclaim when those limits are reached.
2.7.1 Current Kernel Memory resources accounted
-----------------------------------------------
@ -710,42 +705,10 @@ For compatibility reasons writing 1 to memory.use_hierarchy will always pass::
THIS IS DEPRECATED!
Soft limits allow for greater sharing of memory. The idea behind soft limits
is to allow control groups to use as much of the memory as needed, provided
Writing to memory.soft_limit_in_bytes has no effect and reading it will
always return the maximum value.
a. There is no memory contention
b. They do not exceed their hard limit
When the system detects memory contention or low memory, control groups
are pushed back to their soft limits. If the soft limit of each control
group is very high, they are pushed back as much as possible to make
sure that one control group does not starve the others of memory.
Please note that soft limits is a best-effort feature; it comes with
no guarantees, but it does its best to make sure that when memory is
heavily contended for, memory is allocated based on the soft limit
hints/setup. Currently soft limit based reclaim is set up such that
it gets invoked from balance_pgdat (kswapd).
7.1 Interface
-------------
Soft limits can be setup by using the following commands (in this example we
assume a soft limit of 256 MiB)::
# echo 256M > memory.soft_limit_in_bytes
If we want to change this to 1G, we can at any time use::
# echo 1G > memory.soft_limit_in_bytes
.. note::
Soft limits take effect over a long period of time, since they involve
reclaiming memory for balancing between memory cgroups
.. note::
It is recommended to set the soft limit always below the hard limit,
otherwise the hard limit will take precedence.
Use memory.low and memory.min in cgroup v2 instead.
.. _cgroup-v1-memory-move-charges:

View File

@ -12221,7 +12221,7 @@ F: drivers/tty/hvc/
HUNG TASK DETECTOR
M: Andrew Morton <akpm@linux-foundation.org>
R: Lance Yang <lance.yang@linux.dev>
M: Lance Yang <lance.yang@linux.dev>
R: Masami Hiramatsu <mhiramat@kernel.org>
R: Petr Mladek <pmladek@suse.com>
L: linux-kernel@vger.kernel.org
@ -17410,7 +17410,6 @@ F: mm/swapfile.c
MEMORY MANAGEMENT - THP (TRANSPARENT HUGE PAGE)
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
R: Liam R. Howlett <liam@infradead.org>
@ -17420,6 +17419,7 @@ R: Dev Jain <dev.jain@arm.com>
R: Barry Song <baohua@kernel.org>
R: Lance Yang <lance.yang@linux.dev>
R: Usama Arif <usama.arif@linux.dev>
R: Kiryl Shutsemau <kas@kernel.org>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
@ -17692,7 +17692,7 @@ F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml
F: drivers/spi/spi-at91-usart.c
MICROCHIP ATSHA204A DRIVER
M: Thorsten Blum <thorsten.blum@linux.dev>
M: Thorsten Blum <blum@kernel.org>
L: linux-crypto@vger.kernel.org
S: Maintained
F: drivers/crypto/atmel-sha204a.c
@ -17716,7 +17716,7 @@ F: Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
F: drivers/media/platform/microchip/microchip-csi2dc.c
MICROCHIP ECC DRIVER
M: Thorsten Blum <thorsten.blum@linux.dev>
M: Thorsten Blum <blum@kernel.org>
L: linux-crypto@vger.kernel.org
S: Maintained
F: drivers/crypto/atmel-ecc.c
@ -25403,7 +25403,7 @@ F: drivers/md/md*
F: drivers/md/raid*
F: include/linux/raid/
F: include/uapi/linux/raid/
F: lib/raid/raid6/
F: lib/raid/
SOLIDRUN CLEARFOG SUPPORT
M: Russell King <linux@armlinux.org.uk>

View File

@ -25,7 +25,8 @@ struct user_struct {
#if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_BPF_SYSCALL) || \
defined(CONFIG_NET) || defined(CONFIG_IO_URING) || \
defined(CONFIG_VFIO_PCI_ZDEV_KVM) || IS_ENABLED(CONFIG_IOMMUFD)
defined(CONFIG_VFIO_PCI_ZDEV_KVM) || IS_ENABLED(CONFIG_IOMMUFD) || \
defined(CONFIG_SECRETMEM)
atomic_long_t locked_vm;
#endif
#ifdef CONFIG_WATCH_QUEUE

View File

@ -93,6 +93,6 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
{
*done = true;
mutex_unlock(&once_mutex);
static_branch_disable(once_key);
once_disable_jump(once_key, mod);
}
EXPORT_SYMBOL(__do_once_sleepable_done);

View File

@ -2449,6 +2449,8 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
add_mm_counter(mm, mm_counter_file(folio),
-HPAGE_PMD_NR);
if (is_present && pmd_dirty(pmdval))
folio_mark_dirty(folio);
if (is_present && pmd_young(pmdval) &&
likely(vma_has_recency(vma)))
folio_mark_accessed(folio);

View File

@ -1992,7 +1992,8 @@ int dissolve_free_hugetlb_folio(struct folio *folio)
if (h->surplus_huge_pages_node[folio_nid(folio)])
adjust_surplus = true;
remove_hugetlb_folio(h, folio, adjust_surplus);
h->max_huge_pages--;
if (!adjust_surplus)
h->max_huge_pages--;
spin_unlock_irq(&hugetlb_lock);
/*
@ -2012,7 +2013,8 @@ int dissolve_free_hugetlb_folio(struct folio *folio)
if (rc) {
spin_lock_irq(&hugetlb_lock);
add_hugetlb_folio(h, folio, adjust_surplus);
h->max_huge_pages++;
if (!adjust_surplus)
h->max_huge_pages++;
goto out;
}
} else {
@ -7330,14 +7332,14 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio,
* There is no need to transfer the per-node surplus state
* when we do not cross the node.
*/
if (new_nid == old_nid)
return;
spin_lock_irq(&hugetlb_lock);
if (h->surplus_huge_pages_node[old_nid]) {
h->surplus_huge_pages_node[old_nid]--;
h->surplus_huge_pages_node[new_nid]++;
if (new_nid != old_nid) {
spin_lock_irq(&hugetlb_lock);
if (h->surplus_huge_pages_node[old_nid]) {
h->surplus_huge_pages_node[old_nid]--;
h->surplus_huge_pages_node[new_nid]++;
}
spin_unlock_irq(&hugetlb_lock);
}
spin_unlock_irq(&hugetlb_lock);
}
/*

View File

@ -97,6 +97,7 @@ static void hugetlb_cgroup_init(struct hugetlb_cgroup *h_cgroup,
struct page_counter *fault, *fault_parent = NULL;
struct page_counter *rsvd, *rsvd_parent = NULL;
unsigned long limit;
int ret;
if (parent_h_cgroup) {
fault_parent = hugetlb_cgroup_counter_from_cgroup(
@ -118,8 +119,10 @@ static void hugetlb_cgroup_init(struct hugetlb_cgroup *h_cgroup,
limit = round_down(PAGE_COUNTER_MAX,
pages_per_huge_page(&hstates[idx]));
VM_BUG_ON(page_counter_set_max(fault, limit));
VM_BUG_ON(page_counter_set_max(rsvd, limit));
ret = page_counter_set_max(fault, limit);
VM_WARN_ON_ONCE(ret);
ret = page_counter_set_max(rsvd, limit);
VM_WARN_ON_ONCE(ret);
}
}

View File

@ -3,6 +3,7 @@
#include <linux/mm.h>
#include <linux/cma.h>
#include <linux/compiler.h>
#include <linux/cpuset.h>
#include <linux/mm_inline.h>
#include <asm/page.h>
@ -55,15 +56,25 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
int node;
struct folio *folio;
struct page *page = NULL;
const nodemask_t *nmask;
unsigned int cpuset_mems_cookie;
if (!hugetlb_cma_size)
return NULL;
if (hugetlb_cma[nid])
retry_cpuset:
if (!nodemask) {
cpuset_mems_cookie = read_mems_allowed_begin();
nmask = &cpuset_current_mems_allowed;
} else {
nmask = nodemask;
}
if (hugetlb_cma[nid] && node_isset(nid, *nmask))
page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
if (!page && !(gfp_mask & __GFP_THISNODE)) {
for_each_node_mask(node, *nodemask) {
for_each_node_mask(node, *nmask) {
if (node == nid || !hugetlb_cma[node])
continue;
@ -73,8 +84,12 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
}
}
if (!page)
if (!page) {
if (!nodemask &&
unlikely(read_mems_allowed_retry(cpuset_mems_cookie)))
goto retry_cpuset;
return NULL;
}
folio = page_folio(page);
folio_set_hugetlb_cma(folio);

View File

@ -454,12 +454,6 @@ int hugepage_madvise(struct vm_area_struct *vma,
case MADV_HUGEPAGE:
*vm_flags &= ~VM_NOHUGEPAGE;
*vm_flags |= VM_HUGEPAGE;
/*
* If the vma become good for khugepaged to scan,
* register it here without waiting a page fault that
* may not happen any time soon.
*/
khugepaged_enter_vma(vma, *vm_flags);
break;
case MADV_NOHUGEPAGE:
*vm_flags &= ~VM_HUGEPAGE;

View File

@ -178,6 +178,14 @@ static int madvise_update_vma(vm_flags_t new_flags,
/* vm_flags is protected by the mmap_lock held in write mode. */
vma_start_write(vma);
vma->flags = new_vma_flags;
/*
* If the vma become good for khugepaged to scan,
* register it here without waiting a page fault that
* may not happen any time soon.
*/
if (vma_flags_test(&new_vma_flags, VMA_HUGEPAGE_BIT))
khugepaged_enter_vma(vma, vma_flags_to_legacy(new_vma_flags));
if (set_new_anon_name)
return replace_anon_vma_name(vma, anon_name);

View File

@ -96,7 +96,6 @@ enum {
RES_LIMIT,
RES_MAX_USAGE,
RES_FAILCNT,
RES_SOFT_LIMIT,
};
#ifdef CONFIG_LOCKDEP
@ -1888,6 +1887,30 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
return -EINVAL;
}
static u64 mem_cgroup_soft_limit_read(struct cgroup_subsys_state *css,
struct cftype *cft)
{
return (u64)PAGE_COUNTER_MAX * PAGE_SIZE;
}
static ssize_t mem_cgroup_soft_limit_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
unsigned long nr_pages;
int ret;
ret = page_counter_memparse(strstrip(buf), "-1", &nr_pages);
if (ret)
return ret;
pr_warn_once("soft_limit_in_bytes is deprecated and will be removed. "
"Writing any value to this file has no effect. "
"Please report your usecase to linux-mm@kvack.org if you "
"depend on this functionality.\n");
return nbytes;
}
static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
struct cftype *cft)
{
@ -1924,8 +1947,6 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
return (u64)counter->watermark * PAGE_SIZE;
case RES_FAILCNT:
return counter->failcnt;
case RES_SOFT_LIMIT:
return (u64)READ_ONCE(memcg->soft_limit) * PAGE_SIZE;
default:
BUG();
}
@ -2020,17 +2041,6 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
break;
}
break;
case RES_SOFT_LIMIT:
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
ret = -EOPNOTSUPP;
} else {
pr_warn_once("soft_limit_in_bytes is deprecated and will be removed. "
"Please report your usecase to linux-mm@kvack.org if you "
"depend on this functionality.\n");
WRITE_ONCE(memcg->soft_limit, nr_pages);
ret = 0;
}
break;
}
return ret ?: nbytes;
}
@ -2384,9 +2394,8 @@ struct cftype mem_cgroup_legacy_files[] = {
},
{
.name = "soft_limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
.write = mem_cgroup_write,
.read_u64 = mem_cgroup_read_u64,
.write = mem_cgroup_soft_limit_write,
.read_u64 = mem_cgroup_soft_limit_read,
},
{
.name = "failcnt",

View File

@ -2679,7 +2679,7 @@ static unsigned long alloc_pages_bulk_weighted_interleave(gfp_t gfp,
prev_node = node;
/* create a local copy of node weights to operate on outside rcu */
weights = kzalloc(nr_node_ids, GFP_KERNEL);
weights = kmalloc(nr_node_ids, gfp & GFP_RECLAIM_MASK);
if (!weights)
return total_allocated;

View File

@ -1423,6 +1423,15 @@ int migrate_device_range(unsigned long *src_pfns, unsigned long start,
src_pfns[i] = migrate_device_pfn_lock(pfn);
nr = folio_nr_pages(folio);
if (nr > npages - i) {
if (src_pfns[i] & MIGRATE_PFN_MIGRATE) {
folio_unlock(folio);
folio_put(folio);
}
memset(&src_pfns[i], 0,
(npages - i) * sizeof(*src_pfns));
break;
}
if (nr > 1) {
src_pfns[i] |= MIGRATE_PFN_COMPOUND;
for (j = 1; j < nr; j++)
@ -1457,6 +1466,15 @@ int migrate_device_pfns(unsigned long *src_pfns, unsigned long npages)
src_pfns[i] = migrate_device_pfn_lock(src_pfns[i]);
nr = folio_nr_pages(folio);
if (nr > npages - i) {
if (src_pfns[i] & MIGRATE_PFN_MIGRATE) {
folio_unlock(folio);
folio_put(folio);
}
memset(&src_pfns[i], 0,
(npages - i) * sizeof(*src_pfns));
break;
}
if (nr > 1) {
src_pfns[i] |= MIGRATE_PFN_COMPOUND;
for (j = 1; j < nr; j++)

View File

@ -1331,18 +1331,30 @@ static void dontunmap_complete(struct vma_remap_struct *vrm,
{
unsigned long start = vrm->addr;
unsigned long end = vrm->addr + vrm->old_len;
unsigned long old_start = vrm->vma->vm_start;
unsigned long old_end = vrm->vma->vm_end;
struct vm_area_struct *vma = vrm->vma;
unsigned long old_start = vma->vm_start;
unsigned long old_end = vma->vm_end;
/* We always clear VMA_LOCKED[ONFAULT]_BIT on the old VMA. */
vma_clear_flags_mask(vrm->vma, VMA_LOCKED_MASK);
vma_clear_flags_mask(vma, VMA_LOCKED_MASK);
/*
* anon_vma links of the old vma is no longer needed after its page
* table has been moved.
*/
if (new_vma != vrm->vma && start == old_start && end == old_end)
unlink_anon_vmas(vrm->vma);
if (new_vma != vma && start == old_start && end == old_end) {
const pgoff_t pgoff_unfaulted = vma->vm_start >> PAGE_SHIFT;
unlink_anon_vmas(vma);
/*
* The VMA is now unfaulted and it is an invariant that
* unfaulted anonymous VMAs have page offset equal to
* vma->vm_start >> PAGE_SHIFT.
*/
vma_set_anon_pgoff(vma, pgoff_unfaulted);
if (vma_is_anonymous(vma) && !vma->vm_file)
vma_set_pgoff(vma, pgoff_unfaulted);
}
/* Because we won't unmap we don't need to touch locked_vm. */
}

View File

@ -18,6 +18,8 @@
#include <linux/secretmem.h>
#include <linux/set_memory.h>
#include <linux/sched/signal.h>
#include <linux/sched/user.h>
#include <linux/cred.h>
#include <uapi/linux/magic.h>
@ -47,10 +49,69 @@ bool secretmem_active(void)
return !!atomic_read(&secretmem_users);
}
struct secretmem_inode_state {
struct user_struct *user;
atomic_long_t nr_pages_accounted;
};
static bool __secretmem_account_pages(struct user_struct *user,
unsigned long nr_pages)
{
unsigned long page_limit, cur_pages, new_pages;
if (!nr_pages)
return true;
page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
cur_pages = atomic_long_read(&user->locked_vm);
do {
new_pages = cur_pages + nr_pages;
if (new_pages > page_limit)
return false;
} while (!atomic_long_try_cmpxchg(&user->locked_vm,
&cur_pages, new_pages));
return true;
}
static bool secretmem_account_folio(struct secretmem_inode_state *state,
const struct folio *folio)
{
const unsigned long nr_pages = folio_nr_pages(folio);
if (!__secretmem_account_pages(state->user, nr_pages))
return false;
atomic_long_add(nr_pages, &state->nr_pages_accounted);
return true;
}
static void __secretmem_unaccount_pages(struct secretmem_inode_state *state,
unsigned long nr_pages)
{
atomic_long_sub(nr_pages, &state->user->locked_vm);
atomic_long_sub(nr_pages, &state->nr_pages_accounted);
}
static void secretmem_unaccount_folio(struct secretmem_inode_state *state,
struct folio *folio)
{
__secretmem_unaccount_pages(state, folio_nr_pages(folio));
}
static void secretmem_unaccount_all_folios(struct secretmem_inode_state *state)
{
const unsigned long nr_pages_accounted =
atomic_long_read(&state->nr_pages_accounted);
__secretmem_unaccount_pages(state, nr_pages_accounted);
}
static vm_fault_t secretmem_fault(struct vm_fault *vmf)
{
struct address_space *mapping = vmf->vma->vm_file->f_mapping;
struct inode *inode = file_inode(vmf->vma->vm_file);
struct secretmem_inode_state *state = inode->i_private;
pgoff_t offset = vmf->pgoff;
gfp_t gfp = vmf->gfp_mask;
unsigned long addr;
@ -72,8 +133,15 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
goto out;
}
if (!secretmem_account_folio(state, folio)) {
folio_put(folio);
ret = VM_FAULT_SIGBUS;
goto out;
}
err = set_direct_map_invalid_noflush(folio_page(folio, 0));
if (err) {
secretmem_unaccount_folio(state, folio);
folio_put(folio);
ret = vmf_error(err);
goto out;
@ -82,6 +150,7 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
__folio_mark_uptodate(folio);
err = filemap_add_folio(mapping, folio, offset, gfp);
if (unlikely(err)) {
secretmem_unaccount_folio(state, folio);
/*
* If a split of large page was required, it
* already happened when we marked the page invalid
@ -112,22 +181,30 @@ static const struct vm_operations_struct secretmem_vm_ops = {
.fault = secretmem_fault,
};
static void secretmem_destroy_inode_priv(struct inode *inode)
{
struct secretmem_inode_state *state = inode->i_private;
secretmem_unaccount_all_folios(state);
free_uid(state->user);
kfree(state);
inode->i_private = NULL;
}
static int secretmem_release(struct inode *inode, struct file *file)
{
atomic_dec(&secretmem_users);
secretmem_destroy_inode_priv(inode);
return 0;
}
static int secretmem_mmap_prepare(struct vm_area_desc *desc)
{
const unsigned long len = vma_desc_size(desc);
if (!vma_desc_test_any(desc, VMA_SHARED_BIT, VMA_MAYSHARE_BIT))
return -EINVAL;
vma_desc_set_flags(desc, VMA_LOCKED_BIT, VMA_DONTDUMP_BIT);
if (!mlock_future_ok(desc->mm, /*is_vma_locked=*/ true, len))
return -EAGAIN;
vma_desc_set_flags(desc, VMA_DONTDUMP_BIT);
desc->vm_ops = &secretmem_vm_ops;
return 0;
@ -187,20 +264,40 @@ static const struct inode_operations secretmem_iops = {
static struct vfsmount *secretmem_mnt;
static int secretmem_init_inode_priv(struct inode *inode)
{
struct secretmem_inode_state *state;
state = kzalloc_obj(*state);
if (!state)
return -ENOMEM;
state->user = get_uid(current_user());
inode->i_private = state;
return 0;
}
static struct file *secretmem_file_create(unsigned long flags)
{
struct file *file;
struct inode *inode;
const char *anon_name = "[secretmem]";
int err;
inode = anon_inode_make_secure_inode(secretmem_mnt->mnt_sb, anon_name, NULL);
if (IS_ERR(inode))
return ERR_CAST(inode);
err = secretmem_init_inode_priv(inode);
if (err)
goto err_free_inode;
file = alloc_file_pseudo(inode, secretmem_mnt, "secretmem",
O_RDWR | O_LARGEFILE, &secretmem_fops);
if (IS_ERR(file))
goto err_free_inode;
if (IS_ERR(file)) {
err = PTR_ERR(file);
goto err_free_priv;
}
mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
mapping_set_unevictable(inode->i_mapping);
@ -215,10 +312,11 @@ static struct file *secretmem_file_create(unsigned long flags)
atomic_inc(&secretmem_users);
return file;
err_free_priv:
secretmem_destroy_inode_priv(inode);
err_free_inode:
iput(inode);
return file;
return ERR_PTR(err);
}
SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)

View File

@ -2171,8 +2171,10 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
}
if (err) {
if (err == -EAGAIN)
if (err == -EAGAIN) {
err = 0;
continue;
}
break;
}

View File

@ -57,33 +57,6 @@ static void test_file_apis(int fd)
pass("file IO is blocked as expected\n");
}
static void test_mlock_limit(int fd)
{
size_t len;
char *mem;
len = mlock_limit_cur;
if (len % page_size != 0)
len = (len/page_size) * page_size;
mem = mmap(NULL, len, prot, mode, fd, 0);
if (mem == MAP_FAILED) {
fail("unable to mmap secret memory\n");
return;
}
munmap(mem, len);
len = mlock_limit_max * 2;
mem = mmap(NULL, len, prot, mode, fd, 0);
if (mem != MAP_FAILED) {
fail("unexpected mlock limit violation\n");
munmap(mem, len);
return;
}
pass("mlock limit is respected\n");
}
static void test_vmsplice(int fd, const char *desc)
{
ssize_t transferred;
@ -297,7 +270,7 @@ static void prepare(void)
strerror(errno));
}
#define NUM_TESTS 6
#define NUM_TESTS 5
int main(int argc, char *argv[])
{
@ -319,7 +292,6 @@ int main(int argc, char *argv[])
if (ftruncate(fd, page_size))
ksft_exit_fail_msg("ftruncate failed: %s\n", strerror(errno));
test_mlock_limit(fd);
test_file_apis(fd);
/*
* We have to run the first vmsplice test before any secretmem page was