Merge dcde98da99
("Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input") into android-mainline
Steps on the way to 5.17-rc7 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I3aabd91b8d1aec1e9ae8cff35e749573da65f5f7
This commit is contained in:
commit
bd1f0731bd
@ -23,7 +23,7 @@ There are four components to pagemap:
|
||||
* Bit 56 page exclusively mapped (since 4.2)
|
||||
* Bit 57 pte is uffd-wp write-protected (since 5.13) (see
|
||||
:ref:`Documentation/admin-guide/mm/userfaultfd.rst <userfaultfd>`)
|
||||
* Bits 57-60 zero
|
||||
* Bits 58-60 zero
|
||||
* Bit 61 page is file-page or shared-anon (since 3.5)
|
||||
* Bit 62 page swapped
|
||||
* Bit 63 page present
|
||||
|
@ -69,8 +69,13 @@ static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
|
||||
{
|
||||
a->fixup = b->fixup + delta;
|
||||
b->fixup = tmp.fixup - delta;
|
||||
a->handler = b->handler + delta;
|
||||
b->handler = tmp.handler - delta;
|
||||
a->handler = b->handler;
|
||||
if (a->handler)
|
||||
a->handler += delta;
|
||||
b->handler = tmp.handler;
|
||||
if (b->handler)
|
||||
b->handler -= delta;
|
||||
}
|
||||
#define swap_ex_entry_fixup swap_ex_entry_fixup
|
||||
|
||||
#endif
|
||||
|
@ -47,15 +47,17 @@ struct ftrace_regs {
|
||||
|
||||
static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
|
||||
{
|
||||
return &fregs->regs;
|
||||
struct pt_regs *regs = &fregs->regs;
|
||||
|
||||
if (test_pt_regs_flag(regs, PIF_FTRACE_FULL_REGS))
|
||||
return regs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *fregs,
|
||||
unsigned long ip)
|
||||
{
|
||||
struct pt_regs *regs = arch_ftrace_get_regs(fregs);
|
||||
|
||||
regs->psw.addr = ip;
|
||||
fregs->regs.psw.addr = ip;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -15,11 +15,13 @@
|
||||
#define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */
|
||||
#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */
|
||||
#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */
|
||||
#define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */
|
||||
|
||||
#define _PIF_SYSCALL BIT(PIF_SYSCALL)
|
||||
#define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART)
|
||||
#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET)
|
||||
#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT)
|
||||
#define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
@ -159,9 +159,38 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ftrace_hotpatch_trampoline *ftrace_get_trampoline(struct dyn_ftrace *rec)
|
||||
{
|
||||
struct ftrace_hotpatch_trampoline *trampoline;
|
||||
struct ftrace_insn insn;
|
||||
s64 disp;
|
||||
u16 opc;
|
||||
|
||||
if (copy_from_kernel_nofault(&insn, (void *)rec->ip, sizeof(insn)))
|
||||
return ERR_PTR(-EFAULT);
|
||||
disp = (s64)insn.disp * 2;
|
||||
trampoline = (void *)(rec->ip + disp);
|
||||
if (get_kernel_nofault(opc, &trampoline->brasl_opc))
|
||||
return ERR_PTR(-EFAULT);
|
||||
if (opc != 0xc015)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
unsigned long addr)
|
||||
{
|
||||
struct ftrace_hotpatch_trampoline *trampoline;
|
||||
u64 old;
|
||||
|
||||
trampoline = ftrace_get_trampoline(rec);
|
||||
if (IS_ERR(trampoline))
|
||||
return PTR_ERR(trampoline);
|
||||
if (get_kernel_nofault(old, &trampoline->interceptor))
|
||||
return -EFAULT;
|
||||
if (old != old_addr)
|
||||
return -EINVAL;
|
||||
s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -188,6 +217,12 @@ static void brcl_enable(void *brcl)
|
||||
|
||||
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
struct ftrace_hotpatch_trampoline *trampoline;
|
||||
|
||||
trampoline = ftrace_get_trampoline(rec);
|
||||
if (IS_ERR(trampoline))
|
||||
return PTR_ERR(trampoline);
|
||||
s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
|
||||
brcl_enable((void *)rec->ip);
|
||||
return 0;
|
||||
}
|
||||
@ -291,7 +326,7 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
|
||||
|
||||
regs = ftrace_get_regs(fregs);
|
||||
p = get_kprobe((kprobe_opcode_t *)ip);
|
||||
if (unlikely(!p) || kprobe_disabled(p))
|
||||
if (!regs || unlikely(!p) || kprobe_disabled(p))
|
||||
goto out;
|
||||
|
||||
if (kprobe_running()) {
|
||||
|
@ -27,6 +27,7 @@ ENDPROC(ftrace_stub)
|
||||
#define STACK_PTREGS_GPRS (STACK_PTREGS + __PT_GPRS)
|
||||
#define STACK_PTREGS_PSW (STACK_PTREGS + __PT_PSW)
|
||||
#define STACK_PTREGS_ORIG_GPR2 (STACK_PTREGS + __PT_ORIG_GPR2)
|
||||
#define STACK_PTREGS_FLAGS (STACK_PTREGS + __PT_FLAGS)
|
||||
#ifdef __PACK_STACK
|
||||
/* allocate just enough for r14, r15 and backchain */
|
||||
#define TRACED_FUNC_FRAME_SIZE 24
|
||||
@ -57,6 +58,14 @@ ENDPROC(ftrace_stub)
|
||||
.if \allregs == 1
|
||||
stg %r14,(STACK_PTREGS_PSW)(%r15)
|
||||
stosm (STACK_PTREGS_PSW)(%r15),0
|
||||
#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
|
||||
mvghi STACK_PTREGS_FLAGS(%r15),_PIF_FTRACE_FULL_REGS
|
||||
#else
|
||||
lghi %r14,_PIF_FTRACE_FULL_REGS
|
||||
stg %r14,STACK_PTREGS_FLAGS(%r15)
|
||||
#endif
|
||||
.else
|
||||
xc STACK_PTREGS_FLAGS(8,%r15),STACK_PTREGS_FLAGS(%r15)
|
||||
.endif
|
||||
|
||||
lg %r14,(__SF_GPRS+8*8)(%r1) # restore original return address
|
||||
|
@ -800,6 +800,8 @@ static void __init check_initrd(void)
|
||||
static void __init reserve_kernel(void)
|
||||
{
|
||||
memblock_reserve(0, STARTUP_NORMAL_OFFSET);
|
||||
memblock_reserve(OLDMEM_BASE, sizeof(unsigned long));
|
||||
memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long));
|
||||
memblock_reserve(__amode31_base, __eamode31 - __samode31);
|
||||
memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
|
||||
memblock_reserve(__pa(_stext), _end - _stext);
|
||||
|
@ -860,7 +860,9 @@ static const char *keys[KEY_MAX + 1] = {
|
||||
[KEY_F22] = "F22", [KEY_F23] = "F23",
|
||||
[KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD",
|
||||
[KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3",
|
||||
[KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend",
|
||||
[KEY_PROG4] = "Prog4",
|
||||
[KEY_ALL_APPLICATIONS] = "AllApplications",
|
||||
[KEY_SUSPEND] = "Suspend",
|
||||
[KEY_CLOSE] = "Close", [KEY_PLAY] = "Play",
|
||||
[KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost",
|
||||
[KEY_PRINT] = "Print", [KEY_HP] = "HP",
|
||||
@ -969,6 +971,7 @@ static const char *keys[KEY_MAX + 1] = {
|
||||
[KEY_ASSISTANT] = "Assistant",
|
||||
[KEY_KBD_LAYOUT_NEXT] = "KbdLayoutNext",
|
||||
[KEY_EMOJI_PICKER] = "EmojiPicker",
|
||||
[KEY_DICTATE] = "Dictate",
|
||||
[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
|
||||
[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
|
||||
[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
|
||||
|
@ -992,6 +992,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
|
||||
case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break;
|
||||
|
||||
case 0x0d8: map_key_clear(KEY_DICTATE); break;
|
||||
case 0x0d9: map_key_clear(KEY_EMOJI_PICKER); break;
|
||||
|
||||
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
|
||||
@ -1083,6 +1084,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
|
||||
case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT); break;
|
||||
|
||||
case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS); break;
|
||||
|
||||
case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break;
|
||||
case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break;
|
||||
case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break;
|
||||
|
@ -556,7 +556,7 @@ config KEYBOARD_PMIC8XXX
|
||||
|
||||
config KEYBOARD_SAMSUNG
|
||||
tristate "Samsung keypad support"
|
||||
depends on HAVE_CLK
|
||||
depends on HAS_IOMEM && HAVE_CLK
|
||||
select INPUT_MATRIXKMAP
|
||||
help
|
||||
Say Y here if you want to use the keypad on your Samsung mobile
|
||||
|
@ -186,55 +186,21 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_enable_power(struct elan_tp_data *data)
|
||||
static int elan_set_power(struct elan_tp_data *data, bool on)
|
||||
{
|
||||
int repeat = ETP_RETRY_COUNT;
|
||||
int error;
|
||||
|
||||
error = regulator_enable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to enable regulator: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
do {
|
||||
error = data->ops->power_control(data->client, true);
|
||||
error = data->ops->power_control(data->client, on);
|
||||
if (error >= 0)
|
||||
return 0;
|
||||
|
||||
msleep(30);
|
||||
} while (--repeat > 0);
|
||||
|
||||
dev_err(&data->client->dev, "failed to enable power: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int elan_disable_power(struct elan_tp_data *data)
|
||||
{
|
||||
int repeat = ETP_RETRY_COUNT;
|
||||
int error;
|
||||
|
||||
do {
|
||||
error = data->ops->power_control(data->client, false);
|
||||
if (!error) {
|
||||
error = regulator_disable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to disable regulator: %d\n",
|
||||
error);
|
||||
/* Attempt to power the chip back up */
|
||||
data->ops->power_control(data->client, true);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
msleep(30);
|
||||
} while (--repeat > 0);
|
||||
|
||||
dev_err(&data->client->dev, "failed to disable power: %d\n", error);
|
||||
dev_err(&data->client->dev, "failed to set power %s: %d\n",
|
||||
on ? "on" : "off", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1399,9 +1365,19 @@ static int __maybe_unused elan_suspend(struct device *dev)
|
||||
/* Enable wake from IRQ */
|
||||
data->irq_wake = (enable_irq_wake(client->irq) == 0);
|
||||
} else {
|
||||
ret = elan_disable_power(data);
|
||||
ret = elan_set_power(data, false);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = regulator_disable(data->vcc);
|
||||
if (ret) {
|
||||
dev_err(dev, "error %d disabling regulator\n", ret);
|
||||
/* Attempt to power the chip back up */
|
||||
elan_set_power(data, true);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&data->sysfs_mutex);
|
||||
return ret;
|
||||
}
|
||||
@ -1412,12 +1388,18 @@ static int __maybe_unused elan_resume(struct device *dev)
|
||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||
int error;
|
||||
|
||||
if (device_may_wakeup(dev) && data->irq_wake) {
|
||||
if (!device_may_wakeup(dev)) {
|
||||
error = regulator_enable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(dev, "error %d enabling regulator\n", error);
|
||||
goto err;
|
||||
}
|
||||
} else if (data->irq_wake) {
|
||||
disable_irq_wake(client->irq);
|
||||
data->irq_wake = false;
|
||||
}
|
||||
|
||||
error = elan_enable_power(data);
|
||||
error = elan_set_power(data, true);
|
||||
if (error) {
|
||||
dev_err(dev, "power up when resuming failed: %d\n", error);
|
||||
goto err;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_data/x86/soc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
@ -805,21 +806,6 @@ static int goodix_reset(struct goodix_ts_data *ts)
|
||||
}
|
||||
|
||||
#ifdef ACPI_GPIO_SUPPORT
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/intel-family.h>
|
||||
|
||||
static const struct x86_cpu_id baytrail_cpu_ids[] = {
|
||||
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, X86_FEATURE_ANY, },
|
||||
{}
|
||||
};
|
||||
|
||||
static inline bool is_byt(void)
|
||||
{
|
||||
const struct x86_cpu_id *id = x86_match_cpu(baytrail_cpu_ids);
|
||||
|
||||
return !!id;
|
||||
}
|
||||
|
||||
static const struct acpi_gpio_params first_gpio = { 0, 0, false };
|
||||
static const struct acpi_gpio_params second_gpio = { 1, 0, false };
|
||||
|
||||
@ -878,7 +864,7 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
|
||||
const struct acpi_gpio_mapping *gpio_mapping = NULL;
|
||||
struct device *dev = &ts->client->dev;
|
||||
LIST_HEAD(resources);
|
||||
int ret;
|
||||
int irq, ret;
|
||||
|
||||
ts->gpio_count = 0;
|
||||
ts->gpio_int_idx = -1;
|
||||
@ -891,6 +877,20 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
|
||||
|
||||
acpi_dev_free_resource_list(&resources);
|
||||
|
||||
/*
|
||||
* CHT devices should have a GpioInt + a regular GPIO ACPI resource.
|
||||
* Some CHT devices have a bug (where the also is bogus Interrupt
|
||||
* resource copied from a previous BYT based generation). i2c-core-acpi
|
||||
* will use the non-working Interrupt resource, fix this up.
|
||||
*/
|
||||
if (soc_intel_is_cht() && ts->gpio_count == 2 && ts->gpio_int_idx != -1) {
|
||||
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
|
||||
if (irq > 0 && irq != ts->client->irq) {
|
||||
dev_warn(dev, "Overriding IRQ %d -> %d\n", ts->client->irq, irq);
|
||||
ts->client->irq = irq;
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
|
||||
ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
|
||||
gpio_mapping = acpi_goodix_int_first_gpios;
|
||||
@ -903,7 +903,7 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
|
||||
dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n");
|
||||
ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD;
|
||||
gpio_mapping = acpi_goodix_reset_only_gpios;
|
||||
} else if (is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
|
||||
} else if (soc_intel_is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
|
||||
dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
|
||||
ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
|
||||
gpio_mapping = acpi_goodix_int_last_gpios;
|
||||
|
@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
|
||||
|
||||
name = arch_vma_name(vma);
|
||||
if (!name) {
|
||||
const char *anon_name;
|
||||
struct anon_vma_name *anon_name;
|
||||
|
||||
if (!mm) {
|
||||
name = "[vdso]";
|
||||
@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
|
||||
goto done;
|
||||
}
|
||||
|
||||
anon_name = vma_anon_name(vma);
|
||||
anon_name = anon_vma_name(vma);
|
||||
if (anon_name) {
|
||||
seq_pad(m, ' ');
|
||||
seq_printf(m, "[anon:%s]", anon_name);
|
||||
seq_printf(m, "[anon:%s]", anon_name->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1597,7 +1597,8 @@ static const struct mm_walk_ops pagemap_ops = {
|
||||
* Bits 5-54 swap offset if swapped
|
||||
* Bit 55 pte is soft-dirty (see Documentation/admin-guide/mm/soft-dirty.rst)
|
||||
* Bit 56 page exclusively mapped
|
||||
* Bits 57-60 zero
|
||||
* Bit 57 pte is uffd-wp write-protected
|
||||
* Bits 58-60 zero
|
||||
* Bit 61 page is file-page or shared-anon
|
||||
* Bit 62 page swapped
|
||||
* Bit 63 page present
|
||||
|
@ -878,7 +878,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
|
||||
new_flags, vma->anon_vma,
|
||||
vma->vm_file, vma->vm_pgoff,
|
||||
vma_policy(vma),
|
||||
NULL_VM_UFFD_CTX, vma_anon_name(vma));
|
||||
NULL_VM_UFFD_CTX, anon_vma_name(vma));
|
||||
if (prev)
|
||||
vma = prev;
|
||||
else
|
||||
@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
|
||||
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
|
||||
vma_policy(vma),
|
||||
((struct vm_userfaultfd_ctx){ ctx }),
|
||||
vma_anon_name(vma));
|
||||
anon_vma_name(vma));
|
||||
if (prev) {
|
||||
vma = prev;
|
||||
goto next;
|
||||
@ -1615,7 +1615,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
|
||||
prev = vma_merge(mm, prev, start, vma_end, new_flags,
|
||||
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
|
||||
vma_policy(vma),
|
||||
NULL_VM_UFFD_CTX, vma_anon_name(vma));
|
||||
NULL_VM_UFFD_CTX, anon_vma_name(vma));
|
||||
if (prev) {
|
||||
vma = prev;
|
||||
goto next;
|
||||
|
@ -2626,7 +2626,7 @@ static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start,
|
||||
extern struct vm_area_struct *vma_merge(struct mm_struct *,
|
||||
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
|
||||
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
|
||||
struct mempolicy *, struct vm_userfaultfd_ctx, const char *);
|
||||
struct mempolicy *, struct vm_userfaultfd_ctx, struct anon_vma_name *);
|
||||
extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
|
||||
extern int __split_vma(struct mm_struct *, struct vm_area_struct *,
|
||||
unsigned long addr, int new_below);
|
||||
@ -3372,11 +3372,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma)
|
||||
|
||||
#ifdef CONFIG_ANON_VMA_NAME
|
||||
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
|
||||
unsigned long len_in, const char *name);
|
||||
unsigned long len_in,
|
||||
struct anon_vma_name *anon_name);
|
||||
#else
|
||||
static inline int
|
||||
madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
|
||||
unsigned long len_in, const char *name) {
|
||||
unsigned long len_in, struct anon_vma_name *anon_name) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -140,50 +140,91 @@ static __always_inline void del_page_from_lru_list(struct page *page,
|
||||
|
||||
#ifdef CONFIG_ANON_VMA_NAME
|
||||
/*
|
||||
* mmap_lock should be read-locked when calling vma_anon_name() and while using
|
||||
* the returned pointer.
|
||||
* mmap_lock should be read-locked when calling anon_vma_name(). Caller should
|
||||
* either keep holding the lock while using the returned pointer or it should
|
||||
* raise anon_vma_name refcount before releasing the lock.
|
||||
*/
|
||||
extern const char *vma_anon_name(struct vm_area_struct *vma);
|
||||
|
||||
/*
|
||||
* mmap_lock should be read-locked for orig_vma->vm_mm.
|
||||
* mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be
|
||||
* isolated.
|
||||
*/
|
||||
extern void dup_vma_anon_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma);
|
||||
|
||||
/*
|
||||
* mmap_lock should be write-locked or vma should have been isolated under
|
||||
* write-locked mmap_lock protection.
|
||||
*/
|
||||
extern void free_vma_anon_name(struct vm_area_struct *vma);
|
||||
extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma);
|
||||
extern struct anon_vma_name *anon_vma_name_alloc(const char *name);
|
||||
extern void anon_vma_name_free(struct kref *kref);
|
||||
|
||||
/* mmap_lock should be read-locked */
|
||||
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
|
||||
const char *name)
|
||||
static inline void anon_vma_name_get(struct anon_vma_name *anon_name)
|
||||
{
|
||||
const char *vma_name = vma_anon_name(vma);
|
||||
if (anon_name)
|
||||
kref_get(&anon_name->kref);
|
||||
}
|
||||
|
||||
/* either both NULL, or pointers to same string */
|
||||
if (vma_name == name)
|
||||
static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
|
||||
{
|
||||
if (anon_name)
|
||||
kref_put(&anon_name->kref, anon_vma_name_free);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name)
|
||||
{
|
||||
/* Prevent anon_name refcount saturation early on */
|
||||
if (kref_read(&anon_name->kref) < REFCOUNT_MAX) {
|
||||
anon_vma_name_get(anon_name);
|
||||
return anon_name;
|
||||
|
||||
}
|
||||
return anon_vma_name_alloc(anon_name->name);
|
||||
}
|
||||
|
||||
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma)
|
||||
{
|
||||
struct anon_vma_name *anon_name = anon_vma_name(orig_vma);
|
||||
|
||||
if (anon_name)
|
||||
new_vma->anon_name = anon_vma_name_reuse(anon_name);
|
||||
}
|
||||
|
||||
static inline void free_anon_vma_name(struct vm_area_struct *vma)
|
||||
{
|
||||
/*
|
||||
* Not using anon_vma_name because it generates a warning if mmap_lock
|
||||
* is not held, which might be the case here.
|
||||
*/
|
||||
if (!vma->vm_file)
|
||||
anon_vma_name_put(vma->anon_name);
|
||||
}
|
||||
|
||||
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
|
||||
struct anon_vma_name *anon_name2)
|
||||
{
|
||||
if (anon_name1 == anon_name2)
|
||||
return true;
|
||||
|
||||
return name && vma_name && !strcmp(name, vma_name);
|
||||
return anon_name1 && anon_name2 &&
|
||||
!strcmp(anon_name1->name, anon_name2->name);
|
||||
}
|
||||
|
||||
#else /* CONFIG_ANON_VMA_NAME */
|
||||
static inline const char *vma_anon_name(struct vm_area_struct *vma)
|
||||
static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma) {}
|
||||
static inline void free_vma_anon_name(struct vm_area_struct *vma) {}
|
||||
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
|
||||
const char *name)
|
||||
|
||||
static inline struct anon_vma_name *anon_vma_name_alloc(const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {}
|
||||
static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {}
|
||||
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma) {}
|
||||
static inline void free_anon_vma_name(struct vm_area_struct *vma) {}
|
||||
|
||||
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
|
||||
struct anon_vma_name *anon_name2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ANON_VMA_NAME */
|
||||
|
||||
static inline void init_tlb_flush_pending(struct mm_struct *mm)
|
||||
|
@ -416,7 +416,10 @@ struct vm_area_struct {
|
||||
struct rb_node rb;
|
||||
unsigned long rb_subtree_last;
|
||||
} shared;
|
||||
/* Serialized by mmap_sem. */
|
||||
/*
|
||||
* Serialized by mmap_sem. Never use directly because it is
|
||||
* valid only when vm_file is NULL. Use anon_vma_name instead.
|
||||
*/
|
||||
struct anon_vma_name *anon_name;
|
||||
};
|
||||
|
||||
|
@ -278,7 +278,8 @@
|
||||
#define KEY_PAUSECD 201
|
||||
#define KEY_PROG3 202
|
||||
#define KEY_PROG4 203
|
||||
#define KEY_DASHBOARD 204 /* AL Dashboard */
|
||||
#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */
|
||||
#define KEY_DASHBOARD KEY_ALL_APPLICATIONS
|
||||
#define KEY_SUSPEND 205
|
||||
#define KEY_CLOSE 206 /* AC Close */
|
||||
#define KEY_PLAY 207
|
||||
@ -612,6 +613,7 @@
|
||||
#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
|
||||
#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */
|
||||
#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */
|
||||
#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */
|
||||
|
||||
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
|
||||
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
|
||||
|
@ -16,7 +16,7 @@ CONFIG_SYMBOLIC_ERRNAME=y
|
||||
#
|
||||
# Compile-time checks and compiler options
|
||||
#
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_FRAME_WARN=2048
|
||||
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
|
||||
|
@ -372,14 +372,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
|
||||
*new = data_race(*orig);
|
||||
INIT_LIST_HEAD(&new->anon_vma_chain);
|
||||
new->vm_next = new->vm_prev = NULL;
|
||||
dup_vma_anon_name(orig, new);
|
||||
dup_anon_vma_name(orig, new);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
void vm_area_free(struct vm_area_struct *vma)
|
||||
{
|
||||
free_vma_anon_name(vma);
|
||||
free_anon_vma_name(vma);
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
}
|
||||
|
||||
|
19
kernel/sys.c
19
kernel/sys.c
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mm_inline.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/reboot.h>
|
||||
@ -2288,15 +2289,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
const char __user *uname;
|
||||
char *name, *pch;
|
||||
struct anon_vma_name *anon_name = NULL;
|
||||
int error;
|
||||
|
||||
switch (opt) {
|
||||
case PR_SET_VMA_ANON_NAME:
|
||||
uname = (const char __user *)arg;
|
||||
if (uname) {
|
||||
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
|
||||
char *name, *pch;
|
||||
|
||||
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
@ -2306,15 +2308,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Reset the name */
|
||||
name = NULL;
|
||||
/* anon_vma has its own copy */
|
||||
anon_name = anon_vma_name_alloc(name);
|
||||
kfree(name);
|
||||
if (!anon_name)
|
||||
return -ENOMEM;
|
||||
|
||||
}
|
||||
|
||||
mmap_write_lock(mm);
|
||||
error = madvise_set_anon_name(mm, addr, size, name);
|
||||
error = madvise_set_anon_name(mm, addr, size, anon_name);
|
||||
mmap_write_unlock(mm);
|
||||
kfree(name);
|
||||
anon_vma_name_put(anon_name);
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
|
92
mm/madvise.c
92
mm/madvise.c
@ -65,7 +65,7 @@ static int madvise_need_mmap_write(int behavior)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ANON_VMA_NAME
|
||||
static struct anon_vma_name *anon_vma_name_alloc(const char *name)
|
||||
struct anon_vma_name *anon_vma_name_alloc(const char *name)
|
||||
{
|
||||
struct anon_vma_name *anon_name;
|
||||
size_t count;
|
||||
@ -81,78 +81,48 @@ static struct anon_vma_name *anon_vma_name_alloc(const char *name)
|
||||
return anon_name;
|
||||
}
|
||||
|
||||
static void vma_anon_name_free(struct kref *kref)
|
||||
void anon_vma_name_free(struct kref *kref)
|
||||
{
|
||||
struct anon_vma_name *anon_name =
|
||||
container_of(kref, struct anon_vma_name, kref);
|
||||
kfree(anon_name);
|
||||
}
|
||||
|
||||
static inline bool has_vma_anon_name(struct vm_area_struct *vma)
|
||||
struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
|
||||
{
|
||||
return !vma->vm_file && vma->anon_name;
|
||||
}
|
||||
|
||||
const char *vma_anon_name(struct vm_area_struct *vma)
|
||||
{
|
||||
if (!has_vma_anon_name(vma))
|
||||
return NULL;
|
||||
|
||||
mmap_assert_locked(vma->vm_mm);
|
||||
|
||||
return vma->anon_name->name;
|
||||
}
|
||||
if (vma->vm_file)
|
||||
return NULL;
|
||||
|
||||
void dup_vma_anon_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma)
|
||||
{
|
||||
if (!has_vma_anon_name(orig_vma))
|
||||
return;
|
||||
|
||||
kref_get(&orig_vma->anon_name->kref);
|
||||
new_vma->anon_name = orig_vma->anon_name;
|
||||
}
|
||||
|
||||
void free_vma_anon_name(struct vm_area_struct *vma)
|
||||
{
|
||||
struct anon_vma_name *anon_name;
|
||||
|
||||
if (!has_vma_anon_name(vma))
|
||||
return;
|
||||
|
||||
anon_name = vma->anon_name;
|
||||
vma->anon_name = NULL;
|
||||
kref_put(&anon_name->kref, vma_anon_name_free);
|
||||
return vma->anon_name;
|
||||
}
|
||||
|
||||
/* mmap_lock should be write-locked */
|
||||
static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
|
||||
static int replace_anon_vma_name(struct vm_area_struct *vma,
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
const char *anon_name;
|
||||
struct anon_vma_name *orig_name = anon_vma_name(vma);
|
||||
|
||||
if (!name) {
|
||||
free_vma_anon_name(vma);
|
||||
if (!anon_name) {
|
||||
vma->anon_name = NULL;
|
||||
anon_vma_name_put(orig_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
anon_name = vma_anon_name(vma);
|
||||
if (anon_name) {
|
||||
/* Same name, nothing to do here */
|
||||
if (!strcmp(name, anon_name))
|
||||
return 0;
|
||||
if (anon_vma_name_eq(orig_name, anon_name))
|
||||
return 0;
|
||||
|
||||
free_vma_anon_name(vma);
|
||||
}
|
||||
vma->anon_name = anon_vma_name_alloc(name);
|
||||
if (!vma->anon_name)
|
||||
return -ENOMEM;
|
||||
vma->anon_name = anon_vma_name_reuse(anon_name);
|
||||
anon_vma_name_put(orig_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_ANON_VMA_NAME */
|
||||
static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
|
||||
static int replace_anon_vma_name(struct vm_area_struct *vma,
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
if (name)
|
||||
if (anon_name)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@ -161,17 +131,19 @@ static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
|
||||
/*
|
||||
* Update the vm_flags on region of a vma, splitting it or merging it as
|
||||
* necessary. Must be called with mmap_sem held for writing;
|
||||
* Caller should ensure anon_name stability by raising its refcount even when
|
||||
* anon_name belongs to a valid vma because this function might free that vma.
|
||||
*/
|
||||
static int madvise_update_vma(struct vm_area_struct *vma,
|
||||
struct vm_area_struct **prev, unsigned long start,
|
||||
unsigned long end, unsigned long new_flags,
|
||||
const char *name)
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
struct mm_struct *mm = vma->vm_mm;
|
||||
int error;
|
||||
pgoff_t pgoff;
|
||||
|
||||
if (new_flags == vma->vm_flags && is_same_vma_anon_name(vma, name)) {
|
||||
if (new_flags == vma->vm_flags && anon_vma_name_eq(anon_vma_name(vma), anon_name)) {
|
||||
*prev = vma;
|
||||
return 0;
|
||||
}
|
||||
@ -179,7 +151,7 @@ static int madvise_update_vma(struct vm_area_struct *vma,
|
||||
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
|
||||
*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
|
||||
vma->vm_file, pgoff, vma_policy(vma),
|
||||
vma->vm_userfaultfd_ctx, name);
|
||||
vma->vm_userfaultfd_ctx, anon_name);
|
||||
if (*prev) {
|
||||
vma = *prev;
|
||||
goto success;
|
||||
@ -209,7 +181,7 @@ static int madvise_update_vma(struct vm_area_struct *vma,
|
||||
*/
|
||||
vma->vm_flags = new_flags;
|
||||
if (!vma->vm_file) {
|
||||
error = replace_vma_anon_name(vma, name);
|
||||
error = replace_anon_vma_name(vma, anon_name);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@ -975,6 +947,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
|
||||
unsigned long behavior)
|
||||
{
|
||||
int error;
|
||||
struct anon_vma_name *anon_name;
|
||||
unsigned long new_flags = vma->vm_flags;
|
||||
|
||||
switch (behavior) {
|
||||
@ -1040,8 +1013,11 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
|
||||
break;
|
||||
}
|
||||
|
||||
anon_name = anon_vma_name(vma);
|
||||
anon_vma_name_get(anon_name);
|
||||
error = madvise_update_vma(vma, prev, start, end, new_flags,
|
||||
vma_anon_name(vma));
|
||||
anon_name);
|
||||
anon_vma_name_put(anon_name);
|
||||
|
||||
out:
|
||||
/*
|
||||
@ -1225,7 +1201,7 @@ int madvise_walk_vmas(struct mm_struct *mm, unsigned long start,
|
||||
static int madvise_vma_anon_name(struct vm_area_struct *vma,
|
||||
struct vm_area_struct **prev,
|
||||
unsigned long start, unsigned long end,
|
||||
unsigned long name)
|
||||
unsigned long anon_name)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -1234,7 +1210,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
|
||||
return -EBADF;
|
||||
|
||||
error = madvise_update_vma(vma, prev, start, end, vma->vm_flags,
|
||||
(const char *)name);
|
||||
(struct anon_vma_name *)anon_name);
|
||||
|
||||
/*
|
||||
* madvise() returns EAGAIN if kernel resources, such as
|
||||
@ -1246,7 +1222,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
|
||||
}
|
||||
|
||||
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
|
||||
unsigned long len_in, const char *name)
|
||||
unsigned long len_in, struct anon_vma_name *anon_name)
|
||||
{
|
||||
unsigned long end;
|
||||
unsigned long len;
|
||||
@ -1266,7 +1242,7 @@ int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
|
||||
if (end == start)
|
||||
return 0;
|
||||
|
||||
return madvise_walk_vmas(mm, start, end, (unsigned long)name,
|
||||
return madvise_walk_vmas(mm, start, end, (unsigned long)anon_name,
|
||||
madvise_vma_anon_name);
|
||||
}
|
||||
#endif /* CONFIG_ANON_VMA_NAME */
|
||||
|
42
mm/memfd.c
42
mm/memfd.c
@ -31,20 +31,28 @@
|
||||
static void memfd_tag_pins(struct xa_state *xas)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned int tagged = 0;
|
||||
int latency = 0;
|
||||
int cache_count;
|
||||
|
||||
lru_add_drain();
|
||||
|
||||
xas_lock_irq(xas);
|
||||
xas_for_each(xas, page, ULONG_MAX) {
|
||||
if (xa_is_value(page))
|
||||
continue;
|
||||
page = find_subpage(page, xas->xa_index);
|
||||
if (page_count(page) - page_mapcount(page) > 1)
|
||||
xas_set_mark(xas, MEMFD_TAG_PINNED);
|
||||
cache_count = 1;
|
||||
if (!xa_is_value(page) &&
|
||||
PageTransHuge(page) && !PageHuge(page))
|
||||
cache_count = HPAGE_PMD_NR;
|
||||
|
||||
if (++tagged % XA_CHECK_SCHED)
|
||||
if (!xa_is_value(page) &&
|
||||
page_count(page) - total_mapcount(page) != cache_count)
|
||||
xas_set_mark(xas, MEMFD_TAG_PINNED);
|
||||
if (cache_count != 1)
|
||||
xas_set(xas, page->index + cache_count);
|
||||
|
||||
latency += cache_count;
|
||||
if (latency < XA_CHECK_SCHED)
|
||||
continue;
|
||||
latency = 0;
|
||||
|
||||
xas_pause(xas);
|
||||
xas_unlock_irq(xas);
|
||||
@ -73,7 +81,8 @@ static int memfd_wait_for_pins(struct address_space *mapping)
|
||||
|
||||
error = 0;
|
||||
for (scan = 0; scan <= LAST_SCAN; scan++) {
|
||||
unsigned int tagged = 0;
|
||||
int latency = 0;
|
||||
int cache_count;
|
||||
|
||||
if (!xas_marked(&xas, MEMFD_TAG_PINNED))
|
||||
break;
|
||||
@ -87,10 +96,14 @@ static int memfd_wait_for_pins(struct address_space *mapping)
|
||||
xas_lock_irq(&xas);
|
||||
xas_for_each_marked(&xas, page, ULONG_MAX, MEMFD_TAG_PINNED) {
|
||||
bool clear = true;
|
||||
if (xa_is_value(page))
|
||||
continue;
|
||||
page = find_subpage(page, xas.xa_index);
|
||||
if (page_count(page) - page_mapcount(page) != 1) {
|
||||
|
||||
cache_count = 1;
|
||||
if (!xa_is_value(page) &&
|
||||
PageTransHuge(page) && !PageHuge(page))
|
||||
cache_count = HPAGE_PMD_NR;
|
||||
|
||||
if (!xa_is_value(page) && cache_count !=
|
||||
page_count(page) - total_mapcount(page)) {
|
||||
/*
|
||||
* On the last scan, we clean up all those tags
|
||||
* we inserted; but make a note that we still
|
||||
@ -103,8 +116,11 @@ static int memfd_wait_for_pins(struct address_space *mapping)
|
||||
}
|
||||
if (clear)
|
||||
xas_clear_mark(&xas, MEMFD_TAG_PINNED);
|
||||
if (++tagged % XA_CHECK_SCHED)
|
||||
|
||||
latency += cache_count;
|
||||
if (latency < XA_CHECK_SCHED)
|
||||
continue;
|
||||
latency = 0;
|
||||
|
||||
xas_pause(&xas);
|
||||
xas_unlock_irq(&xas);
|
||||
|
@ -814,7 +814,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
|
||||
prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
|
||||
vma->anon_vma, vma->vm_file, pgoff,
|
||||
new_pol, vma->vm_userfaultfd_ctx,
|
||||
vma_anon_name(vma));
|
||||
anon_vma_name(vma));
|
||||
if (prev) {
|
||||
vma = prev;
|
||||
next = vma->vm_next;
|
||||
|
@ -512,7 +512,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
||||
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
|
||||
*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
|
||||
vma->vm_file, pgoff, vma_policy(vma),
|
||||
vma->vm_userfaultfd_ctx, vma_anon_name(vma));
|
||||
vma->vm_userfaultfd_ctx, anon_vma_name(vma));
|
||||
if (*prev) {
|
||||
vma = *prev;
|
||||
goto success;
|
||||
|
12
mm/mmap.c
12
mm/mmap.c
@ -1031,7 +1031,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
|
||||
static inline int is_mergeable_vma(struct vm_area_struct *vma,
|
||||
struct file *file, unsigned long vm_flags,
|
||||
struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
|
||||
const char *anon_name)
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
/*
|
||||
* VM_SOFTDIRTY should not prevent from VMA merging, if we
|
||||
@ -1049,7 +1049,7 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
|
||||
return 0;
|
||||
if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx))
|
||||
return 0;
|
||||
if (!is_same_vma_anon_name(vma, anon_name))
|
||||
if (!anon_vma_name_eq(anon_vma_name(vma), anon_name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -1084,7 +1084,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
|
||||
struct anon_vma *anon_vma, struct file *file,
|
||||
pgoff_t vm_pgoff,
|
||||
struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
|
||||
const char *anon_name)
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) &&
|
||||
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
|
||||
@ -1106,7 +1106,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
|
||||
struct anon_vma *anon_vma, struct file *file,
|
||||
pgoff_t vm_pgoff,
|
||||
struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
|
||||
const char *anon_name)
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) &&
|
||||
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
|
||||
@ -1167,7 +1167,7 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
|
||||
struct anon_vma *anon_vma, struct file *file,
|
||||
pgoff_t pgoff, struct mempolicy *policy,
|
||||
struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
|
||||
const char *anon_name)
|
||||
struct anon_vma_name *anon_name)
|
||||
{
|
||||
pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
|
||||
struct vm_area_struct *area, *next;
|
||||
@ -3256,7 +3256,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
|
||||
return NULL; /* should never get here */
|
||||
new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
|
||||
vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
|
||||
vma->vm_userfaultfd_ctx, vma_anon_name(vma));
|
||||
vma->vm_userfaultfd_ctx, anon_vma_name(vma));
|
||||
if (new_vma) {
|
||||
/*
|
||||
* Source vma may have been merged into new_vma
|
||||
|
@ -464,7 +464,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
|
||||
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
|
||||
*pprev = vma_merge(mm, *pprev, start, end, newflags,
|
||||
vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
|
||||
vma->vm_userfaultfd_ctx, vma_anon_name(vma));
|
||||
vma->vm_userfaultfd_ctx, anon_vma_name(vma));
|
||||
if (*pprev) {
|
||||
vma = *pprev;
|
||||
VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY);
|
||||
|
@ -3,9 +3,10 @@
|
||||
* hugepage-mremap:
|
||||
*
|
||||
* Example of remapping huge page memory in a user application using the
|
||||
* mremap system call. Code assumes a hugetlbfs filesystem is mounted
|
||||
* at './huge'. The amount of memory used by this test is decided by a command
|
||||
* line argument in MBs. If missing, the default amount is 10MB.
|
||||
* mremap system call. The path to a file in a hugetlbfs filesystem must
|
||||
* be passed as the last argument to this test. The amount of memory used
|
||||
* by this test in MBs can optionally be passed as an argument. If no memory
|
||||
* amount is passed, the default amount is 10MB.
|
||||
*
|
||||
* To make sure the test triggers pmd sharing and goes through the 'unshare'
|
||||
* path in the mremap code use 1GB (1024) or more.
|
||||
@ -25,7 +26,6 @@
|
||||
#define DEFAULT_LENGTH_MB 10UL
|
||||
#define MB_TO_BYTES(x) (x * 1024 * 1024)
|
||||
|
||||
#define FILE_NAME "huge/hugepagefile"
|
||||
#define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
|
||||
|
||||
@ -107,17 +107,26 @@ static void register_region_with_uffd(char *addr, size_t len)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
size_t length;
|
||||
|
||||
if (argc != 2 && argc != 3) {
|
||||
printf("Usage: %s [length_in_MB] <hugetlb_file>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read memory length as the first arg if valid, otherwise fallback to
|
||||
* the default length. Any additional args are ignored.
|
||||
* the default length.
|
||||
*/
|
||||
size_t length = argc > 1 ? (size_t)atoi(argv[1]) : 0UL;
|
||||
if (argc == 3)
|
||||
length = argc > 2 ? (size_t)atoi(argv[1]) : 0UL;
|
||||
|
||||
length = length > 0 ? length : DEFAULT_LENGTH_MB;
|
||||
length = MB_TO_BYTES(length);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
int fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
|
||||
/* last arg is the hugetlb file name */
|
||||
int fd = open(argv[argc-1], O_CREAT | O_RDWR, 0755);
|
||||
|
||||
if (fd < 0) {
|
||||
perror("Open failed");
|
||||
@ -169,5 +178,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
munmap(addr, length);
|
||||
|
||||
close(fd);
|
||||
unlink(argv[argc-1]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -111,13 +111,14 @@ fi
|
||||
echo "-----------------------"
|
||||
echo "running hugepage-mremap"
|
||||
echo "-----------------------"
|
||||
./hugepage-mremap 256
|
||||
./hugepage-mremap $mnt/huge_mremap
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
exitcode=1
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
rm -f $mnt/huge_mremap
|
||||
|
||||
echo "NOTE: The above hugetlb tests provide minimal coverage. Use"
|
||||
echo " https://github.com/libhugetlbfs/libhugetlbfs.git for"
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <linux/mman.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
Loading…
Reference in New Issue
Block a user