Commit 39c3c396 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mm-hotfixes-stable-2022-07-26' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "Thirteen hotfixes.

  Eight are cc:stable and the remainder are for post-5.18 issues or are
  too minor to warrant backporting"

* tag 'mm-hotfixes-stable-2022-07-26' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mailmap: update Gao Xiang's email addresses
  userfaultfd: provide properly masked address for huge-pages
  Revert "ocfs2: mount shared volume without ha stack"
  hugetlb: fix memoryleak in hugetlb_mcopy_atomic_pte
  fs: sendfile handles O_NONBLOCK of out_fd
  ntfs: fix use-after-free in ntfs_ucsncmp()
  secretmem: fix unhandled fault in truncate
  mm/hugetlb: separate path for hwpoison entry in copy_hugetlb_page_range()
  mm: fix missing wake-up event for FSDAX pages
  mm: fix page leak with multiple threads mapping the same page
  mailmap: update Seth Forshee's email address
  tmpfs: fix the issue that the mount and remount results are inconsistent.
  mm: kfence: apply kmemleak_ignore_phys on early allocated pool
parents 5de64d44 1f7ea547
...@@ -135,6 +135,8 @@ Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com> ...@@ -135,6 +135,8 @@ Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com>
Frank Zago <fzago@systemfabricworks.com> Frank Zago <fzago@systemfabricworks.com>
Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com> Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com> Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com>
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com> Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com>
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com> Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com>
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@linux.vnet.ibm.com> Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@linux.vnet.ibm.com>
...@@ -371,6 +373,7 @@ Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> ...@@ -371,6 +373,7 @@ Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
Sebastian Reichel <sre@kernel.org> <sre@debian.org> Sebastian Reichel <sre@kernel.org> <sre@debian.org>
Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de> Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de>
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com> Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com> Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
......
...@@ -592,8 +592,12 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name, ...@@ -592,8 +592,12 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
a = (ATTR_RECORD*)((u8*)ctx->attr + a = (ATTR_RECORD*)((u8*)ctx->attr +
le32_to_cpu(ctx->attr->length)); le32_to_cpu(ctx->attr->length));
for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) { for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec + u8 *mrec_end = (u8 *)ctx->mrec +
le32_to_cpu(ctx->mrec->bytes_allocated)) le32_to_cpu(ctx->mrec->bytes_allocated);
u8 *name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
a->name_length * sizeof(ntfschar);
if ((u8*)a < (u8*)ctx->mrec || (u8*)a > mrec_end ||
name_end > mrec_end)
break; break;
ctx->attr = a; ctx->attr = a;
if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) || if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
......
...@@ -277,7 +277,6 @@ enum ocfs2_mount_options ...@@ -277,7 +277,6 @@ enum ocfs2_mount_options
OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15, /* Journal Async Commit */ OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15, /* Journal Async Commit */
OCFS2_MOUNT_ERRORS_CONT = 1 << 16, /* Return EIO to the calling process on error */ OCFS2_MOUNT_ERRORS_CONT = 1 << 16, /* Return EIO to the calling process on error */
OCFS2_MOUNT_ERRORS_ROFS = 1 << 17, /* Change filesystem to read-only on error */ OCFS2_MOUNT_ERRORS_ROFS = 1 << 17, /* Change filesystem to read-only on error */
OCFS2_MOUNT_NOCLUSTER = 1 << 18, /* No cluster aware filesystem mount */
}; };
#define OCFS2_OSB_SOFT_RO 0x0001 #define OCFS2_OSB_SOFT_RO 0x0001
...@@ -673,8 +672,7 @@ static inline int ocfs2_cluster_o2cb_global_heartbeat(struct ocfs2_super *osb) ...@@ -673,8 +672,7 @@ static inline int ocfs2_cluster_o2cb_global_heartbeat(struct ocfs2_super *osb)
static inline int ocfs2_mount_local(struct ocfs2_super *osb) static inline int ocfs2_mount_local(struct ocfs2_super *osb)
{ {
return ((osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT) return (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT);
|| (osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER));
} }
static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb) static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
......
...@@ -252,16 +252,14 @@ static int __ocfs2_find_empty_slot(struct ocfs2_slot_info *si, ...@@ -252,16 +252,14 @@ static int __ocfs2_find_empty_slot(struct ocfs2_slot_info *si,
int i, ret = -ENOSPC; int i, ret = -ENOSPC;
if ((preferred >= 0) && (preferred < si->si_num_slots)) { if ((preferred >= 0) && (preferred < si->si_num_slots)) {
if (!si->si_slots[preferred].sl_valid || if (!si->si_slots[preferred].sl_valid) {
!si->si_slots[preferred].sl_node_num) {
ret = preferred; ret = preferred;
goto out; goto out;
} }
} }
for(i = 0; i < si->si_num_slots; i++) { for(i = 0; i < si->si_num_slots; i++) {
if (!si->si_slots[i].sl_valid || if (!si->si_slots[i].sl_valid) {
!si->si_slots[i].sl_node_num) {
ret = i; ret = i;
break; break;
} }
...@@ -456,30 +454,24 @@ int ocfs2_find_slot(struct ocfs2_super *osb) ...@@ -456,30 +454,24 @@ int ocfs2_find_slot(struct ocfs2_super *osb)
spin_lock(&osb->osb_lock); spin_lock(&osb->osb_lock);
ocfs2_update_slot_info(si); ocfs2_update_slot_info(si);
if (ocfs2_mount_local(osb)) /* search for ourselves first and take the slot if it already
/* use slot 0 directly in local mode */ * exists. Perhaps we need to mark this in a variable for our
slot = 0; * own journal recovery? Possibly not, though we certainly
else { * need to warn to the user */
/* search for ourselves first and take the slot if it already slot = __ocfs2_node_num_to_slot(si, osb->node_num);
* exists. Perhaps we need to mark this in a variable for our if (slot < 0) {
* own journal recovery? Possibly not, though we certainly /* if no slot yet, then just take 1st available
* need to warn to the user */ * one. */
slot = __ocfs2_node_num_to_slot(si, osb->node_num); slot = __ocfs2_find_empty_slot(si, osb->preferred_slot);
if (slot < 0) { if (slot < 0) {
/* if no slot yet, then just take 1st available spin_unlock(&osb->osb_lock);
* one. */ mlog(ML_ERROR, "no free slots available!\n");
slot = __ocfs2_find_empty_slot(si, osb->preferred_slot); status = -EINVAL;
if (slot < 0) { goto bail;
spin_unlock(&osb->osb_lock); }
mlog(ML_ERROR, "no free slots available!\n"); } else
status = -EINVAL; printk(KERN_INFO "ocfs2: Slot %d on device (%s) was already "
goto bail; "allocated to this node!\n", slot, osb->dev_str);
}
} else
printk(KERN_INFO "ocfs2: Slot %d on device (%s) was "
"already allocated to this node!\n",
slot, osb->dev_str);
}
ocfs2_set_slot(si, slot, osb->node_num); ocfs2_set_slot(si, slot, osb->node_num);
osb->slot_num = slot; osb->slot_num = slot;
......
...@@ -172,7 +172,6 @@ enum { ...@@ -172,7 +172,6 @@ enum {
Opt_dir_resv_level, Opt_dir_resv_level,
Opt_journal_async_commit, Opt_journal_async_commit,
Opt_err_cont, Opt_err_cont,
Opt_nocluster,
Opt_err, Opt_err,
}; };
...@@ -206,7 +205,6 @@ static const match_table_t tokens = { ...@@ -206,7 +205,6 @@ static const match_table_t tokens = {
{Opt_dir_resv_level, "dir_resv_level=%u"}, {Opt_dir_resv_level, "dir_resv_level=%u"},
{Opt_journal_async_commit, "journal_async_commit"}, {Opt_journal_async_commit, "journal_async_commit"},
{Opt_err_cont, "errors=continue"}, {Opt_err_cont, "errors=continue"},
{Opt_nocluster, "nocluster"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -618,13 +616,6 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) ...@@ -618,13 +616,6 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
goto out; goto out;
} }
tmp = OCFS2_MOUNT_NOCLUSTER;
if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
ret = -EINVAL;
mlog(ML_ERROR, "Cannot change nocluster option on remount\n");
goto out;
}
tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL | tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
OCFS2_MOUNT_HB_NONE; OCFS2_MOUNT_HB_NONE;
if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) { if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
...@@ -865,7 +856,6 @@ static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb, ...@@ -865,7 +856,6 @@ static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb,
} }
if (ocfs2_userspace_stack(osb) && if (ocfs2_userspace_stack(osb) &&
!(osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER) &&
strncmp(osb->osb_cluster_stack, mopt->cluster_stack, strncmp(osb->osb_cluster_stack, mopt->cluster_stack,
OCFS2_STACK_LABEL_LEN)) { OCFS2_STACK_LABEL_LEN)) {
mlog(ML_ERROR, mlog(ML_ERROR,
...@@ -1137,11 +1127,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1137,11 +1127,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK ? "writeback" : osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK ? "writeback" :
"ordered"); "ordered");
if ((osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER) &&
!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT))
printk(KERN_NOTICE "ocfs2: The shared device (%s) is mounted "
"without cluster aware mode.\n", osb->dev_str);
atomic_set(&osb->vol_state, VOLUME_MOUNTED); atomic_set(&osb->vol_state, VOLUME_MOUNTED);
wake_up(&osb->osb_mount_event); wake_up(&osb->osb_mount_event);
...@@ -1452,9 +1437,6 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -1452,9 +1437,6 @@ static int ocfs2_parse_options(struct super_block *sb,
case Opt_journal_async_commit: case Opt_journal_async_commit:
mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT; mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
break; break;
case Opt_nocluster:
mopt->mount_opt |= OCFS2_MOUNT_NOCLUSTER;
break;
default: default:
mlog(ML_ERROR, mlog(ML_ERROR,
"Unrecognized mount option \"%s\" " "Unrecognized mount option \"%s\" "
...@@ -1566,9 +1548,6 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root) ...@@ -1566,9 +1548,6 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
if (opts & OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT) if (opts & OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT)
seq_printf(s, ",journal_async_commit"); seq_printf(s, ",journal_async_commit");
if (opts & OCFS2_MOUNT_NOCLUSTER)
seq_printf(s, ",nocluster");
return 0; return 0;
} }
......
...@@ -1263,6 +1263,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, ...@@ -1263,6 +1263,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
count, fl); count, fl);
file_end_write(out.file); file_end_write(out.file);
} else { } else {
if (out.file->f_flags & O_NONBLOCK)
fl |= SPLICE_F_NONBLOCK;
retval = splice_file_to_pipe(in.file, opipe, &pos, count, fl); retval = splice_file_to_pipe(in.file, opipe, &pos, count, fl);
} }
......
...@@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg) ...@@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg)
} }
static inline struct uffd_msg userfault_msg(unsigned long address, static inline struct uffd_msg userfault_msg(unsigned long address,
unsigned long real_address,
unsigned int flags, unsigned int flags,
unsigned long reason, unsigned long reason,
unsigned int features) unsigned int features)
{ {
struct uffd_msg msg; struct uffd_msg msg;
msg_init(&msg); msg_init(&msg);
msg.event = UFFD_EVENT_PAGEFAULT; msg.event = UFFD_EVENT_PAGEFAULT;
if (!(features & UFFD_FEATURE_EXACT_ADDRESS)) msg.arg.pagefault.address = (features & UFFD_FEATURE_EXACT_ADDRESS) ?
address &= PAGE_MASK; real_address : address;
msg.arg.pagefault.address = address;
/* /*
* These flags indicate why the userfault occurred: * These flags indicate why the userfault occurred:
* - UFFD_PAGEFAULT_FLAG_WP indicates a write protect fault. * - UFFD_PAGEFAULT_FLAG_WP indicates a write protect fault.
...@@ -488,8 +490,8 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) ...@@ -488,8 +490,8 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function); init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function);
uwq.wq.private = current; uwq.wq.private = current;
uwq.msg = userfault_msg(vmf->real_address, vmf->flags, reason, uwq.msg = userfault_msg(vmf->address, vmf->real_address, vmf->flags,
ctx->features); reason, ctx->features);
uwq.ctx = ctx; uwq.ctx = ctx;
uwq.waken = false; uwq.waken = false;
......
...@@ -1130,23 +1130,27 @@ static inline bool is_zone_movable_page(const struct page *page) ...@@ -1130,23 +1130,27 @@ static inline bool is_zone_movable_page(const struct page *page)
#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX) #if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX)
DECLARE_STATIC_KEY_FALSE(devmap_managed_key); DECLARE_STATIC_KEY_FALSE(devmap_managed_key);
bool __put_devmap_managed_page(struct page *page); bool __put_devmap_managed_page_refs(struct page *page, int refs);
static inline bool put_devmap_managed_page(struct page *page) static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
{ {
if (!static_branch_unlikely(&devmap_managed_key)) if (!static_branch_unlikely(&devmap_managed_key))
return false; return false;
if (!is_zone_device_page(page)) if (!is_zone_device_page(page))
return false; return false;
return __put_devmap_managed_page(page); return __put_devmap_managed_page_refs(page, refs);
} }
#else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */ #else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
static inline bool put_devmap_managed_page(struct page *page) static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
{ {
return false; return false;
} }
#endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */ #endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
static inline bool put_devmap_managed_page(struct page *page)
{
return put_devmap_managed_page_refs(page, 1);
}
/* 127: arbitrary random number, small enough to assemble well */ /* 127: arbitrary random number, small enough to assemble well */
#define folio_ref_zero_or_close_to_overflow(folio) \ #define folio_ref_zero_or_close_to_overflow(folio) \
((unsigned int) folio_ref_count(folio) + 127u <= 127u) ((unsigned int) folio_ref_count(folio) + 127u <= 127u)
......
...@@ -87,7 +87,8 @@ static inline struct folio *try_get_folio(struct page *page, int refs) ...@@ -87,7 +87,8 @@ static inline struct folio *try_get_folio(struct page *page, int refs)
* belongs to this folio. * belongs to this folio.
*/ */
if (unlikely(page_folio(page) != folio)) { if (unlikely(page_folio(page) != folio)) {
folio_put_refs(folio, refs); if (!put_devmap_managed_page_refs(&folio->page, refs))
folio_put_refs(folio, refs);
goto retry; goto retry;
} }
...@@ -176,7 +177,8 @@ static void gup_put_folio(struct folio *folio, int refs, unsigned int flags) ...@@ -176,7 +177,8 @@ static void gup_put_folio(struct folio *folio, int refs, unsigned int flags)
refs *= GUP_PIN_COUNTING_BIAS; refs *= GUP_PIN_COUNTING_BIAS;
} }
folio_put_refs(folio, refs); if (!put_devmap_managed_page_refs(&folio->page, refs))
folio_put_refs(folio, refs);
} }
/** /**
......
...@@ -4788,8 +4788,13 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, ...@@ -4788,8 +4788,13 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
* sharing with another vma. * sharing with another vma.
*/ */
; ;
} else if (unlikely(is_hugetlb_entry_migration(entry) || } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
is_hugetlb_entry_hwpoisoned(entry))) { bool uffd_wp = huge_pte_uffd_wp(entry);
if (!userfaultfd_wp(dst_vma) && uffd_wp)
entry = huge_pte_clear_uffd_wp(entry);
set_huge_pte_at(dst, addr, dst_pte, entry);
} else if (unlikely(is_hugetlb_entry_migration(entry))) {
swp_entry_t swp_entry = pte_to_swp_entry(entry); swp_entry_t swp_entry = pte_to_swp_entry(entry);
bool uffd_wp = huge_pte_uffd_wp(entry); bool uffd_wp = huge_pte_uffd_wp(entry);
...@@ -5947,6 +5952,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, ...@@ -5947,6 +5952,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
page = alloc_huge_page(dst_vma, dst_addr, 0); page = alloc_huge_page(dst_vma, dst_addr, 0);
if (IS_ERR(page)) { if (IS_ERR(page)) {
put_page(*pagep);
ret = -ENOMEM; ret = -ENOMEM;
*pagep = NULL; *pagep = NULL;
goto out; goto out;
......
...@@ -603,14 +603,6 @@ static unsigned long kfence_init_pool(void) ...@@ -603,14 +603,6 @@ static unsigned long kfence_init_pool(void)
addr += 2 * PAGE_SIZE; addr += 2 * PAGE_SIZE;
} }
/*
* The pool is live and will never be deallocated from this point on.
* Remove the pool object from the kmemleak object tree, as it would
* otherwise overlap with allocations returned by kfence_alloc(), which
* are registered with kmemleak through the slab post-alloc hook.
*/
kmemleak_free(__kfence_pool);
return 0; return 0;
} }
...@@ -623,8 +615,16 @@ static bool __init kfence_init_pool_early(void) ...@@ -623,8 +615,16 @@ static bool __init kfence_init_pool_early(void)
addr = kfence_init_pool(); addr = kfence_init_pool();
if (!addr) if (!addr) {
/*
* The pool is live and will never be deallocated from this point on.
* Ignore the pool object from the kmemleak phys object tree, as it would
* otherwise overlap with allocations returned by kfence_alloc(), which
* are registered with kmemleak through the slab post-alloc hook.
*/
kmemleak_ignore_phys(__pa(__kfence_pool));
return true; return true;
}
/* /*
* Only release unprotected pages, and do not try to go back and change * Only release unprotected pages, and do not try to go back and change
......
...@@ -4369,9 +4369,12 @@ vm_fault_t finish_fault(struct vm_fault *vmf) ...@@ -4369,9 +4369,12 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
return VM_FAULT_OOM; return VM_FAULT_OOM;
} }
/* See comment in handle_pte_fault() */ /*
* See comment in handle_pte_fault() for how this scenario happens, we
* need to return NOPAGE so that we drop this page.
*/
if (pmd_devmap_trans_unstable(vmf->pmd)) if (pmd_devmap_trans_unstable(vmf->pmd))
return 0; return VM_FAULT_NOPAGE;
vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd,
vmf->address, &vmf->ptl); vmf->address, &vmf->ptl);
......
...@@ -499,7 +499,7 @@ void free_zone_device_page(struct page *page) ...@@ -499,7 +499,7 @@ void free_zone_device_page(struct page *page)
} }
#ifdef CONFIG_FS_DAX #ifdef CONFIG_FS_DAX
bool __put_devmap_managed_page(struct page *page) bool __put_devmap_managed_page_refs(struct page *page, int refs)
{ {
if (page->pgmap->type != MEMORY_DEVICE_FS_DAX) if (page->pgmap->type != MEMORY_DEVICE_FS_DAX)
return false; return false;
...@@ -509,9 +509,9 @@ bool __put_devmap_managed_page(struct page *page) ...@@ -509,9 +509,9 @@ bool __put_devmap_managed_page(struct page *page)
* refcount is 1, then the page is free and the refcount is * refcount is 1, then the page is free and the refcount is
* stable because nobody holds a reference on the page. * stable because nobody holds a reference on the page.
*/ */
if (page_ref_dec_return(page) == 1) if (page_ref_sub_return(page, refs) == 1)
wake_up_var(&page->_refcount); wake_up_var(&page->_refcount);
return true; return true;
} }
EXPORT_SYMBOL(__put_devmap_managed_page); EXPORT_SYMBOL(__put_devmap_managed_page_refs);
#endif /* CONFIG_FS_DAX */ #endif /* CONFIG_FS_DAX */
...@@ -55,22 +55,28 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf) ...@@ -55,22 +55,28 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
gfp_t gfp = vmf->gfp_mask; gfp_t gfp = vmf->gfp_mask;
unsigned long addr; unsigned long addr;
struct page *page; struct page *page;
vm_fault_t ret;
int err; int err;
if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode)) if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
return vmf_error(-EINVAL); return vmf_error(-EINVAL);
filemap_invalidate_lock_shared(mapping);
retry: retry:
page = find_lock_page(mapping, offset); page = find_lock_page(mapping, offset);
if (!page) { if (!page) {
page = alloc_page(gfp | __GFP_ZERO); page = alloc_page(gfp | __GFP_ZERO);
if (!page) if (!page) {
return VM_FAULT_OOM; ret = VM_FAULT_OOM;
goto out;
}
err = set_direct_map_invalid_noflush(page); err = set_direct_map_invalid_noflush(page);
if (err) { if (err) {
put_page(page); put_page(page);
return vmf_error(err); ret = vmf_error(err);
goto out;
} }
__SetPageUptodate(page); __SetPageUptodate(page);
...@@ -86,7 +92,8 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf) ...@@ -86,7 +92,8 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
if (err == -EEXIST) if (err == -EEXIST)
goto retry; goto retry;
return vmf_error(err); ret = vmf_error(err);
goto out;
} }
addr = (unsigned long)page_address(page); addr = (unsigned long)page_address(page);
...@@ -94,7 +101,11 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf) ...@@ -94,7 +101,11 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
} }
vmf->page = page; vmf->page = page;
return VM_FAULT_LOCKED; ret = VM_FAULT_LOCKED;
out:
filemap_invalidate_unlock_shared(mapping);
return ret;
} }
static const struct vm_operations_struct secretmem_vm_ops = { static const struct vm_operations_struct secretmem_vm_ops = {
...@@ -162,12 +173,20 @@ static int secretmem_setattr(struct user_namespace *mnt_userns, ...@@ -162,12 +173,20 @@ static int secretmem_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry, struct iattr *iattr) struct dentry *dentry, struct iattr *iattr)
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct address_space *mapping = inode->i_mapping;
unsigned int ia_valid = iattr->ia_valid; unsigned int ia_valid = iattr->ia_valid;
int ret;
filemap_invalidate_lock(mapping);
if ((ia_valid & ATTR_SIZE) && inode->i_size) if ((ia_valid & ATTR_SIZE) && inode->i_size)
return -EINVAL; ret = -EINVAL;
else
ret = simple_setattr(mnt_userns, dentry, iattr);
return simple_setattr(mnt_userns, dentry, iattr); filemap_invalidate_unlock(mapping);
return ret;
} }
static const struct inode_operations secretmem_iops = { static const struct inode_operations secretmem_iops = {
......
...@@ -3392,7 +3392,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) ...@@ -3392,7 +3392,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
break; break;
case Opt_nr_blocks: case Opt_nr_blocks:
ctx->blocks = memparse(param->string, &rest); ctx->blocks = memparse(param->string, &rest);
if (*rest) if (*rest || ctx->blocks > S64_MAX)
goto bad_value; goto bad_value;
ctx->seen |= SHMEM_SEEN_BLOCKS; ctx->seen |= SHMEM_SEEN_BLOCKS;
break; break;
...@@ -3514,10 +3514,7 @@ static int shmem_reconfigure(struct fs_context *fc) ...@@ -3514,10 +3514,7 @@ static int shmem_reconfigure(struct fs_context *fc)
raw_spin_lock(&sbinfo->stat_lock); raw_spin_lock(&sbinfo->stat_lock);
inodes = sbinfo->max_inodes - sbinfo->free_inodes; inodes = sbinfo->max_inodes - sbinfo->free_inodes;
if (ctx->blocks > S64_MAX) {
err = "Number of blocks too large";
goto out;
}
if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) { if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) {
if (!sbinfo->max_blocks) { if (!sbinfo->max_blocks) {
err = "Cannot retroactively limit size"; err = "Cannot retroactively limit size";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment