Merge branch 'akpm' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Aug 2018 19:34:08 +0000 (12:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Aug 2018 19:34:08 +0000 (12:34 -0700)
Merge more updates from Andrew Morton:

 - the rest of MM

 - procfs updates

 - various misc things

 - more y2038 fixes

 - get_maintainer updates

 - lib/ updates

 - checkpatch updates

 - various epoll updates

 - autofs updates

 - hfsplus

 - some reiserfs work

 - fatfs updates

 - signal.c cleanups

 - ipc/ updates

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (166 commits)
  ipc/util.c: update return value of ipc_getref from int to bool
  ipc/util.c: further variable name cleanups
  ipc: simplify ipc initialization
  ipc: get rid of ids->tables_initialized hack
  lib/rhashtable: guarantee initial hashtable allocation
  lib/rhashtable: simplify bucket_table_alloc()
  ipc: drop ipc_lock()
  ipc/util.c: correct comment in ipc_obtain_object_check
  ipc: rename ipcctl_pre_down_nolock()
  ipc/util.c: use ipc_rcu_putref() for failues in ipc_addid()
  ipc: reorganize initialization of kern_ipc_perm.seq
  ipc: compute kern_ipc_perm.id under the ipc lock
  init/Kconfig: remove EXPERT from CHECKPOINT_RESTORE
  fs/sysv/inode.c: use ktime_get_real_seconds() for superblock stamp
  adfs: use timespec64 for time conversion
  kernel/sysctl.c: fix typos in comments
  drivers/rapidio/devices/rio_mport_cdev.c: remove redundant pointer md
  fork: don't copy inconsistent signal handler state to child
  signal: make get_signal() return bool
  signal: make sigkill_pending() return bool
  ...

182 files changed:
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/filesystems/proc.txt
Documentation/sysctl/kernel.txt
Documentation/sysctl/vm.txt
arch/Kconfig
arch/arm/kernel/process.c
arch/arm64/Kconfig
arch/powerpc/Kconfig
arch/x86/Kconfig
arch/x86/boot/compressed/kaslr.c
arch/x86/include/asm/Kbuild
arch/x86/include/asm/export.h [deleted file]
arch/x86/kvm/x86.c
drivers/block/zram/zram_drv.c
drivers/firmware/efi/libstub/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/radeon/radeon_mn.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/hfi1/mmu_rb.c
drivers/infiniband/hw/mlx5/odp.c
drivers/md/bcache/Kconfig
drivers/md/bcache/util.c
drivers/md/bcache/util.h
drivers/misc/mic/scif/scif_dma.c
drivers/misc/sgi-gru/grutlbpurge.c
drivers/pci/quirks.c
drivers/rapidio/devices/rio_mport_cdev.c
drivers/xen/gntdev.c
fs/adfs/inode.c
fs/autofs/autofs_i.h
fs/autofs/expire.c
fs/autofs/inode.c
fs/autofs/root.c
fs/eventpoll.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fat.h
fs/fat/fatent.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/hfsplus/Kconfig
fs/hfsplus/Makefile
fs/hfsplus/acl.h [deleted file]
fs/hfsplus/dir.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/posix_acl.c [deleted file]
fs/hfsplus/super.c
fs/hfsplus/unicode.c
fs/hfsplus/xattr.c
fs/hfsplus/xattr.h
fs/hfsplus/xattr_security.c
fs/hugetlbfs/inode.c
fs/nilfs2/file.c
fs/nilfs2/super.c
fs/proc/Kconfig
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/kcore.c
fs/proc/meminfo.c
fs/proc/stat.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/proc/uptime.c
fs/proc/vmcore.c
fs/reiserfs/item_ops.c
fs/reiserfs/journal.c
fs/reiserfs/procfs.c
fs/reiserfs/reiserfs.h
fs/reiserfs/xattr.c
fs/sysv/inode.c
fs/userfaultfd.c
include/asm-generic/bug.h
include/asm-generic/export.h
include/linux/backing-dev-defs.h
include/linux/backing-dev.h
include/linux/bitops.h
include/linux/compiler.h
include/linux/crash_core.h
include/linux/crc64.h [new file with mode: 0644]
include/linux/export.h
include/linux/init.h
include/linux/ipc_namespace.h
include/linux/kcore.h
include/linux/kernel.h
include/linux/kvm_host.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mm.h
include/linux/mmu_notifier.h
include/linux/mmzone.h
include/linux/net_dim.h
include/linux/nodemask.h
include/linux/oom.h
include/linux/pci.h
include/linux/percpu.h
include/linux/proc_fs.h
include/linux/sched.h
include/linux/sched/signal.h
include/linux/sched/sysctl.h
include/linux/sched/user.h
include/linux/shrinker.h
include/linux/signal.h
include/linux/swap.h
include/linux/tracepoint.h
include/rdma/ib_umem_odp.h
include/uapi/linux/auto_fs.h
init/Kconfig
init/do_mounts.c
init/do_mounts_initrd.c
init/do_mounts_md.c
init/do_mounts_rd.c
init/initramfs.c
init/main.c
ipc/msg.c
ipc/namespace.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/crash_core.c
kernel/fork.c
kernel/hung_task.c
kernel/module.c
kernel/printk/printk.c
kernel/sched/wait.c
kernel/signal.c
kernel/sysctl.c
kernel/tracepoint.c
kernel/user.c
lib/.gitignore
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/bitmap.c
lib/crc64.c [new file with mode: 0644]
lib/gen_crc64table.c [new file with mode: 0644]
lib/rhashtable.c
lib/test_debug_virtual.c
lib/test_hexdump.c
mm/Kconfig.debug
mm/backing-dev.c
mm/hmm.c
mm/internal.h
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/mm_init.c
mm/mmap.c
mm/mmu_notifier.c
mm/oom_kill.c
mm/page_alloc.c
mm/percpu.c
mm/shmem.c
mm/swap_slots.c
mm/swapfile.c
mm/vmscan.c
scripts/checkpatch.pl
scripts/get_maintainer.pl
scripts/spelling.txt
security/security.c
tools/testing/selftests/proc/.gitignore
tools/testing/selftests/proc/Makefile
tools/testing/selftests/proc/proc.h
tools/testing/selftests/proc/self.c [new file with mode: 0644]
tools/testing/selftests/proc/thread-self.c [new file with mode: 0644]
tools/testing/selftests/vm/.gitignore
tools/testing/selftests/vm/Makefile
tools/testing/selftests/vm/map_populate.c [new file with mode: 0644]
tools/testing/selftests/vm/run_vmtests
virt/kvm/kvm_main.c

index 1746131bc9cb315dca4d4b03b23678cece518727..184193bcb262ac908f1f5a7a7c2c662dec0ea4b8 100644 (file)
@@ -1072,6 +1072,24 @@ PAGE_SIZE multiple when read back.
        high limit is used and monitored properly, this limit's
        utility is limited to providing the final safety net.
 
+  memory.oom.group
+       A read-write single value file which exists on non-root
+       cgroups.  The default value is "0".
+
+       Determines whether the cgroup should be treated as
+       an indivisible workload by the OOM killer. If set,
+       all tasks belonging to the cgroup or to its descendants
+       (if the memory cgroup is not a leaf cgroup) are killed
+       together or not at all. This can be used to avoid
+       partial kills to guarantee workload integrity.
+
+       Tasks with the OOM protection (oom_score_adj set to -1000)
+       are treated as an exception and are never killed.
+
+       If the OOM killer is invoked in a cgroup, it's not going
+       to kill any tasks outside of this cgroup, regardless
+       memory.oom.group values of ancestor cgroups.
+
   memory.events
        A read-only flat-keyed file which exists on non-root cgroups.
        The following entries are defined.  Unless specified
index bffb0caa369305e221108ae7557605acf7809b89..970d837bd57fcaf73479e457279a0d300835619b 100644 (file)
                        on: enable the feature
 
        page_poison=    [KNL] Boot-time parameter changing the state of
-                       poisoning on the buddy allocator.
-                       off: turn off poisoning
+                       poisoning on the buddy allocator, available with
+                       CONFIG_PAGE_POISONING=y.
+                       off: turn off poisoning (default)
                        on: turn on poisoning
 
        panic=          [KNL] Kernel behaviour on panic: delay <timeout>
index 1605acbb23b6631f11d4979017e361360c4208a2..22b4b00dee31290bde37b3abc63f4a0807f973cc 100644 (file)
@@ -870,6 +870,7 @@ Committed_AS:   100056 kB
 VmallocTotal:   112216 kB
 VmallocUsed:       428 kB
 VmallocChunk:   111088 kB
+Percpu:          62080 kB
 HardwareCorrupted:   0 kB
 AnonHugePages:   49152 kB
 ShmemHugePages:      0 kB
@@ -962,6 +963,8 @@ Committed_AS: The amount of memory presently allocated on the system.
 VmallocTotal: total size of vmalloc memory area
  VmallocUsed: amount of vmalloc area which is used
 VmallocChunk: largest contiguous block of vmalloc area which is free
+      Percpu: Memory allocated to the percpu allocator used to back percpu
+              allocations. This stat excludes the cost of metadata.
 
 ..............................................................................
 
index 59585030cbafa4e6a489980caf54234b5c91eeef..37a679501ddc68bc0ab26c58444794c0d30c8f40 100644 (file)
@@ -38,6 +38,7 @@ show up in /proc/sys/kernel:
 - hung_task_panic
 - hung_task_check_count
 - hung_task_timeout_secs
+- hung_task_check_interval_secs
 - hung_task_warnings
 - hyperv_record_panic_msg
 - kexec_load_disabled
@@ -355,7 +356,7 @@ This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
 
 hung_task_timeout_secs:
 
-Check interval. When a task in D state did not get scheduled
+When a task in D state did not get scheduled
 for more than this value report a warning.
 This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
 
@@ -364,6 +365,18 @@ Possible values to set are in range {0..LONG_MAX/HZ}.
 
 ==============================================================
 
+hung_task_check_interval_secs:
+
+Hung task check interval. If hung task checking is enabled
+(see hung_task_timeout_secs), the check is done every
+hung_task_check_interval_secs seconds.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0 (default): means use hung_task_timeout_secs as checking interval.
+Possible values to set are in range {0..LONG_MAX/HZ}.
+
+==============================================================
+
 hung_task_warnings:
 
 The maximum number of warnings to report. During a check interval
@@ -451,7 +464,8 @@ Notes:
 1) kernel doesn't guarantee, that new object will have desired id. So,
 it's up to userspace, how to handle an object with "wrong" id.
 2) Toggle with non-default value will be set back to -1 by kernel after
-successful IPC object allocation.
+successful IPC object allocation. If an IPC object allocation syscall
+fails, it is undefined if the value remains unmodified or is reset to -1.
 
 ==============================================================
 
index e72853b6d7257b30c93eceff5eee014cfa146ae6..7d73882e2c273c57d1277c701b71a1774b22763c 100644 (file)
@@ -691,7 +691,7 @@ and don't use much of it.
 The default value is 0.
 
 See Documentation/vm/overcommit-accounting.rst and
-mm/mmap.c::__vm_enough_memory() for more information.
+mm/util.c::__vm_enough_memory() for more information.
 
 ==============================================================
 
index c6148166a7b4b0df1873ab55f299f148d9a8d6a9..4426e9687d89832e405c448eef7e41cb7a26d9ce 100644 (file)
@@ -841,6 +841,16 @@ config REFCOUNT_FULL
          against various use-after-free conditions that can be used in
          security flaw exploits.
 
+config HAVE_ARCH_PREL32_RELOCATIONS
+       bool
+       help
+         May be selected by an architecture if it supports place-relative
+         32-bit relocations, both in the toolchain and in the module loader,
+         in which case relative references can be used in special sections
+         for PCI fixup, initcalls etc which are only half the size on 64 bit
+         architectures, and don't require runtime relocation on relocatable
+         kernels.
+
 source "kernel/gcov/Kconfig"
 
 source "scripts/gcc-plugins/Kconfig"
index d9c2991331111617cc3fce04f38fe17fd1a78f6d..82ab015bf42b7bf263cd13d61274e6f4e899d9db 100644 (file)
@@ -330,16 +330,15 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
  * atomic helpers. Insert it into the gate_vma so that it is visible
  * through ptrace and /proc/<pid>/mem.
  */
-static struct vm_area_struct gate_vma = {
-       .vm_start       = 0xffff0000,
-       .vm_end         = 0xffff0000 + PAGE_SIZE,
-       .vm_flags       = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC,
-};
+static struct vm_area_struct gate_vma;
 
 static int __init gate_vma_init(void)
 {
        vma_init(&gate_vma, NULL);
        gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
+       gate_vma.vm_start = 0xffff0000;
+       gate_vma.vm_end = 0xffff0000 + PAGE_SIZE;
+       gate_vma.vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC;
        return 0;
 }
 arch_initcall(gate_vma_init);
index d0a53cc6293a3d3c288ffc1f9809d90fe439cea2..29e75b47becd5a94c9e4cf7944e77a67cdca05d7 100644 (file)
@@ -108,6 +108,7 @@ config ARM64
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
+       select HAVE_ARCH_PREL32_RELOCATIONS
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_STACKLEAK
        select HAVE_ARCH_THREAD_STRUCT_WHITELIST
index a80669209155383343ba8adbb90b3e8427e2afdb..db0b6eebbfa5b55a6f7c4f55b1d489bcf158d974 100644 (file)
@@ -177,6 +177,7 @@ config PPC
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS   if COMPAT
+       select HAVE_ARCH_PREL32_RELOCATIONS
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_CBPF_JIT                    if !PPC64
index b0312f8947cee149cc1cea4d5b4bb851499a7b86..512003f168895c231150f943d18db545e82e9f61 100644 (file)
@@ -124,6 +124,7 @@ config X86
        select HAVE_ARCH_MMAP_RND_BITS          if MMU
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS   if MMU && COMPAT
        select HAVE_ARCH_COMPAT_MMAP_BASES      if MMU && COMPAT
+       select HAVE_ARCH_PREL32_RELOCATIONS
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_THREAD_STRUCT_WHITELIST
        select HAVE_ARCH_TRACEHOOK
index 302517929932bb52405d5396c57f084691090e5e..d1e19f358b6ec5fbc5c682e02d2b36149b0aa43a 100644 (file)
  * _ctype[] in lib/ctype.c is needed by isspace() of linux/ctype.h.
  * While both lib/ctype.c and lib/cmdline.c will bring EXPORT_SYMBOL
  * which is meaningless and will cause compiling error in some cases.
- * So do not include linux/export.h and define EXPORT_SYMBOL(sym)
- * as empty.
  */
-#define _LINUX_EXPORT_H
-#define EXPORT_SYMBOL(sym)
+#define __DISABLE_EXPORTS
 
 #include "misc.h"
 #include "error.h"
index de690c2d2e33aafc529e30d0b8066534c1789669..a0ab9ab61c754c6a413744bd54eb9599bfbf5dc1 100644 (file)
@@ -8,5 +8,6 @@ generated-y += xen-hypercalls.h
 
 generic-y += dma-contiguous.h
 generic-y += early_ioremap.h
+generic-y += export.h
 generic-y += mcs_spinlock.h
 generic-y += mm-arch-hooks.h
diff --git a/arch/x86/include/asm/export.h b/arch/x86/include/asm/export.h
deleted file mode 100644 (file)
index 2a51d66..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifdef CONFIG_64BIT
-#define KSYM_ALIGN 16
-#endif
-#include <asm-generic/export.h>
index f7dff0457846474c6b1af5822674ffb7a64d2c9b..4a74a7cf0a8bf835800c0cb23d72b17bcb931efa 100644 (file)
@@ -7305,8 +7305,9 @@ static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
        kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
 }
 
-void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
-               unsigned long start, unsigned long end)
+int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+               unsigned long start, unsigned long end,
+               bool blockable)
 {
        unsigned long apic_address;
 
@@ -7317,6 +7318,8 @@ void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
        apic_address = gfn_to_hva(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT);
        if (start <= apic_address && apic_address < end)
                kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD);
+
+       return 0;
 }
 
 void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
index c7acf74253a12e22fb9720b2c75966a68ea3eded..a1d6b5597c17bac113c062f7b3200e2926b9f0e5 100644 (file)
@@ -337,6 +337,7 @@ static ssize_t backing_dev_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t len)
 {
        char *file_name;
+       size_t sz;
        struct file *backing_dev = NULL;
        struct inode *inode;
        struct address_space *mapping;
@@ -357,7 +358,11 @@ static ssize_t backing_dev_store(struct device *dev,
                goto out;
        }
 
-       strlcpy(file_name, buf, len);
+       strlcpy(file_name, buf, PATH_MAX);
+       /* ignore trailing newline */
+       sz = strlen(file_name);
+       if (sz > 0 && file_name[sz - 1] == '\n')
+               file_name[sz - 1] = 0x00;
 
        backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0);
        if (IS_ERR(backing_dev)) {
index 88c322d7c71edf306591be82d717ac4426eb09e1..14c40a7750d1d4017edbc386d4e02df7949149fe 100644 (file)
@@ -24,6 +24,7 @@ KBUILD_CFLAGS                 := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
                                   -D__NO_FORTIFY \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector) \
+                                  -D__DISABLE_EXPORTS
 
 GCOV_PROFILE                   := n
 KASAN_SANITIZE                 := n
index a365ea2383d18c137df14d1fa116fad954d9ca45..e55508b394962d8d77e6fe285cee1a9544214714 100644 (file)
@@ -178,12 +178,18 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn)
  *
  * @amn: our notifier
  */
-static void amdgpu_mn_read_lock(struct amdgpu_mn *amn)
+static int amdgpu_mn_read_lock(struct amdgpu_mn *amn, bool blockable)
 {
-       mutex_lock(&amn->read_lock);
+       if (blockable)
+               mutex_lock(&amn->read_lock);
+       else if (!mutex_trylock(&amn->read_lock))
+               return -EAGAIN;
+
        if (atomic_inc_return(&amn->recursion) == 1)
                down_read_non_owner(&amn->lock);
        mutex_unlock(&amn->read_lock);
+
+       return 0;
 }
 
 /**
@@ -239,10 +245,11 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node,
  * Block for operations on BOs to finish and mark pages as accessed and
  * potentially dirty.
  */
-static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
+static int amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
                                                 struct mm_struct *mm,
                                                 unsigned long start,
-                                                unsigned long end)
+                                                unsigned long end,
+                                                bool blockable)
 {
        struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
        struct interval_tree_node *it;
@@ -250,17 +257,28 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
        /* notification is exclusive, but interval is inclusive */
        end -= 1;
 
-       amdgpu_mn_read_lock(amn);
+       /* TODO we should be able to split locking for interval tree and
+        * amdgpu_mn_invalidate_node
+        */
+       if (amdgpu_mn_read_lock(amn, blockable))
+               return -EAGAIN;
 
        it = interval_tree_iter_first(&amn->objects, start, end);
        while (it) {
                struct amdgpu_mn_node *node;
 
+               if (!blockable) {
+                       amdgpu_mn_read_unlock(amn);
+                       return -EAGAIN;
+               }
+
                node = container_of(it, struct amdgpu_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
                amdgpu_mn_invalidate_node(node, start, end);
        }
+
+       return 0;
 }
 
 /**
@@ -275,10 +293,11 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn,
  * necessitates evicting all user-mode queues of the process. The BOs
  * are restorted in amdgpu_mn_invalidate_range_end_hsa.
  */
-static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
+static int amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
                                                 struct mm_struct *mm,
                                                 unsigned long start,
-                                                unsigned long end)
+                                                unsigned long end,
+                                                bool blockable)
 {
        struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn);
        struct interval_tree_node *it;
@@ -286,13 +305,19 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
        /* notification is exclusive, but interval is inclusive */
        end -= 1;
 
-       amdgpu_mn_read_lock(amn);
+       if (amdgpu_mn_read_lock(amn, blockable))
+               return -EAGAIN;
 
        it = interval_tree_iter_first(&amn->objects, start, end);
        while (it) {
                struct amdgpu_mn_node *node;
                struct amdgpu_bo *bo;
 
+               if (!blockable) {
+                       amdgpu_mn_read_unlock(amn);
+                       return -EAGAIN;
+               }
+
                node = container_of(it, struct amdgpu_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
@@ -304,6 +329,8 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn,
                                amdgpu_amdkfd_evict_userptr(mem, mm);
                }
        }
+
+       return 0;
 }
 
 /**
index dcd6e230d16aa7905c1ae075fab469e333f7ef8b..2c9b284036d10217a013e146eba8704123006d65 100644 (file)
@@ -112,10 +112,11 @@ static void del_object(struct i915_mmu_object *mo)
        mo->attached = false;
 }
 
-static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
+static int i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
                                                       struct mm_struct *mm,
                                                       unsigned long start,
-                                                      unsigned long end)
+                                                      unsigned long end,
+                                                      bool blockable)
 {
        struct i915_mmu_notifier *mn =
                container_of(_mn, struct i915_mmu_notifier, mn);
@@ -124,7 +125,7 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
        LIST_HEAD(cancelled);
 
        if (RB_EMPTY_ROOT(&mn->objects.rb_root))
-               return;
+               return 0;
 
        /* interval ranges are inclusive, but invalidate range is exclusive */
        end--;
@@ -132,6 +133,10 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
        spin_lock(&mn->lock);
        it = interval_tree_iter_first(&mn->objects, start, end);
        while (it) {
+               if (!blockable) {
+                       spin_unlock(&mn->lock);
+                       return -EAGAIN;
+               }
                /* The mmu_object is released late when destroying the
                 * GEM object so it is entirely possible to gain a
                 * reference on an object in the process of being freed
@@ -154,6 +159,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
 
        if (!list_empty(&cancelled))
                flush_workqueue(mn->wq);
+
+       return 0;
 }
 
 static const struct mmu_notifier_ops i915_gem_userptr_notifier = {
index abd24975c9b1d946cec7c85ba7ebe3b820d1c8e4..f8b35df44c60eba57e7b2ec76c068190dd941c79 100644 (file)
@@ -118,19 +118,27 @@ static void radeon_mn_release(struct mmu_notifier *mn,
  * We block for all BOs between start and end to be idle and
  * unmap them by move them into system domain again.
  */
-static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
+static int radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                                             struct mm_struct *mm,
                                             unsigned long start,
-                                            unsigned long end)
+                                            unsigned long end,
+                                            bool blockable)
 {
        struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn);
        struct ttm_operation_ctx ctx = { false, false };
        struct interval_tree_node *it;
+       int ret = 0;
 
        /* notification is exclusive, but interval is inclusive */
        end -= 1;
 
-       mutex_lock(&rmn->lock);
+       /* TODO we should be able to split locking for interval tree and
+        * the tear down.
+        */
+       if (blockable)
+               mutex_lock(&rmn->lock);
+       else if (!mutex_trylock(&rmn->lock))
+               return -EAGAIN;
 
        it = interval_tree_iter_first(&rmn->objects, start, end);
        while (it) {
@@ -138,6 +146,11 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                struct radeon_bo *bo;
                long r;
 
+               if (!blockable) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
+
                node = container_of(it, struct radeon_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
@@ -166,7 +179,10 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
                }
        }
        
+out_unlock:
        mutex_unlock(&rmn->lock);
+
+       return ret;
 }
 
 static const struct mmu_notifier_ops radeon_mn_ops = {
index 182436b92ba93a95ca6e119108c30d50706b7212..6ec748eccff7e87d7691b92a6d50534d89d4625e 100644 (file)
@@ -186,6 +186,7 @@ static void ib_umem_notifier_release(struct mmu_notifier *mn,
        rbt_ib_umem_for_each_in_range(&context->umem_tree, 0,
                                      ULLONG_MAX,
                                      ib_umem_notifier_release_trampoline,
+                                     true,
                                      NULL);
        up_read(&context->umem_rwsem);
 }
@@ -207,22 +208,31 @@ static int invalidate_range_start_trampoline(struct ib_umem *item, u64 start,
        return 0;
 }
 
-static void ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
+static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
                                                    struct mm_struct *mm,
                                                    unsigned long start,
-                                                   unsigned long end)
+                                                   unsigned long end,
+                                                   bool blockable)
 {
        struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn);
+       int ret;
 
        if (!context->invalidate_range)
-               return;
+               return 0;
+
+       if (blockable)
+               down_read(&context->umem_rwsem);
+       else if (!down_read_trylock(&context->umem_rwsem))
+               return -EAGAIN;
 
        ib_ucontext_notifier_start_account(context);
-       down_read(&context->umem_rwsem);
-       rbt_ib_umem_for_each_in_range(&context->umem_tree, start,
+       ret = rbt_ib_umem_for_each_in_range(&context->umem_tree, start,
                                      end,
-                                     invalidate_range_start_trampoline, NULL);
+                                     invalidate_range_start_trampoline,
+                                     blockable, NULL);
        up_read(&context->umem_rwsem);
+
+       return ret;
 }
 
 static int invalidate_range_end_trampoline(struct ib_umem *item, u64 start,
@@ -242,10 +252,15 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn,
        if (!context->invalidate_range)
                return;
 
+       /*
+        * TODO: we currently bail out if there is any sleepable work to be done
+        * in ib_umem_notifier_invalidate_range_start so we shouldn't really block
+        * here. But this is ugly and fragile.
+        */
        down_read(&context->umem_rwsem);
        rbt_ib_umem_for_each_in_range(&context->umem_tree, start,
                                      end,
-                                     invalidate_range_end_trampoline, NULL);
+                                     invalidate_range_end_trampoline, true, NULL);
        up_read(&context->umem_rwsem);
        ib_ucontext_notifier_end_account(context);
 }
@@ -798,6 +813,7 @@ EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages);
 int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root,
                                  u64 start, u64 last,
                                  umem_call_back cb,
+                                 bool blockable,
                                  void *cookie)
 {
        int ret_val = 0;
@@ -809,6 +825,9 @@ int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root,
 
        for (node = rbt_ib_umem_iter_first(root, start, last - 1);
                        node; node = next) {
+               /* TODO move the blockable decision up to the callback */
+               if (!blockable)
+                       return -EAGAIN;
                next = rbt_ib_umem_iter_next(node, start, last - 1);
                umem = container_of(node, struct ib_umem_odp, interval_tree);
                ret_val = cb(umem->umem, start, last, cookie) || ret_val;
index 70aceefe14d5fa306a3ce78408b9866518030104..e1c7996c018efe688dbe081cc0928f05c5f0bbdd 100644 (file)
@@ -67,9 +67,9 @@ struct mmu_rb_handler {
 
 static unsigned long mmu_node_start(struct mmu_rb_node *);
 static unsigned long mmu_node_last(struct mmu_rb_node *);
-static void mmu_notifier_range_start(struct mmu_notifier *,
+static int mmu_notifier_range_start(struct mmu_notifier *,
                                     struct mm_struct *,
-                                    unsigned long, unsigned long);
+                                    unsigned long, unsigned long, bool);
 static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *,
                                           unsigned long, unsigned long);
 static void do_remove(struct mmu_rb_handler *handler,
@@ -284,10 +284,11 @@ void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler,
        handler->ops->remove(handler->ops_arg, node);
 }
 
-static void mmu_notifier_range_start(struct mmu_notifier *mn,
+static int mmu_notifier_range_start(struct mmu_notifier *mn,
                                     struct mm_struct *mm,
                                     unsigned long start,
-                                    unsigned long end)
+                                    unsigned long end,
+                                    bool blockable)
 {
        struct mmu_rb_handler *handler =
                container_of(mn, struct mmu_rb_handler, mn);
@@ -313,6 +314,8 @@ static void mmu_notifier_range_start(struct mmu_notifier *mn,
 
        if (added)
                queue_work(handler->wq, &handler->del_work);
+
+       return 0;
 }
 
 /*
index f1a87a690a4cd0555a1bb0ccbd585bb114a498b9..d216e0d2921dafc28b59e9a56dfbd82c660cc0d8 100644 (file)
@@ -488,7 +488,7 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr)
 
        down_read(&ctx->umem_rwsem);
        rbt_ib_umem_for_each_in_range(&ctx->umem_tree, 0, ULLONG_MAX,
-                                     mr_leaf_free, imr);
+                                     mr_leaf_free, true, imr);
        up_read(&ctx->umem_rwsem);
 
        wait_event(imr->q_leaf_free, !atomic_read(&imr->num_leaf_free));
index 17bf109c58e9e4206dd055e81a571bfb79236fd4..af247298409aadc6d7a91d3450f69e545999c73f 100644 (file)
@@ -1,6 +1,7 @@
 
 config BCACHE
        tristate "Block device as cache"
+       select CRC64
        ---help---
        Allows a block device to be used as cache for other devices; uses
        a btree for indexing and the layout is optimized for SSDs.
index b15256bcf0e7568e761a8afcae08659cb7a3a95e..c6a99dfa1ad9e80756a5b8ef2982f0cc31d7bf9f 100644 (file)
@@ -279,134 +279,3 @@ int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp_mask)
 
        return 0;
 }
-
-/*
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any
- * use permitted, subject to terms of PostgreSQL license; see.)
-
- * If we have a 64-bit integer type, then a 64-bit CRC looks just like the
- * usual sort of implementation. (See Ross Williams' excellent introduction
- * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from
- * ftp://ftp.rocksoft.com/papers/crc_v3.txt or several other net sites.)
- * If we have no working 64-bit type, then fake it with two 32-bit registers.
- *
- * The present implementation is a normal (not "reflected", in Williams'
- * terms) 64-bit CRC, using initial all-ones register contents and a final
- * bit inversion. The chosen polynomial is borrowed from the DLT1 spec
- * (ECMA-182, available from http://www.ecma.ch/ecma1/STAND/ECMA-182.HTM):
- *
- * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 +
- * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 +
- * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 +
- * x^7 + x^4 + x + 1
-*/
-
-static const uint64_t crc_table[256] = {
-       0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
-       0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
-       0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
-       0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
-       0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
-       0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
-       0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
-       0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
-       0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
-       0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
-       0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
-       0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
-       0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
-       0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
-       0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
-       0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
-       0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
-       0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
-       0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
-       0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
-       0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
-       0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
-       0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
-       0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
-       0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
-       0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
-       0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
-       0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
-       0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
-       0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
-       0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
-       0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
-       0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
-       0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
-       0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
-       0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
-       0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
-       0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
-       0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
-       0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
-       0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
-       0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
-       0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
-       0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
-       0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
-       0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
-       0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
-       0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
-       0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
-       0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
-       0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
-       0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
-       0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
-       0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
-       0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
-       0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
-       0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
-       0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
-       0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
-       0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
-       0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
-       0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
-       0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
-       0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
-       0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
-       0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
-       0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
-       0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
-       0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
-       0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
-       0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
-       0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
-       0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
-       0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
-       0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
-       0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
-       0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
-       0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
-       0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
-       0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
-       0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
-       0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
-       0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
-       0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
-       0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL,
-       0x9AFCE626CE85B507ULL,
-};
-
-uint64_t bch_crc64_update(uint64_t crc, const void *_data, size_t len)
-{
-       const unsigned char *data = _data;
-
-       while (len--) {
-               int i = ((int) (crc >> 56) ^ *data++) & 0xFF;
-               crc = crc_table[i] ^ (crc << 8);
-       }
-
-       return crc;
-}
-
-uint64_t bch_crc64(const void *data, size_t len)
-{
-       uint64_t crc = 0xffffffffffffffffULL;
-
-       crc = bch_crc64_update(crc, data, len);
-
-       return crc ^ 0xffffffffffffffffULL;
-}
index f7b0133c9d2f1aacd08dec33af2924df8594ebc9..5ff055f0a653fc384ec621351df906a7a851b9c2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/ratelimit.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/crc64.h>
 
 #include "closure.h"
 
@@ -542,6 +543,22 @@ dup:                                                                       \
 #define RB_PREV(ptr, member)                                           \
        container_of_or_null(rb_prev(&(ptr)->member), typeof(*ptr), member)
 
+static inline uint64_t bch_crc64(const void *p, size_t len)
+{
+       uint64_t crc = 0xffffffffffffffffULL;
+
+       crc = crc64_be(crc, p, len);
+       return crc ^ 0xffffffffffffffffULL;
+}
+
+static inline uint64_t bch_crc64_update(uint64_t crc,
+                                       const void *p,
+                                       size_t len)
+{
+       crc = crc64_be(crc, p, len);
+       return crc;
+}
+
 /* Does linear interpolation between powers of two */
 static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits)
 {
@@ -561,8 +578,4 @@ static inline sector_t bdev_sectors(struct block_device *bdev)
 {
        return bdev->bd_inode->i_size >> 9;
 }
-
-uint64_t bch_crc64_update(uint64_t, const void *, size_t);
-uint64_t bch_crc64(const void *, size_t);
-
 #endif /* _BCACHE_UTIL_H */
index 63d6246d6dff3caf8b6f7099257f902d50d2de20..6369aeaa70562e92325813857e2ba5c59aadcecb 100644 (file)
@@ -200,15 +200,18 @@ static void scif_mmu_notifier_release(struct mmu_notifier *mn,
        schedule_work(&scif_info.misc_work);
 }
 
-static void scif_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
+static int scif_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
                                                     struct mm_struct *mm,
                                                     unsigned long start,
-                                                    unsigned long end)
+                                                    unsigned long end,
+                                                    bool blockable)
 {
        struct scif_mmu_notif   *mmn;
 
        mmn = container_of(mn, struct scif_mmu_notif, ep_mmu_notifier);
        scif_rma_destroy_tcw(mmn, start, end - start);
+
+       return 0;
 }
 
 static void scif_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
index a3454eb56fbf57e3a3868c514cdd72affd578cc4..be28f05bfafa9ee41a53c642f0e384812ea88adf 100644 (file)
@@ -219,9 +219,10 @@ void gru_flush_all_tlb(struct gru_state *gru)
 /*
  * MMUOPS notifier callout functions
  */
-static void gru_invalidate_range_start(struct mmu_notifier *mn,
+static int gru_invalidate_range_start(struct mmu_notifier *mn,
                                       struct mm_struct *mm,
-                                      unsigned long start, unsigned long end)
+                                      unsigned long start, unsigned long end,
+                                      bool blockable)
 {
        struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
                                                 ms_notifier);
@@ -231,6 +232,8 @@ static void gru_invalidate_range_start(struct mmu_notifier *mn,
        gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms,
                start, end, atomic_read(&gms->ms_range_active));
        gru_flush_tlb_range(gms, start, end - start);
+
+       return 0;
 }
 
 static void gru_invalidate_range_end(struct mmu_notifier *mn,
index 46f58a9771d7399dbfa7c9ea5fd25819f325ed91..ef7143a274e00c9431a26c14702443dbd7853aa1 100644 (file)
@@ -66,9 +66,15 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                     f->vendor == (u16) PCI_ANY_ID) &&
                    (f->device == dev->device ||
                     f->device == (u16) PCI_ANY_ID)) {
-                       calltime = fixup_debug_start(dev, f->hook);
-                       f->hook(dev);
-                       fixup_debug_report(dev, calltime, f->hook);
+                       void (*hook)(struct pci_dev *dev);
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+                       hook = offset_to_ptr(&f->hook_offset);
+#else
+                       hook = f->hook;
+#endif
+                       calltime = fixup_debug_start(dev, hook);
+                       hook(dev);
+                       fixup_debug_report(dev, calltime, hook);
                }
 }
 
index a8cb8d2f2abbbff0ce6405b14d4fc73172d1391b..cbe467ff1aba9d8ca72588f51856f2239dd4d0d9 100644 (file)
@@ -1006,7 +1006,6 @@ out_free:
 static int rio_mport_wait_for_async_dma(struct file *filp, void __user *arg)
 {
        struct mport_cdev_priv *priv;
-       struct mport_dev *md;
        struct rio_async_tx_wait w_param;
        struct mport_dma_req *req;
        dma_cookie_t cookie;
@@ -1016,7 +1015,6 @@ static int rio_mport_wait_for_async_dma(struct file *filp, void __user *arg)
        int ret;
 
        priv = (struct mport_cdev_priv *)filp->private_data;
-       md = priv->md;
 
        if (unlikely(copy_from_user(&w_param, arg, sizeof(w_param))))
                return -EFAULT;
index c866a62f766d4ee4bfd5e5bc57e701ef8766159a..57390c7666e5dd8d44bfe9bdf1e503afb13de189 100644 (file)
@@ -479,18 +479,25 @@ static const struct vm_operations_struct gntdev_vmops = {
 
 /* ------------------------------------------------------------------ */
 
+static bool in_range(struct gntdev_grant_map *map,
+                             unsigned long start, unsigned long end)
+{
+       if (!map->vma)
+               return false;
+       if (map->vma->vm_start >= end)
+               return false;
+       if (map->vma->vm_end <= start)
+               return false;
+
+       return true;
+}
+
 static void unmap_if_in_range(struct gntdev_grant_map *map,
                              unsigned long start, unsigned long end)
 {
        unsigned long mstart, mend;
        int err;
 
-       if (!map->vma)
-               return;
-       if (map->vma->vm_start >= end)
-               return;
-       if (map->vma->vm_end <= start)
-               return;
        mstart = max(start, map->vma->vm_start);
        mend   = min(end,   map->vma->vm_end);
        pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
@@ -503,21 +510,40 @@ static void unmap_if_in_range(struct gntdev_grant_map *map,
        WARN_ON(err);
 }
 
-static void mn_invl_range_start(struct mmu_notifier *mn,
+static int mn_invl_range_start(struct mmu_notifier *mn,
                                struct mm_struct *mm,
-                               unsigned long start, unsigned long end)
+                               unsigned long start, unsigned long end,
+                               bool blockable)
 {
        struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
        struct gntdev_grant_map *map;
+       int ret = 0;
+
+       /* TODO do we really need a mutex here? */
+       if (blockable)
+               mutex_lock(&priv->lock);
+       else if (!mutex_trylock(&priv->lock))
+               return -EAGAIN;
 
-       mutex_lock(&priv->lock);
        list_for_each_entry(map, &priv->maps, next) {
+               if (in_range(map, start, end)) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
                unmap_if_in_range(map, start, end);
        }
        list_for_each_entry(map, &priv->freeable_maps, next) {
+               if (in_range(map, start, end)) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
                unmap_if_in_range(map, start, end);
        }
+
+out_unlock:
        mutex_unlock(&priv->lock);
+
+       return ret;
 }
 
 static void mn_release(struct mmu_notifier *mn,
index e91028d4340abf9b7ad32c5cf77f668bf32bfd4b..66621e96f9afe2a8a33bdb35d624353473aa7386 100644 (file)
@@ -167,7 +167,7 @@ adfs_mode2atts(struct super_block *sb, struct inode *inode)
  * of time to convert from RISC OS epoch to Unix epoch.
  */
 static void
-adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
+adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
 {
        unsigned int high, low;
        /* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
@@ -195,11 +195,11 @@ adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
        /* convert from RISC OS to Unix epoch */
        nsec -= nsec_unix_epoch_diff_risc_os_epoch;
 
-       *tv = ns_to_timespec(nsec);
+       *tv = ns_to_timespec64(nsec);
        return;
 
  cur_time:
-       *tv = timespec64_to_timespec(current_time(inode));
+       *tv = current_time(inode);
        return;
 
  too_early:
@@ -242,7 +242,6 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
 struct inode *
 adfs_iget(struct super_block *sb, struct object_info *obj)
 {
-       struct timespec ts;
        struct inode *inode;
 
        inode = new_inode(sb);
@@ -271,9 +270,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
        ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
        inode->i_mode    = adfs_atts2mode(sb, inode);
-       ts = timespec64_to_timespec(inode->i_mtime);
-       adfs_adfs2unix_time(&ts, inode);
-       inode->i_mtime = timespec_to_timespec64(ts);
+       adfs_adfs2unix_time(&inode->i_mtime, inode);
        inode->i_atime = inode->i_mtime;
        inode->i_ctime = inode->i_mtime;
 
index 50281228985049563292bc549d0fd7101f06abe1..9f9cadbfbd7a34f8005fafb0960b3c60e4848c60 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/completion.h>
 #include <linux/file.h>
+#include <linux/magic.h>
 
 /* This is the range of ioctl() numbers we claim as ours */
 #define AUTOFS_IOC_FIRST     AUTOFS_IOC_READY
@@ -125,7 +126,8 @@ struct autofs_sb_info {
 
 static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
 {
-       return (struct autofs_sb_info *)(sb->s_fs_info);
+       return sb->s_magic != AUTOFS_SUPER_MAGIC ?
+               NULL : (struct autofs_sb_info *)(sb->s_fs_info);
 }
 
 static inline struct autofs_info *autofs_dentry_ino(struct dentry *dentry)
@@ -152,15 +154,9 @@ int autofs_expire_run(struct super_block *, struct vfsmount *,
                      struct autofs_sb_info *,
                      struct autofs_packet_expire __user *);
 int autofs_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
-                          struct autofs_sb_info *sbi, int when);
+                          struct autofs_sb_info *sbi, unsigned int how);
 int autofs_expire_multi(struct super_block *, struct vfsmount *,
                        struct autofs_sb_info *, int __user *);
-struct dentry *autofs_expire_direct(struct super_block *sb,
-                                   struct vfsmount *mnt,
-                                   struct autofs_sb_info *sbi, int how);
-struct dentry *autofs_expire_indirect(struct super_block *sb,
-                                     struct vfsmount *mnt,
-                                     struct autofs_sb_info *sbi, int how);
 
 /* Device node initialization */
 
index b332d3f6e7306d7c3fe923c64f82126ca95ca4a3..d441244b79df98d23d6e0640466a2db68ffdac6b 100644 (file)
 
 #include "autofs_i.h"
 
-static unsigned long now;
-
 /* Check if a dentry can be expired */
 static inline int autofs_can_expire(struct dentry *dentry,
-                                   unsigned long timeout, int do_now)
+                                   unsigned long timeout, unsigned int how)
 {
        struct autofs_info *ino = autofs_dentry_ino(dentry);
 
@@ -22,16 +20,17 @@ static inline int autofs_can_expire(struct dentry *dentry,
        if (ino == NULL)
                return 0;
 
-       if (!do_now) {
+       if (!(how & AUTOFS_EXP_IMMEDIATE)) {
                /* Too young to die */
-               if (!timeout || time_after(ino->last_used + timeout, now))
+               if (!timeout || time_after(ino->last_used + timeout, jiffies))
                        return 0;
        }
        return 1;
 }
 
 /* Check a mount point for busyness */
-static int autofs_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
+static int autofs_mount_busy(struct vfsmount *mnt,
+                            struct dentry *dentry, unsigned int how)
 {
        struct dentry *top = dentry;
        struct path path = {.mnt = mnt, .dentry = dentry};
@@ -52,6 +51,12 @@ static int autofs_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
                        goto done;
        }
 
+       /* Not a submount, has a forced expire been requested */
+       if (how & AUTOFS_EXP_FORCED) {
+               status = 0;
+               goto done;
+       }
+
        /* Update the expiry counter if fs is busy */
        if (!may_umount_tree(path.mnt)) {
                struct autofs_info *ino;
@@ -187,10 +192,14 @@ again:
 static int autofs_direct_busy(struct vfsmount *mnt,
                              struct dentry *top,
                              unsigned long timeout,
-                             int do_now)
+                             unsigned int how)
 {
        pr_debug("top %p %pd\n", top, top);
 
+       /* Forced expire, user space handles busy mounts */
+       if (how & AUTOFS_EXP_FORCED)
+               return 0;
+
        /* If it's busy update the expiry counters */
        if (!may_umount_tree(mnt)) {
                struct autofs_info *ino;
@@ -202,7 +211,7 @@ static int autofs_direct_busy(struct vfsmount *mnt,
        }
 
        /* Timeout of a direct mount is determined by its top dentry */
-       if (!autofs_can_expire(top, timeout, do_now))
+       if (!autofs_can_expire(top, timeout, how))
                return 1;
 
        return 0;
@@ -215,7 +224,7 @@ static int autofs_direct_busy(struct vfsmount *mnt,
 static int autofs_tree_busy(struct vfsmount *mnt,
                            struct dentry *top,
                            unsigned long timeout,
-                           int do_now)
+                           unsigned int how)
 {
        struct autofs_info *top_ino = autofs_dentry_ino(top);
        struct dentry *p;
@@ -237,7 +246,7 @@ static int autofs_tree_busy(struct vfsmount *mnt,
                 * If the fs is busy update the expiry counter.
                 */
                if (d_mountpoint(p)) {
-                       if (autofs_mount_busy(mnt, p)) {
+                       if (autofs_mount_busy(mnt, p, how)) {
                                top_ino->last_used = jiffies;
                                dput(p);
                                return 1;
@@ -260,8 +269,12 @@ static int autofs_tree_busy(struct vfsmount *mnt,
                }
        }
 
+       /* Forced expire, user space handles busy mounts */
+       if (how & AUTOFS_EXP_FORCED)
+               return 0;
+
        /* Timeout of a tree mount is ultimately determined by its top dentry */
-       if (!autofs_can_expire(top, timeout, do_now))
+       if (!autofs_can_expire(top, timeout, how))
                return 1;
 
        return 0;
@@ -270,7 +283,7 @@ static int autofs_tree_busy(struct vfsmount *mnt,
 static struct dentry *autofs_check_leaves(struct vfsmount *mnt,
                                          struct dentry *parent,
                                          unsigned long timeout,
-                                         int do_now)
+                                         unsigned int how)
 {
        struct dentry *p;
 
@@ -282,11 +295,17 @@ static struct dentry *autofs_check_leaves(struct vfsmount *mnt,
 
                if (d_mountpoint(p)) {
                        /* Can we umount this guy */
-                       if (autofs_mount_busy(mnt, p))
+                       if (autofs_mount_busy(mnt, p, how))
                                continue;
 
+                       /* This isn't a submount so if a forced expire
+                        * has been requested, user space handles busy
+                        * mounts */
+                       if (how & AUTOFS_EXP_FORCED)
+                               return p;
+
                        /* Can we expire this guy */
-                       if (autofs_can_expire(p, timeout, do_now))
+                       if (autofs_can_expire(p, timeout, how))
                                return p;
                }
        }
@@ -294,23 +313,21 @@ static struct dentry *autofs_check_leaves(struct vfsmount *mnt,
 }
 
 /* Check if we can expire a direct mount (possibly a tree) */
-struct dentry *autofs_expire_direct(struct super_block *sb,
-                                   struct vfsmount *mnt,
-                                   struct autofs_sb_info *sbi,
-                                   int how)
+static struct dentry *autofs_expire_direct(struct super_block *sb,
+                                          struct vfsmount *mnt,
+                                          struct autofs_sb_info *sbi,
+                                          unsigned int how)
 {
-       unsigned long timeout;
        struct dentry *root = dget(sb->s_root);
-       int do_now = how & AUTOFS_EXP_IMMEDIATE;
        struct autofs_info *ino;
+       unsigned long timeout;
 
        if (!root)
                return NULL;
 
-       now = jiffies;
        timeout = sbi->exp_timeout;
 
-       if (!autofs_direct_busy(mnt, root, timeout, do_now)) {
+       if (!autofs_direct_busy(mnt, root, timeout, how)) {
                spin_lock(&sbi->fs_lock);
                ino = autofs_dentry_ino(root);
                /* No point expiring a pending mount */
@@ -321,7 +338,7 @@ struct dentry *autofs_expire_direct(struct super_block *sb,
                ino->flags |= AUTOFS_INF_WANT_EXPIRE;
                spin_unlock(&sbi->fs_lock);
                synchronize_rcu();
-               if (!autofs_direct_busy(mnt, root, timeout, do_now)) {
+               if (!autofs_direct_busy(mnt, root, timeout, how)) {
                        spin_lock(&sbi->fs_lock);
                        ino->flags |= AUTOFS_INF_EXPIRING;
                        init_completion(&ino->expire_complete);
@@ -346,10 +363,8 @@ out:
 static struct dentry *should_expire(struct dentry *dentry,
                                    struct vfsmount *mnt,
                                    unsigned long timeout,
-                                   int how)
+                                   unsigned int how)
 {
-       int do_now = how & AUTOFS_EXP_IMMEDIATE;
-       int exp_leaves = how & AUTOFS_EXP_LEAVES;
        struct autofs_info *ino = autofs_dentry_ino(dentry);
        unsigned int ino_count;
 
@@ -367,22 +382,33 @@ static struct dentry *should_expire(struct dentry *dentry,
                pr_debug("checking mountpoint %p %pd\n", dentry, dentry);
 
                /* Can we umount this guy */
-               if (autofs_mount_busy(mnt, dentry))
+               if (autofs_mount_busy(mnt, dentry, how))
                        return NULL;
 
+               /* This isn't a submount so if a forced expire
+                * has been requested, user space handles busy
+                * mounts */
+               if (how & AUTOFS_EXP_FORCED)
+                       return dentry;
+
                /* Can we expire this guy */
-               if (autofs_can_expire(dentry, timeout, do_now))
+               if (autofs_can_expire(dentry, timeout, how))
                        return dentry;
                return NULL;
        }
 
        if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
                pr_debug("checking symlink %p %pd\n", dentry, dentry);
+
+               /* Forced expire, user space handles busy mounts */
+               if (how & AUTOFS_EXP_FORCED)
+                       return dentry;
+
                /*
                 * A symlink can't be "busy" in the usual sense so
                 * just check last used for expire timeout.
                 */
-               if (autofs_can_expire(dentry, timeout, do_now))
+               if (autofs_can_expire(dentry, timeout, how))
                        return dentry;
                return NULL;
        }
@@ -391,27 +417,33 @@ static struct dentry *should_expire(struct dentry *dentry,
                return NULL;
 
        /* Case 2: tree mount, expire iff entire tree is not busy */
-       if (!exp_leaves) {
-               /* Path walk currently on this dentry? */
-               ino_count = atomic_read(&ino->count) + 1;
-               if (d_count(dentry) > ino_count)
-                       return NULL;
+       if (!(how & AUTOFS_EXP_LEAVES)) {
+               /* Not a forced expire? */
+               if (!(how & AUTOFS_EXP_FORCED)) {
+                       /* ref-walk currently on this dentry? */
+                       ino_count = atomic_read(&ino->count) + 1;
+                       if (d_count(dentry) > ino_count)
+                               return NULL;
+               }
 
-               if (!autofs_tree_busy(mnt, dentry, timeout, do_now))
+               if (!autofs_tree_busy(mnt, dentry, timeout, how))
                        return dentry;
        /*
         * Case 3: pseudo direct mount, expire individual leaves
         *         (autofs-4.1).
         */
        } else {
-               /* Path walk currently on this dentry? */
                struct dentry *expired;
 
-               ino_count = atomic_read(&ino->count) + 1;
-               if (d_count(dentry) > ino_count)
-                       return NULL;
+               /* Not a forced expire? */
+               if (!(how & AUTOFS_EXP_FORCED)) {
+                       /* ref-walk currently on this dentry? */
+                       ino_count = atomic_read(&ino->count) + 1;
+                       if (d_count(dentry) > ino_count)
+                               return NULL;
+               }
 
-               expired = autofs_check_leaves(mnt, dentry, timeout, do_now);
+               expired = autofs_check_leaves(mnt, dentry, timeout, how);
                if (expired) {
                        if (expired == dentry)
                                dput(dentry);
@@ -427,10 +459,10 @@ static struct dentry *should_expire(struct dentry *dentry,
  *  - it is unused by any user process
  *  - it has been unused for exp_timeout time
  */
-struct dentry *autofs_expire_indirect(struct super_block *sb,
-                                     struct vfsmount *mnt,
-                                     struct autofs_sb_info *sbi,
-                                     int how)
+static struct dentry *autofs_expire_indirect(struct super_block *sb,
+                                            struct vfsmount *mnt,
+                                            struct autofs_sb_info *sbi,
+                                            unsigned int how)
 {
        unsigned long timeout;
        struct dentry *root = sb->s_root;
@@ -442,13 +474,10 @@ struct dentry *autofs_expire_indirect(struct super_block *sb,
        if (!root)
                return NULL;
 
-       now = jiffies;
        timeout = sbi->exp_timeout;
 
        dentry = NULL;
        while ((dentry = get_next_positive_subdir(dentry, root))) {
-               int flags = how;
-
                spin_lock(&sbi->fs_lock);
                ino = autofs_dentry_ino(dentry);
                if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
@@ -457,7 +486,7 @@ struct dentry *autofs_expire_indirect(struct super_block *sb,
                }
                spin_unlock(&sbi->fs_lock);
 
-               expired = should_expire(dentry, mnt, timeout, flags);
+               expired = should_expire(dentry, mnt, timeout, how);
                if (!expired)
                        continue;
 
@@ -470,7 +499,7 @@ struct dentry *autofs_expire_indirect(struct super_block *sb,
                /* Make sure a reference is not taken on found if
                 * things have changed.
                 */
-               flags &= ~AUTOFS_EXP_LEAVES;
+               how &= ~AUTOFS_EXP_LEAVES;
                found = should_expire(expired, mnt, timeout, how);
                if (!found || found != expired)
                        /* Something has changed, continue */
@@ -575,7 +604,7 @@ int autofs_expire_run(struct super_block *sb,
        spin_lock(&sbi->fs_lock);
        ino = autofs_dentry_ino(dentry);
        /* avoid rapid-fire expire attempts if expiry fails */
-       ino->last_used = now;
+       ino->last_used = jiffies;
        ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
        complete_all(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
@@ -584,15 +613,15 @@ int autofs_expire_run(struct super_block *sb,
 }
 
 int autofs_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
-                          struct autofs_sb_info *sbi, int when)
+                          struct autofs_sb_info *sbi, unsigned int how)
 {
        struct dentry *dentry;
        int ret = -EAGAIN;
 
        if (autofs_type_trigger(sbi->type))
-               dentry = autofs_expire_direct(sb, mnt, sbi, when);
+               dentry = autofs_expire_direct(sb, mnt, sbi, how);
        else
-               dentry = autofs_expire_indirect(sb, mnt, sbi, when);
+               dentry = autofs_expire_indirect(sb, mnt, sbi, how);
 
        if (dentry) {
                struct autofs_info *ino = autofs_dentry_ino(dentry);
@@ -605,7 +634,7 @@ int autofs_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
 
                spin_lock(&sbi->fs_lock);
                /* avoid rapid-fire expire attempts if expiry fails */
-               ino->last_used = now;
+               ino->last_used = jiffies;
                ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
                complete_all(&ino->expire_complete);
                spin_unlock(&sbi->fs_lock);
@@ -622,10 +651,10 @@ int autofs_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
 int autofs_expire_multi(struct super_block *sb, struct vfsmount *mnt,
                        struct autofs_sb_info *sbi, int __user *arg)
 {
-       int do_now = 0;
+       unsigned int how = 0;
 
-       if (arg && get_user(do_now, arg))
+       if (arg && get_user(how, arg))
                return -EFAULT;
 
-       return autofs_do_expire_multi(sb, mnt, sbi, do_now);
+       return autofs_do_expire_multi(sb, mnt, sbi, how);
 }
index b51980fc274e6c6b26fef944974a076523ae33a3..846c052569dd4913e1aea268ad88a0521251002e 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/seq_file.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
-#include <linux/magic.h>
 
 #include "autofs_i.h"
 
index a3d4141505784cb759883a8015ab1fbdb5a5aaae..782e57b911abcf0cd1d7aae2095333554e1f1d74 100644 (file)
@@ -559,6 +559,13 @@ static int autofs_dir_symlink(struct inode *dir,
        if (!autofs_oz_mode(sbi))
                return -EACCES;
 
+       /* autofs_oz_mode() needs to allow path walks when the
+        * autofs mount is catatonic but the state of an autofs
+        * file system needs to be preserved over restarts.
+        */
+       if (sbi->catatonic)
+               return -EACCES;
+
        BUG_ON(!ino);
 
        autofs_clean_ino(ino);
@@ -612,9 +619,15 @@ static int autofs_dir_unlink(struct inode *dir, struct dentry *dentry)
        struct autofs_info *ino = autofs_dentry_ino(dentry);
        struct autofs_info *p_ino;
 
-       /* This allows root to remove symlinks */
-       if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
+       if (!autofs_oz_mode(sbi))
+               return -EACCES;
+
+       /* autofs_oz_mode() needs to allow path walks when the
+        * autofs mount is catatonic but the state of an autofs
+        * file system needs to be preserved over restarts.
+        */
+       if (sbi->catatonic)
+               return -EACCES;
 
        if (atomic_dec_and_test(&ino->count)) {
                p_ino = autofs_dentry_ino(dentry->d_parent);
@@ -697,6 +710,13 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry)
        if (!autofs_oz_mode(sbi))
                return -EACCES;
 
+       /* autofs_oz_mode() needs to allow path walks when the
+        * autofs mount is catatonic but the state of an autofs
+        * file system needs to be preserved over restarts.
+        */
+       if (sbi->catatonic)
+               return -EACCES;
+
        spin_lock(&sbi->lookup_lock);
        if (!simple_empty(dentry)) {
                spin_unlock(&sbi->lookup_lock);
@@ -735,6 +755,13 @@ static int autofs_dir_mkdir(struct inode *dir,
        if (!autofs_oz_mode(sbi))
                return -EACCES;
 
+       /* autofs_oz_mode() needs to allow path walks when the
+        * autofs mount is catatonic but the state of an autofs
+        * file system needs to be preserved over restarts.
+        */
+       if (sbi->catatonic)
+               return -EACCES;
+
        pr_debug("dentry %p, creating %pd\n", dentry, dentry);
 
        BUG_ON(!ino);
index 67db22fe99c5ce8bf0ba606c0a45f221cbf69b38..42bbe6824b4bffc1fb5388c993abf102fcd8ea2b 100644 (file)
  *
  * 1) epmutex (mutex)
  * 2) ep->mtx (mutex)
- * 3) ep->lock (spinlock)
+ * 3) ep->wq.lock (spinlock)
  *
  * The acquire order is the one listed above, from 1 to 3.
- * We need a spinlock (ep->lock) because we manipulate objects
+ * We need a spinlock (ep->wq.lock) because we manipulate objects
  * from inside the poll callback, that might be triggered from
  * a wake_up() that in turn might be called from IRQ context.
  * So we can't sleep inside the poll callback and hence we need
@@ -85,7 +85,7 @@
  * of epoll file descriptors, we use the current recursion depth as
  * the lockdep subkey.
  * It is possible to drop the "ep->mtx" and to use the global
- * mutex "epmutex" (together with "ep->lock") to have it working,
+ * mutex "epmutex" (together with "ep->wq.lock") to have it working,
  * but having "ep->mtx" will make the interface more scalable.
  * Events that require holding "epmutex" are very rare, while for
  * normal operations the epoll private "ep->mtx" will guarantee
@@ -182,11 +182,10 @@ struct epitem {
  * This structure is stored inside the "private_data" member of the file
  * structure and represents the main data structure for the eventpoll
  * interface.
+ *
+ * Access to it is protected by the lock inside wq.
  */
 struct eventpoll {
-       /* Protect the access to this structure */
-       spinlock_t lock;
-
        /*
         * This mutex is used to ensure that files are not removed
         * while epoll is using them. This is held during the event
@@ -210,7 +209,7 @@ struct eventpoll {
        /*
         * This is a single linked list that chains all the "struct epitem" that
         * happened while transferring ready events to userspace w/out
-        * holding ->lock.
+        * holding ->wq.lock.
         */
        struct epitem *ovflist;
 
@@ -337,9 +336,9 @@ static inline int ep_cmp_ffd(struct epoll_filefd *p1,
 }
 
 /* Tells us if the item is currently linked */
-static inline int ep_is_linked(struct list_head *p)
+static inline int ep_is_linked(struct epitem *epi)
 {
-       return !list_empty(p);
+       return !list_empty(&epi->rdllink);
 }
 
 static inline struct eppoll_entry *ep_pwq_from_wait(wait_queue_entry_t *p)
@@ -392,7 +391,6 @@ static bool ep_busy_loop_end(void *p, unsigned long start_time)
 
        return ep_events_available(ep) || busy_loop_timeout(start_time);
 }
-#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /*
  * Busy poll if globally on and supporting sockets found && no events,
@@ -402,20 +400,16 @@ static bool ep_busy_loop_end(void *p, unsigned long start_time)
  */
 static void ep_busy_loop(struct eventpoll *ep, int nonblock)
 {
-#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int napi_id = READ_ONCE(ep->napi_id);
 
        if ((napi_id >= MIN_NAPI_ID) && net_busy_loop_on())
                napi_busy_loop(napi_id, nonblock ? NULL : ep_busy_loop_end, ep);
-#endif
 }
 
 static inline void ep_reset_busy_poll_napi_id(struct eventpoll *ep)
 {
-#ifdef CONFIG_NET_RX_BUSY_POLL
        if (ep->napi_id)
                ep->napi_id = 0;
-#endif
 }
 
 /*
@@ -423,7 +417,6 @@ static inline void ep_reset_busy_poll_napi_id(struct eventpoll *ep)
  */
 static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
 {
-#ifdef CONFIG_NET_RX_BUSY_POLL
        struct eventpoll *ep;
        unsigned int napi_id;
        struct socket *sock;
@@ -453,9 +446,24 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
 
        /* record NAPI ID for use in next busy poll */
        ep->napi_id = napi_id;
-#endif
 }
 
+#else
+
+static inline void ep_busy_loop(struct eventpoll *ep, int nonblock)
+{
+}
+
+static inline void ep_reset_busy_poll_napi_id(struct eventpoll *ep)
+{
+}
+
+static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
+{
+}
+
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
 /**
  * ep_call_nested - Perform a bound (possibly) nested call, by checking
  *                  that the recursion limit is not exceeded, and that
@@ -668,10 +676,11 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
 {
        __poll_t res;
        int pwake = 0;
-       unsigned long flags;
        struct epitem *epi, *nepi;
        LIST_HEAD(txlist);
 
+       lockdep_assert_irqs_enabled();
+
        /*
         * We need to lock this because we could be hit by
         * eventpoll_release_file() and epoll_ctl().
@@ -688,17 +697,17 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
         * because we want the "sproc" callback to be able to do it
         * in a lockless way.
         */
-       spin_lock_irqsave(&ep->lock, flags);
+       spin_lock_irq(&ep->wq.lock);
        list_splice_init(&ep->rdllist, &txlist);
        ep->ovflist = NULL;
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        /*
         * Now call the callback function.
         */
        res = (*sproc)(ep, &txlist, priv);
 
-       spin_lock_irqsave(&ep->lock, flags);
+       spin_lock_irq(&ep->wq.lock);
        /*
         * During the time we spent inside the "sproc" callback, some
         * other events might have been queued by the poll callback.
@@ -712,7 +721,7 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
                 * queued into ->ovflist but the "txlist" might already
                 * contain them, and the list_splice() below takes care of them.
                 */
-               if (!ep_is_linked(&epi->rdllink)) {
+               if (!ep_is_linked(epi)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
                        ep_pm_stay_awake(epi);
                }
@@ -740,7 +749,7 @@ static __poll_t ep_scan_ready_list(struct eventpoll *ep,
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        if (!ep_locked)
                mutex_unlock(&ep->mtx);
@@ -764,16 +773,12 @@ static void epi_rcu_free(struct rcu_head *head)
  */
 static int ep_remove(struct eventpoll *ep, struct epitem *epi)
 {
-       unsigned long flags;
        struct file *file = epi->ffd.file;
 
+       lockdep_assert_irqs_enabled();
+
        /*
-        * Removes poll wait queue hooks. We _have_ to do this without holding
-        * the "ep->lock" otherwise a deadlock might occur. This because of the
-        * sequence of the lock acquisition. Here we do "ep->lock" then the wait
-        * queue head lock when unregistering the wait queue. The wakeup callback
-        * will run by holding the wait queue head lock and will call our callback
-        * that will try to get "ep->lock".
+        * Removes poll wait queue hooks.
         */
        ep_unregister_pollwait(ep, epi);
 
@@ -784,10 +789,10 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
 
        rb_erase_cached(&epi->rbn, &ep->rbr);
 
-       spin_lock_irqsave(&ep->lock, flags);
-       if (ep_is_linked(&epi->rdllink))
+       spin_lock_irq(&ep->wq.lock);
+       if (ep_is_linked(epi))
                list_del_init(&epi->rdllink);
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        wakeup_source_unregister(ep_wakeup_source(epi));
        /*
@@ -837,7 +842,7 @@ static void ep_free(struct eventpoll *ep)
         * Walks through the whole tree by freeing each "struct epitem". At this
         * point we are sure no poll callbacks will be lingering around, and also by
         * holding "epmutex" we can be sure that no file cleanup code will hit
-        * us during this operation. So we can avoid the lock on "ep->lock".
+        * us during this operation. So we can avoid the lock on "ep->wq.lock".
         * We do not need to lock ep->mtx, either, we only do it to prevent
         * a lockdep warning.
         */
@@ -1017,7 +1022,6 @@ static int ep_alloc(struct eventpoll **pep)
        if (unlikely(!ep))
                goto free_uid;
 
-       spin_lock_init(&ep->lock);
        mutex_init(&ep->mtx);
        init_waitqueue_head(&ep->wq);
        init_waitqueue_head(&ep->poll_wait);
@@ -1122,7 +1126,7 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v
        __poll_t pollflags = key_to_poll(key);
        int ewake = 0;
 
-       spin_lock_irqsave(&ep->lock, flags);
+       spin_lock_irqsave(&ep->wq.lock, flags);
 
        ep_set_busy_poll_napi_id(epi);
 
@@ -1167,7 +1171,7 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v
        }
 
        /* If this file is already in the ready list we exit soon */
-       if (!ep_is_linked(&epi->rdllink)) {
+       if (!ep_is_linked(epi)) {
                list_add_tail(&epi->rdllink, &ep->rdllist);
                ep_pm_stay_awake_rcu(epi);
        }
@@ -1199,7 +1203,7 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v
                pwake++;
 
 out_unlock:
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irqrestore(&ep->wq.lock, flags);
 
        /* We have to call this outside the lock */
        if (pwake)
@@ -1417,11 +1421,12 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
 {
        int error, pwake = 0;
        __poll_t revents;
-       unsigned long flags;
        long user_watches;
        struct epitem *epi;
        struct ep_pqueue epq;
 
+       lockdep_assert_irqs_enabled();
+
        user_watches = atomic_long_read(&ep->user->epoll_watches);
        if (unlikely(user_watches >= max_user_watches))
                return -ENOSPC;
@@ -1484,13 +1489,13 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
                goto error_remove_epi;
 
        /* We have to drop the new item inside our item list to keep track of it */
-       spin_lock_irqsave(&ep->lock, flags);
+       spin_lock_irq(&ep->wq.lock);
 
        /* record NAPI ID of new item if present */
        ep_set_busy_poll_napi_id(epi);
 
        /* If the file is already "ready" we drop it inside the ready list */
-       if (revents && !ep_is_linked(&epi->rdllink)) {
+       if (revents && !ep_is_linked(epi)) {
                list_add_tail(&epi->rdllink, &ep->rdllist);
                ep_pm_stay_awake(epi);
 
@@ -1501,7 +1506,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
                        pwake++;
        }
 
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        atomic_long_inc(&ep->user->epoll_watches);
 
@@ -1527,10 +1532,10 @@ error_unregister:
         * list, since that is used/cleaned only inside a section bound by "mtx".
         * And ep_insert() is called with "mtx" held.
         */
-       spin_lock_irqsave(&ep->lock, flags);
-       if (ep_is_linked(&epi->rdllink))
+       spin_lock_irq(&ep->wq.lock);
+       if (ep_is_linked(epi))
                list_del_init(&epi->rdllink);
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        wakeup_source_unregister(ep_wakeup_source(epi));
 
@@ -1550,6 +1555,8 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi,
        int pwake = 0;
        poll_table pt;
 
+       lockdep_assert_irqs_enabled();
+
        init_poll_funcptr(&pt, NULL);
 
        /*
@@ -1572,9 +1579,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi,
         * 1) Flush epi changes above to other CPUs.  This ensures
         *    we do not miss events from ep_poll_callback if an
         *    event occurs immediately after we call f_op->poll().
-        *    We need this because we did not take ep->lock while
+        *    We need this because we did not take ep->wq.lock while
         *    changing epi above (but ep_poll_callback does take
-        *    ep->lock).
+        *    ep->wq.lock).
         *
         * 2) We also need to ensure we do not miss _past_ events
         *    when calling f_op->poll().  This barrier also
@@ -1593,8 +1600,8 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi,
         * list, push it inside.
         */
        if (ep_item_poll(epi, &pt, 1)) {
-               spin_lock_irq(&ep->lock);
-               if (!ep_is_linked(&epi->rdllink)) {
+               spin_lock_irq(&ep->wq.lock);
+               if (!ep_is_linked(epi)) {
                        list_add_tail(&epi->rdllink, &ep->rdllist);
                        ep_pm_stay_awake(epi);
 
@@ -1604,7 +1611,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi,
                        if (waitqueue_active(&ep->poll_wait))
                                pwake++;
                }
-               spin_unlock_irq(&ep->lock);
+               spin_unlock_irq(&ep->wq.lock);
        }
 
        /* We have to call this outside the lock */
@@ -1739,11 +1746,12 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout)
 {
        int res = 0, eavail, timed_out = 0;
-       unsigned long flags;
        u64 slack = 0;
        wait_queue_entry_t wait;
        ktime_t expires, *to = NULL;
 
+       lockdep_assert_irqs_enabled();
+
        if (timeout > 0) {
                struct timespec64 end_time = ep_set_mstimeout(timeout);
 
@@ -1756,7 +1764,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                 * caller specified a non blocking operation.
                 */
                timed_out = 1;
-               spin_lock_irqsave(&ep->lock, flags);
+               spin_lock_irq(&ep->wq.lock);
                goto check_events;
        }
 
@@ -1765,7 +1773,7 @@ fetch_events:
        if (!ep_events_available(ep))
                ep_busy_loop(ep, timed_out);
 
-       spin_lock_irqsave(&ep->lock, flags);
+       spin_lock_irq(&ep->wq.lock);
 
        if (!ep_events_available(ep)) {
                /*
@@ -1807,11 +1815,11 @@ fetch_events:
                                break;
                        }
 
-                       spin_unlock_irqrestore(&ep->lock, flags);
+                       spin_unlock_irq(&ep->wq.lock);
                        if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
                                timed_out = 1;
 
-                       spin_lock_irqsave(&ep->lock, flags);
+                       spin_lock_irq(&ep->wq.lock);
                }
 
                __remove_wait_queue(&ep->wq, &wait);
@@ -1821,7 +1829,7 @@ check_events:
        /* Is it worth to try to dig for events ? */
        eavail = ep_events_available(ep);
 
-       spin_unlock_irqrestore(&ep->lock, flags);
+       spin_unlock_irq(&ep->wq.lock);
 
        /*
         * Try to transfer events to user space. In case we get 0 events and
index e9bed49df6b71047b6658063e377fb59ef4c339e..78d501c1fb658f153a9683a95c560a3483c70cd7 100644 (file)
@@ -225,7 +225,8 @@ static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus)
 int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
 {
        struct super_block *sb = inode->i_sb;
-       const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       const int limit = sb->s_maxbytes >> sbi->cluster_bits;
        struct fat_entry fatent;
        struct fat_cache_id cid;
        int nr;
@@ -234,6 +235,12 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
 
        *fclus = 0;
        *dclus = MSDOS_I(inode)->i_start;
+       if (!fat_valid_entry(sbi, *dclus)) {
+               fat_fs_error_ratelimit(sb,
+                       "%s: invalid start cluster (i_pos %lld, start %08x)",
+                       __func__, MSDOS_I(inode)->i_pos, *dclus);
+               return -EIO;
+       }
        if (cluster == 0)
                return 0;
 
@@ -250,9 +257,8 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
                        fat_fs_error_ratelimit(sb,
-                                       "%s: detected the cluster chain loop"
-                                       " (i_pos %lld)", __func__,
-                                       MSDOS_I(inode)->i_pos);
+                               "%s: detected the cluster chain loop (i_pos %lld)",
+                               __func__, MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                }
@@ -262,9 +268,8 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                        goto out;
                else if (nr == FAT_ENT_FREE) {
                        fat_fs_error_ratelimit(sb,
-                                      "%s: invalid cluster chain (i_pos %lld)",
-                                      __func__,
-                                      MSDOS_I(inode)->i_pos);
+                               "%s: invalid cluster chain (i_pos %lld)",
+                               __func__, MSDOS_I(inode)->i_pos);
                        nr = -EIO;
                        goto out;
                } else if (nr == FAT_ENT_EOF) {
index 8e100c3bf72c1a0e3913107b33f9b2859be66882..7f5f3699fc6c086cb169c0f0dd9782971408480f 100644 (file)
@@ -1130,7 +1130,7 @@ error:
        return err;
 }
 
-int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
+int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts)
 {
        struct super_block *sb = dir->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
index 8fc1093da47d38ebf354e2b96c23d6fb5f086822..9d7d2d5da28bf9e6cfb614a267274612e8579247 100644 (file)
@@ -304,7 +304,7 @@ extern int fat_scan_logstart(struct inode *dir, int i_logstart,
                             struct fat_slot_info *sinfo);
 extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
                                struct msdos_dir_entry **de);
-extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
+extern int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts);
 extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
                           struct fat_slot_info *sinfo);
 extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
@@ -348,6 +348,11 @@ static inline void fatent_brelse(struct fat_entry *fatent)
        fatent->fat_inode = NULL;
 }
 
+static inline bool fat_valid_entry(struct msdos_sb_info *sbi, int entry)
+{
+       return FAT_START_ENT <= entry && entry < sbi->max_cluster;
+}
+
 extern void fat_ent_access_init(struct super_block *sb);
 extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent,
                        int entry);
@@ -357,6 +362,7 @@ extern int fat_alloc_clusters(struct inode *inode, int *cluster,
                              int nr_cluster);
 extern int fat_free_clusters(struct inode *inode, int cluster);
 extern int fat_count_free_clusters(struct super_block *sb);
+extern int fat_trim_fs(struct inode *inode, struct fstrim_range *range);
 
 /* fat/file.c */
 extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
@@ -406,9 +412,9 @@ void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...);
         } while (0)
 extern int fat_clusters_flush(struct super_block *sb);
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
-extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
+extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts,
                              __le16 __time, __le16 __date, u8 time_cs);
-extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
+extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
                              __le16 *time, __le16 *date, u8 *time_cs);
 extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 
index bac10de678cc9645af9eccd2584d0ffc548b9c93..defc2168de915c23406fe869af1ca65834818402 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/blkdev.h>
+#include <linux/sched/signal.h>
 #include "fat.h"
 
 struct fatent_operations {
@@ -23,7 +24,7 @@ static void fat12_ent_blocknr(struct super_block *sb, int entry,
 {
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        int bytes = entry + (entry >> 1);
-       WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+       WARN_ON(!fat_valid_entry(sbi, entry));
        *offset = bytes & (sb->s_blocksize - 1);
        *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -33,7 +34,7 @@ static void fat_ent_blocknr(struct super_block *sb, int entry,
 {
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        int bytes = (entry << sbi->fatent_shift);
-       WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry);
+       WARN_ON(!fat_valid_entry(sbi, entry));
        *offset = bytes & (sb->s_blocksize - 1);
        *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits);
 }
@@ -353,7 +354,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
        int err, offset;
        sector_t blocknr;
 
-       if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
+       if (!fat_valid_entry(sbi, entry)) {
                fatent_brelse(fatent);
                fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
                return -EIO;
@@ -690,3 +691,104 @@ out:
        unlock_fat(sbi);
        return err;
 }
+
+static int fat_trim_clusters(struct super_block *sb, u32 clus, u32 nr_clus)
+{
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       return sb_issue_discard(sb, fat_clus_to_blknr(sbi, clus),
+                               nr_clus * sbi->sec_per_clus, GFP_NOFS, 0);
+}
+
+int fat_trim_fs(struct inode *inode, struct fstrim_range *range)
+{
+       struct super_block *sb = inode->i_sb;
+       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       const struct fatent_operations *ops = sbi->fatent_ops;
+       struct fat_entry fatent;
+       u64 ent_start, ent_end, minlen, trimmed = 0;
+       u32 free = 0;
+       unsigned long reada_blocks, reada_mask, cur_block = 0;
+       int err = 0;
+
+       /*
+        * FAT data is organized as clusters, trim at the granulary of cluster.
+        *
+        * fstrim_range is in byte, convert vaules to cluster index.
+        * Treat sectors before data region as all used, not to trim them.
+        */
+       ent_start = max_t(u64, range->start>>sbi->cluster_bits, FAT_START_ENT);
+       ent_end = ent_start + (range->len >> sbi->cluster_bits) - 1;
+       minlen = range->minlen >> sbi->cluster_bits;
+
+       if (ent_start >= sbi->max_cluster || range->len < sbi->cluster_size)
+               return -EINVAL;
+       if (ent_end >= sbi->max_cluster)
+               ent_end = sbi->max_cluster - 1;
+
+       reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
+       reada_mask = reada_blocks - 1;
+
+       fatent_init(&fatent);
+       lock_fat(sbi);
+       fatent_set_entry(&fatent, ent_start);
+       while (fatent.entry <= ent_end) {
+               /* readahead of fat blocks */
+               if ((cur_block & reada_mask) == 0) {
+                       unsigned long rest = sbi->fat_length - cur_block;
+                       fat_ent_reada(sb, &fatent, min(reada_blocks, rest));
+               }
+               cur_block++;
+
+               err = fat_ent_read_block(sb, &fatent);
+               if (err)
+                       goto error;
+               do {
+                       if (ops->ent_get(&fatent) == FAT_ENT_FREE) {
+                               free++;
+                       } else if (free) {
+                               if (free >= minlen) {
+                                       u32 clus = fatent.entry - free;
+
+                                       err = fat_trim_clusters(sb, clus, free);
+                                       if (err && err != -EOPNOTSUPP)
+                                               goto error;
+                                       if (!err)
+                                               trimmed += free;
+                                       err = 0;
+                               }
+                               free = 0;
+                       }
+               } while (fat_ent_next(sbi, &fatent) && fatent.entry <= ent_end);
+
+               if (fatal_signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       goto error;
+               }
+
+               if (need_resched()) {
+                       fatent_brelse(&fatent);
+                       unlock_fat(sbi);
+                       cond_resched();
+                       lock_fat(sbi);
+               }
+       }
+       /* handle scenario when tail entries are all free */
+       if (free && free >= minlen) {
+               u32 clus = fatent.entry - free;
+
+               err = fat_trim_clusters(sb, clus, free);
+               if (err && err != -EOPNOTSUPP)
+                       goto error;
+               if (!err)
+                       trimmed += free;
+               err = 0;
+       }
+
+error:
+       fatent_brelse(&fatent);
+       unlock_fat(sbi);
+
+       range->len = trimmed << sbi->cluster_bits;
+
+       return err;
+}
index 4724cc9ad65021c8fe80a3cc66783e8d01801907..4f3d72fb1e60d64a71f92e632da19ac4ac132ebc 100644 (file)
@@ -121,6 +121,37 @@ static int fat_ioctl_get_volume_id(struct inode *inode, u32 __user *user_attr)
        return put_user(sbi->vol_id, user_attr);
 }
 
+static int fat_ioctl_fitrim(struct inode *inode, unsigned long arg)
+{
+       struct super_block *sb = inode->i_sb;
+       struct fstrim_range __user *user_range;
+       struct fstrim_range range;
+       struct request_queue *q = bdev_get_queue(sb->s_bdev);
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!blk_queue_discard(q))
+               return -EOPNOTSUPP;
+
+       user_range = (struct fstrim_range __user *)arg;
+       if (copy_from_user(&range, user_range, sizeof(range)))
+               return -EFAULT;
+
+       range.minlen = max_t(unsigned int, range.minlen,
+                            q->limits.discard_granularity);
+
+       err = fat_trim_fs(inode, &range);
+       if (err < 0)
+               return err;
+
+       if (copy_to_user(user_range, &range, sizeof(range)))
+               return -EFAULT;
+
+       return 0;
+}
+
 long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
@@ -133,6 +164,8 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return fat_ioctl_set_attributes(filp, user_attr);
        case FAT_IOCTL_GET_VOLUME_ID:
                return fat_ioctl_get_volume_id(inode, user_attr);
+       case FITRIM:
+               return fat_ioctl_fitrim(inode, arg);
        default:
                return -ENOTTY; /* Inappropriate ioctl for device */
        }
index bfd589ea74c01ebf74e4866d920759143b01be16..d6b81e31f9f5d827be92ffad4cf240fa32e5f767 100644 (file)
@@ -508,7 +508,6 @@ static int fat_validate_dir(struct inode *dir)
 /* doesn't deal with root inode */
 int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
-       struct timespec ts;
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
        int error;
 
@@ -559,14 +558,11 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
                           & ~((loff_t)sbi->cluster_size - 1)) >> 9;
 
-       fat_time_fat2unix(sbi, &ts, de->time, de->date, 0);
-       inode->i_mtime = timespec_to_timespec64(ts);
+       fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
        if (sbi->options.isvfat) {
-               fat_time_fat2unix(sbi, &ts, de->ctime,
+               fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
                                  de->cdate, de->ctime_cs);
-               inode->i_ctime = timespec_to_timespec64(ts);
-               fat_time_fat2unix(sbi, &ts, 0, de->adate, 0);
-               inode->i_atime = timespec_to_timespec64(ts);
+               fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
        } else
                inode->i_ctime = inode->i_atime = inode->i_mtime;
 
@@ -843,7 +839,6 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int __fat_write_inode(struct inode *inode, int wait)
 {
-       struct timespec ts;
        struct super_block *sb = inode->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh;
@@ -881,16 +876,13 @@ retry:
                raw_entry->size = cpu_to_le32(inode->i_size);
        raw_entry->attr = fat_make_attrs(inode);
        fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart);
-       ts = timespec64_to_timespec(inode->i_mtime);
-       fat_time_unix2fat(sbi, &ts, &raw_entry->time,
+       fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
                          &raw_entry->date, NULL);
        if (sbi->options.isvfat) {
                __le16 atime;
-               ts = timespec64_to_timespec(inode->i_ctime);
-               fat_time_unix2fat(sbi, &ts, &raw_entry->ctime,
+               fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
                                  &raw_entry->cdate, &raw_entry->ctime_cs);
-               ts = timespec64_to_timespec(inode->i_atime);
-               fat_time_unix2fat(sbi, &ts, &atime,
+               fat_time_unix2fat(sbi, &inode->i_atime, &atime,
                                  &raw_entry->adate, NULL);
        }
        spin_unlock(&sbi->inode_hash_lock);
index f9bdc1e01c98e7969d0e49d21bb468bef2eaaddb..573836dcaefc4c1d2720ee213e5b90098a4acb87 100644 (file)
@@ -180,17 +180,18 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
 #define IS_LEAP_YEAR(y)        (!((y) & 3) && (y) != YEAR_2100)
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
-static time_t days_in_year[] = {
+static long days_in_year[] = {
        /* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
        0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
 };
 
 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
-void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
+void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec64 *ts,
                       __le16 __time, __le16 __date, u8 time_cs)
 {
        u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date);
-       time_t second, day, leap_day, month, year;
+       time64_t second;
+       long day, leap_day, month, year;
 
        year  = date >> 9;
        month = max(1, (date >> 5) & 0xf);
@@ -205,7 +206,7 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
        second =  (time & 0x1f) << 1;
        second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
        second += (time >> 11) * SECS_PER_HOUR;
-       second += (year * 365 + leap_day
+       second += (time64_t)(year * 365 + leap_day
                   + days_in_year[month] + day
                   + DAYS_DELTA) * SECS_PER_DAY;
 
@@ -224,11 +225,11 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
 }
 
 /* Convert linear UNIX date to a FAT time/date pair. */
-void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
+void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec64 *ts,
                       __le16 *time, __le16 *date, u8 *time_cs)
 {
        struct tm tm;
-       time_to_tm(ts->tv_sec,
+       time64_to_tm(ts->tv_sec,
                   (sbi->options.tz_set ? sbi->options.time_offset :
                   -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm);
 
index 16a832c37d663b518432387e5826c1b957fee3d9..efb8c40c9d27467d0d58d10dd5b1ba313c06d9d6 100644 (file)
@@ -225,7 +225,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
 /***** Creates a directory entry (name is already formatted). */
 static int msdos_add_entry(struct inode *dir, const unsigned char *name,
                           int is_dir, int is_hid, int cluster,
-                          struct timespec *ts, struct fat_slot_info *sinfo)
+                          struct timespec64 *ts, struct fat_slot_info *sinfo)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
        struct msdos_dir_entry de;
@@ -250,7 +250,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
        if (err)
                return err;
 
-       dir->i_ctime = dir->i_mtime = timespec_to_timespec64(*ts);
+       dir->i_ctime = dir->i_mtime = *ts;
        if (IS_DIRSYNC(dir))
                (void)fat_sync_inode(dir);
        else
@@ -267,7 +267,6 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct inode *inode = NULL;
        struct fat_slot_info sinfo;
        struct timespec64 ts;
-       struct timespec t;
        unsigned char msdos_name[MSDOS_NAME];
        int err, is_hid;
 
@@ -286,8 +285,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        }
 
        ts = current_time(dir);
-       t = timespec64_to_timespec(ts);
-       err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &t, &sinfo);
+       err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
        if (err)
                goto out;
        inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
@@ -347,7 +345,6 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct inode *inode;
        unsigned char msdos_name[MSDOS_NAME];
        struct timespec64 ts;
-       struct timespec t;
        int err, is_hid, cluster;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
@@ -365,13 +362,12 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        }
 
        ts = current_time(dir);
-       t = timespec64_to_timespec(ts);
-       cluster = fat_alloc_new_dir(dir, &t);
+       cluster = fat_alloc_new_dir(dir, &ts);
        if (cluster < 0) {
                err = cluster;
                goto out;
        }
-       err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &t, &sinfo);
+       err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
        if (err)
                goto out_free;
        inc_nlink(dir);
@@ -503,9 +499,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
                new_i_pos = MSDOS_I(new_inode)->i_pos;
                fat_detach(new_inode);
        } else {
-               struct timespec t = timespec64_to_timespec(ts);
                err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
-                                     &t, &sinfo);
+                                     &ts, &sinfo);
                if (err)
                        goto out;
                new_i_pos = sinfo.i_pos;
index 9a5469120caaf4dc6adafc7560da2fb13ffd009b..82cd1e69cbdf283322e8d7fa8566a22cca54fc0a 100644 (file)
@@ -577,7 +577,7 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
 
 static int vfat_build_slots(struct inode *dir, const unsigned char *name,
                            int len, int is_dir, int cluster,
-                           struct timespec *ts,
+                           struct timespec64 *ts,
                            struct msdos_dir_slot *slots, int *nr_slots)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
@@ -653,7 +653,7 @@ out_free:
 }
 
 static int vfat_add_entry(struct inode *dir, const struct qstr *qname,
-                         int is_dir, int cluster, struct timespec *ts,
+                         int is_dir, int cluster, struct timespec64 *ts,
                          struct fat_slot_info *sinfo)
 {
        struct msdos_dir_slot *slots;
@@ -678,7 +678,7 @@ static int vfat_add_entry(struct inode *dir, const struct qstr *qname,
                goto cleanup;
 
        /* update timestamp */
-       dir->i_ctime = dir->i_mtime = dir->i_atime = timespec_to_timespec64(*ts);
+       dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
        if (IS_DIRSYNC(dir))
                (void)fat_sync_inode(dir);
        else
@@ -762,14 +762,12 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct inode *inode;
        struct fat_slot_info sinfo;
        struct timespec64 ts;
-       struct timespec t;
        int err;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
 
        ts = current_time(dir);
-       t = timespec64_to_timespec(ts);
-       err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &t, &sinfo);
+       err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
        if (err)
                goto out;
        inode_inc_iversion(dir);
@@ -853,19 +851,17 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct inode *inode;
        struct fat_slot_info sinfo;
        struct timespec64 ts;
-       struct timespec t;
        int err, cluster;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
 
        ts = current_time(dir);
-       t = timespec64_to_timespec(ts);
-       cluster = fat_alloc_new_dir(dir, &t);
+       cluster = fat_alloc_new_dir(dir, &ts);
        if (cluster < 0) {
                err = cluster;
                goto out;
        }
-       err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &t, &sinfo);
+       err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
        if (err)
                goto out_free;
        inode_inc_iversion(dir);
@@ -904,7 +900,6 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct inode *old_inode, *new_inode;
        struct fat_slot_info old_sinfo, sinfo;
        struct timespec64 ts;
-       struct timespec t;
        loff_t new_i_pos;
        int err, is_dir, update_dotdot, corrupt = 0;
        struct super_block *sb = old_dir->i_sb;
@@ -939,9 +934,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_i_pos = MSDOS_I(new_inode)->i_pos;
                fat_detach(new_inode);
        } else {
-               t = timespec64_to_timespec(ts);
                err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
-                                    &t, &sinfo);
+                                    &ts, &sinfo);
                if (err)
                        goto out;
                new_i_pos = sinfo.i_pos;
index 7cc8b4acf66ae4fa89087dbd0b9552c3abe4b6e8..a63371815aaba6a0dfda4399b3b5cf8f789b15c2 100644 (file)
@@ -11,18 +11,3 @@ config HFSPLUS_FS
          MacOS 8. It includes all Mac specific filesystem data such as
          data forks and creator codes, but it also has several UNIX
          style features such as file ownership and permissions.
-
-config HFSPLUS_FS_POSIX_ACL
-       bool "HFS+ POSIX Access Control Lists"
-       depends on HFSPLUS_FS
-       select FS_POSIX_ACL
-       help
-         POSIX Access Control Lists (ACLs) support permissions for users and
-         groups beyond the owner/group/world scheme.
-
-         It needs to understand that POSIX ACLs are treated only under
-         Linux. POSIX ACLs doesn't mean something under Mac OS X.
-         Mac OS X beginning with version 10.4 ("Tiger") support NFSv4 ACLs,
-         which are part of the NFSv4 standard.
-
-         If you don't know what Access Control Lists are, say N
index f6a56542f8d7d6a4057a22bb624be768ce477c1e..9ed20e64b983937085d0a471574c91d630b107e7 100644 (file)
@@ -8,5 +8,3 @@ obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o
 hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \
                bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \
                attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o
-
-hfsplus-$(CONFIG_HFSPLUS_FS_POSIX_ACL) += posix_acl.o
diff --git a/fs/hfsplus/acl.h b/fs/hfsplus/acl.h
deleted file mode 100644 (file)
index 488c2b7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/fs/hfsplus/acl.h
- *
- * Vyacheslav Dubeyko <slava@dubeyko.com>
- *
- * Handler for Posix Access Control Lists (ACLs) support.
- */
-
-#include <linux/posix_acl_xattr.h>
-
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-
-/* posix_acl.c */
-struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type);
-int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
-               int type);
-extern int hfsplus_init_posix_acl(struct inode *, struct inode *);
-
-#else  /* CONFIG_HFSPLUS_FS_POSIX_ACL */
-#define hfsplus_get_posix_acl NULL
-#define hfsplus_set_posix_acl NULL
-
-static inline int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
-{
-       return 0;
-}
-#endif  /* CONFIG_HFSPLUS_FS_POSIX_ACL */
index b5254378f0113ca28d98c793a61528f62ea6f122..c5a70f83dbe7e1d63a8e5211b22bf17710f0df61 100644 (file)
@@ -18,7 +18,6 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 #include "xattr.h"
-#include "acl.h"
 
 static inline void hfsplus_instantiate(struct dentry *dentry,
                                       struct inode *inode, u32 cnid)
@@ -455,7 +454,7 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
        if (res)
                goto out_err;
 
-       res = hfsplus_init_inode_security(inode, dir, &dentry->d_name);
+       res = hfsplus_init_security(inode, dir, &dentry->d_name);
        if (res == -EOPNOTSUPP)
                res = 0; /* Operation is not supported. */
        else if (res) {
@@ -496,7 +495,7 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
        if (res)
                goto failed_mknod;
 
-       res = hfsplus_init_inode_security(inode, dir, &dentry->d_name);
+       res = hfsplus_init_security(inode, dir, &dentry->d_name);
        if (res == -EOPNOTSUPP)
                res = 0; /* Operation is not supported. */
        else if (res) {
@@ -567,10 +566,6 @@ const struct inode_operations hfsplus_dir_inode_operations = {
        .mknod                  = hfsplus_mknod,
        .rename                 = hfsplus_rename,
        .listxattr              = hfsplus_listxattr,
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-       .get_acl                = hfsplus_get_posix_acl,
-       .set_acl                = hfsplus_set_posix_acl,
-#endif
 };
 
 const struct file_operations hfsplus_dir_operations = {
index e8770935ce6d8588fc636661485c2fe23a3bafad..8e0f59767694b61ecfc0b57cd25d1a23ea1b94d5 100644 (file)
@@ -336,6 +336,9 @@ static int hfsplus_free_extents(struct super_block *sb,
        int i;
        int err = 0;
 
+       /* Mapping the allocation file may lock the extent tree */
+       WARN_ON(mutex_is_locked(&HFSPLUS_SB(sb)->ext_tree->tree_lock));
+
        hfsplus_dump_extent(extent);
        for (i = 0; i < 8; extent++, i++) {
                count = be32_to_cpu(extent->block_count);
@@ -415,11 +418,13 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid,
                if (res)
                        break;
                start = be32_to_cpu(fd.key->ext.start_block);
-               hfsplus_free_extents(sb, ext_entry,
-                                    total_blocks - start,
-                                    total_blocks);
                hfs_brec_remove(&fd);
+
+               mutex_unlock(&fd.tree->tree_lock);
+               hfsplus_free_extents(sb, ext_entry, total_blocks - start,
+                                    total_blocks);
                total_blocks = start;
+               mutex_lock(&fd.tree->tree_lock);
        } while (total_blocks > blocks);
        hfs_find_exit(&fd);
 
@@ -576,15 +581,20 @@ void hfsplus_file_truncate(struct inode *inode)
        }
        while (1) {
                if (alloc_cnt == hip->first_blocks) {
+                       mutex_unlock(&fd.tree->tree_lock);
                        hfsplus_free_extents(sb, hip->first_extents,
                                             alloc_cnt, alloc_cnt - blk_cnt);
                        hfsplus_dump_extent(hip->first_extents);
                        hip->first_blocks = blk_cnt;
+                       mutex_lock(&fd.tree->tree_lock);
                        break;
                }
                res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt);
                if (res)
                        break;
+               hfs_brec_remove(&fd);
+
+               mutex_unlock(&fd.tree->tree_lock);
                start = hip->cached_start;
                hfsplus_free_extents(sb, hip->cached_extents,
                                     alloc_cnt - start, alloc_cnt - blk_cnt);
@@ -596,7 +606,7 @@ void hfsplus_file_truncate(struct inode *inode)
                alloc_cnt = start;
                hip->cached_start = hip->cached_blocks = 0;
                hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
-               hfs_brec_remove(&fd);
+               mutex_lock(&fd.tree->tree_lock);
        }
        hfs_find_exit(&fd);
 
index d9255abafb81ff594d69490531fe865874ca034e..8e039435958a82700dd22aea4cf7b99fa80b6448 100644 (file)
@@ -31,7 +31,6 @@
 #define DBG_EXTENT     0x00000020
 #define DBG_BITMAP     0x00000040
 #define DBG_ATTR_MOD   0x00000080
-#define DBG_ACL_MOD    0x00000100
 
 #if 0
 #define DBG_MASK       (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
index c824f702feec438eb1cbd59aa721ba19ea280a25..8e9427a42b8195e95c77fab60eae4e84e8b51674 100644 (file)
@@ -21,7 +21,6 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 #include "xattr.h"
-#include "acl.h"
 
 static int hfsplus_readpage(struct file *file, struct page *page)
 {
@@ -267,12 +266,6 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
 
-       if (attr->ia_valid & ATTR_MODE) {
-               error = posix_acl_chmod(inode, inode->i_mode);
-               if (unlikely(error))
-                       return error;
-       }
-
        return 0;
 }
 
@@ -336,10 +329,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
 static const struct inode_operations hfsplus_file_inode_operations = {
        .setattr        = hfsplus_setattr,
        .listxattr      = hfsplus_listxattr,
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-       .get_acl        = hfsplus_get_posix_acl,
-       .set_acl        = hfsplus_set_posix_acl,
-#endif
 };
 
 static const struct file_operations hfsplus_file_operations = {
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
deleted file mode 100644 (file)
index 066114d..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/fs/hfsplus/posix_acl.c
- *
- * Vyacheslav Dubeyko <slava@dubeyko.com>
- *
- * Handler for Posix Access Control Lists (ACLs) support.
- */
-
-#include "hfsplus_fs.h"
-#include "xattr.h"
-#include "acl.h"
-
-struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
-{
-       struct posix_acl *acl;
-       char *xattr_name;
-       char *value = NULL;
-       ssize_t size;
-
-       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
-
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
-               break;
-       case ACL_TYPE_DEFAULT:
-               xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
-               break;
-       default:
-               return ERR_PTR(-EINVAL);
-       }
-
-       size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
-
-       if (size > 0) {
-               value = (char *)hfsplus_alloc_attr_entry();
-               if (unlikely(!value))
-                       return ERR_PTR(-ENOMEM);
-               size = __hfsplus_getxattr(inode, xattr_name, value, size);
-       }
-
-       if (size > 0)
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       else if (size == -ENODATA)
-               acl = NULL;
-       else
-               acl = ERR_PTR(size);
-
-       hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
-
-       return acl;
-}
-
-static int __hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
-                                  int type)
-{
-       int err;
-       char *xattr_name;
-       size_t size = 0;
-       char *value = NULL;
-
-       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
-
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
-               break;
-
-       case ACL_TYPE_DEFAULT:
-               xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
-               if (!S_ISDIR(inode->i_mode))
-                       return acl ? -EACCES : 0;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       if (acl) {
-               size = posix_acl_xattr_size(acl->a_count);
-               if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
-                       return -ENOMEM;
-               value = (char *)hfsplus_alloc_attr_entry();
-               if (unlikely(!value))
-                       return -ENOMEM;
-               err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
-               if (unlikely(err < 0))
-                       goto end_set_acl;
-       }
-
-       err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
-
-end_set_acl:
-       hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
-
-       if (!err)
-               set_cached_acl(inode, type, acl);
-
-       return err;
-}
-
-int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, int type)
-{
-       int err;
-
-       if (type == ACL_TYPE_ACCESS && acl) {
-               err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-               if (err)
-                       return err;
-       }
-       return __hfsplus_set_posix_acl(inode, acl, type);
-}
-
-int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
-{
-       int err = 0;
-       struct posix_acl *default_acl, *acl;
-
-       hfs_dbg(ACL_MOD,
-               "[%s]: ino %lu, dir->ino %lu\n",
-               __func__, inode->i_ino, dir->i_ino);
-
-       if (S_ISLNK(inode->i_mode))
-               return 0;
-
-       err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
-       if (err)
-               return err;
-
-       if (default_acl) {
-               err = __hfsplus_set_posix_acl(inode, default_acl,
-                                             ACL_TYPE_DEFAULT);
-               posix_acl_release(default_acl);
-       }
-
-       if (acl) {
-               if (!err)
-                       err = __hfsplus_set_posix_acl(inode, acl,
-                                                     ACL_TYPE_ACCESS);
-               posix_acl_release(acl);
-       }
-       return err;
-}
index a6c0f54c48c30f25315865f8080d412fb428c00a..eb4535eba95d9a5e13dfda5fb196849a069bda64 100644 (file)
@@ -524,8 +524,10 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                goto out_put_root;
        if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
                hfs_find_exit(&fd);
-               if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
+               if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
+                       err = -EINVAL;
                        goto out_put_root;
+               }
                inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
@@ -562,8 +564,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                                goto out_put_hidden_dir;
                        }
 
-                       err = hfsplus_init_inode_security(sbi->hidden_dir,
-                                                               root, &str);
+                       err = hfsplus_init_security(sbi->hidden_dir,
+                                                       root, &str);
                        if (err == -EOPNOTSUPP)
                                err = 0; /* Operation is not supported. */
                        else if (err) {
index dfa90c21948f82a34b6eedfab2bfdd8b1c996ef3..c8d1b2be7854ea5a829dfe6749121d0a70182903 100644 (file)
@@ -272,8 +272,8 @@ static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
        return size;
 }
 
-/* Decomposes a single unicode character. */
-static inline u16 *decompose_unichar(wchar_t uc, int *size)
+/* Decomposes a non-Hangul unicode character. */
+static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size)
 {
        int off;
 
@@ -296,6 +296,51 @@ static inline u16 *decompose_unichar(wchar_t uc, int *size)
        return hfsplus_decompose_table + (off / 4);
 }
 
+/*
+ * Try to decompose a unicode character as Hangul. Return 0 if @uc is not
+ * precomposed Hangul, otherwise return the length of the decomposition.
+ *
+ * This function was adapted from sample code from the Unicode Standard
+ * Annex #15: Unicode Normalization Forms, version 3.2.0.
+ *
+ * Copyright (C) 1991-2018 Unicode, Inc.  All rights reserved.  Distributed
+ * under the Terms of Use in http://www.unicode.org/copyright.html.
+ */
+static int hfsplus_try_decompose_hangul(wchar_t uc, u16 *result)
+{
+       int index;
+       int l, v, t;
+
+       index = uc - Hangul_SBase;
+       if (index < 0 || index >= Hangul_SCount)
+               return 0;
+
+       l = Hangul_LBase + index / Hangul_NCount;
+       v = Hangul_VBase + (index % Hangul_NCount) / Hangul_TCount;
+       t = Hangul_TBase + index % Hangul_TCount;
+
+       result[0] = l;
+       result[1] = v;
+       if (t != Hangul_TBase) {
+               result[2] = t;
+               return 3;
+       }
+       return 2;
+}
+
+/* Decomposes a single unicode character. */
+static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer)
+{
+       u16 *result;
+
+       /* Hangul is handled separately */
+       result = hangul_buffer;
+       *size = hfsplus_try_decompose_hangul(uc, result);
+       if (*size == 0)
+               result = hfsplus_decompose_nonhangul(uc, size);
+       return result;
+}
+
 int hfsplus_asc2uni(struct super_block *sb,
                    struct hfsplus_unistr *ustr, int max_unistr_len,
                    const char *astr, int len)
@@ -303,13 +348,14 @@ int hfsplus_asc2uni(struct super_block *sb,
        int size, dsize, decompose;
        u16 *dstr, outlen = 0;
        wchar_t c;
+       u16 dhangul[3];
 
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
        while (outlen < max_unistr_len && len > 0) {
                size = asc2unichar(sb, astr, len, &c);
 
                if (decompose)
-                       dstr = decompose_unichar(c, &dsize);
+                       dstr = decompose_unichar(c, &dsize, dhangul);
                else
                        dstr = NULL;
                if (dstr) {
@@ -344,6 +390,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
        unsigned long hash;
        wchar_t c;
        u16 c2;
+       u16 dhangul[3];
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
@@ -357,7 +404,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
                len -= size;
 
                if (decompose)
-                       dstr = decompose_unichar(c, &dsize);
+                       dstr = decompose_unichar(c, &dsize, dhangul);
                else
                        dstr = NULL;
                if (dstr) {
@@ -396,6 +443,7 @@ int hfsplus_compare_dentry(const struct dentry *dentry,
        const char *astr1, *astr2;
        u16 c1, c2;
        wchar_t c;
+       u16 dhangul_1[3], dhangul_2[3];
 
        casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
@@ -413,7 +461,8 @@ int hfsplus_compare_dentry(const struct dentry *dentry,
                        len1 -= size;
 
                        if (decompose)
-                               dstr1 = decompose_unichar(c, &dsize1);
+                               dstr1 = decompose_unichar(c, &dsize1,
+                                                         dhangul_1);
                        if (!decompose || !dstr1) {
                                c1 = c;
                                dstr1 = &c1;
@@ -427,7 +476,8 @@ int hfsplus_compare_dentry(const struct dentry *dentry,
                        len2 -= size;
 
                        if (decompose)
-                               dstr2 = decompose_unichar(c, &dsize2);
+                               dstr2 = decompose_unichar(c, &dsize2,
+                                                         dhangul_2);
                        if (!decompose || !dstr2) {
                                c2 = c;
                                dstr2 = &c2;
index e538b758c448bef6beaaf8d7558b20ef04f82eaf..d5403b4004c97ffd4e3b7d8e59fd3b61051217b4 100644 (file)
@@ -8,10 +8,8 @@
  */
 
 #include "hfsplus_fs.h"
-#include <linux/posix_acl_xattr.h>
 #include <linux/nls.h>
 #include "xattr.h"
-#include "acl.h"
 
 static int hfsplus_removexattr(struct inode *inode, const char *name);
 
@@ -19,10 +17,6 @@ const struct xattr_handler *hfsplus_xattr_handlers[] = {
        &hfsplus_xattr_osx_handler,
        &hfsplus_xattr_user_handler,
        &hfsplus_xattr_trusted_handler,
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-       &posix_acl_access_xattr_handler,
-       &posix_acl_default_xattr_handler,
-#endif
        &hfsplus_xattr_security_handler,
        NULL
 };
index a4e611d697104ba0b0e81bbf4884bb4aeb8dd1f4..d14e362b3ebaf7a4a13639067526eb910c03909e 100644 (file)
@@ -38,7 +38,4 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int hfsplus_init_security(struct inode *inode, struct inode *dir,
                                const struct qstr *qstr);
 
-int hfsplus_init_inode_security(struct inode *inode, struct inode *dir,
-                               const struct qstr *qstr);
-
 #endif
index f5550b006e8810bd43d5c2680bf80f55b3fcd511..cfbe6a3bfb1ee2e0c4123009e53d253c9bd2a5ec 100644 (file)
@@ -12,7 +12,6 @@
 
 #include "hfsplus_fs.h"
 #include "xattr.h"
-#include "acl.h"
 
 static int hfsplus_security_getxattr(const struct xattr_handler *handler,
                                     struct dentry *unused, struct inode *inode,
@@ -72,18 +71,6 @@ int hfsplus_init_security(struct inode *inode, struct inode *dir,
                                        &hfsplus_initxattrs, NULL);
 }
 
-int hfsplus_init_inode_security(struct inode *inode,
-                                               struct inode *dir,
-                                               const struct qstr *qstr)
-{
-       int err;
-
-       err = hfsplus_init_posix_acl(inode, dir);
-       if (!err)
-               err = hfsplus_init_security(inode, dir, qstr);
-       return err;
-}
-
 const struct xattr_handler hfsplus_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .get    = hfsplus_security_getxattr,
index 346a146c7617d10ab34ae8eb1bb5d6641e734d88..32920a10100e23fc60f53cf36c882278ae972cee 100644 (file)
@@ -410,7 +410,6 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
        int i, freed = 0;
        bool truncate_op = (lend == LLONG_MAX);
 
-       memset(&pseudo_vma, 0, sizeof(struct vm_area_struct));
        vma_init(&pseudo_vma, current->mm);
        pseudo_vma.vm_flags = (VM_HUGETLB | VM_MAYSHARE | VM_SHARED);
        pagevec_init(&pvec);
@@ -595,7 +594,6 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
         * allocation routines.  If NUMA is configured, use page index
         * as input to create an allocation policy.
         */
-       memset(&pseudo_vma, 0, sizeof(struct vm_area_struct));
        vma_init(&pseudo_vma, mm);
        pseudo_vma.vm_flags = (VM_HUGETLB | VM_MAYSHARE | VM_SHARED);
        pseudo_vma.vm_file = file;
index c5fa3dee72fc0b962dec9d3134d8c0d723422134..7da0fac71dc26a73d33877d9498c8007b17d11e4 100644 (file)
@@ -51,7 +51,7 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        return err;
 }
 
-static int nilfs_page_mkwrite(struct vm_fault *vmf)
+static vm_fault_t nilfs_page_mkwrite(struct vm_fault *vmf)
 {
        struct vm_area_struct *vma = vmf->vma;
        struct page *page = vmf->page;
index 6ffeca84d7c3c10830687601daaea788d9ef5415..1b9067cf451125941c2140c94aba622b875c0dde 100644 (file)
@@ -834,7 +834,7 @@ static int nilfs_setup_super(struct super_block *sb, int is_mount)
                sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT);
 
        sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1);
-       sbp[0]->s_mtime = cpu_to_le64(get_seconds());
+       sbp[0]->s_mtime = cpu_to_le64(ktime_get_real_seconds());
 
 skip_mount_setup:
        sbp[0]->s_state =
index 0eaeb41453f566f600e6f97d9d1c69faacd89d1e..817c02b13b1d549675997df79ba363cdb319105d 100644 (file)
@@ -31,6 +31,7 @@ config PROC_FS
 config PROC_KCORE
        bool "/proc/kcore support" if !ARM
        depends on PROC_FS && MMU
+       select CRASH_CORE
        help
          Provides a virtual ELF core file of the live kernel.  This can
          be read with gdb and other ELF tools.  No modifications can be
index aaffc0c302162db0fc9d682c071469f55326dc1d..ccf86f16d9f0190c18e7f4345b7ca0960709eb05 100644 (file)
@@ -463,7 +463,7 @@ static int lstats_show_proc(struct seq_file *m, void *v)
        if (!task)
                return -ESRCH;
        seq_puts(m, "Latency Top version : v0.1\n");
-       for (i = 0; i < 32; i++) {
+       for (i = 0; i < LT_SAVECOUNT; i++) {
                struct latency_record *lr = &task->latency_record[i];
                if (lr->backtrace[0]) {
                        int q;
@@ -1366,10 +1366,8 @@ static ssize_t proc_fail_nth_read(struct file *file, char __user *buf,
        if (!task)
                return -ESRCH;
        len = snprintf(numbuf, sizeof(numbuf), "%u\n", task->fail_nth);
-       len = simple_read_from_buffer(buf, count, ppos, numbuf, len);
        put_task_struct(task);
-
-       return len;
+       return simple_read_from_buffer(buf, count, ppos, numbuf, len);
 }
 
 static const struct file_operations proc_fail_nth_operations = {
@@ -2519,47 +2517,47 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
                                   size_t count, loff_t *ppos)
 {
        struct inode * inode = file_inode(file);
+       struct task_struct *task;
        void *page;
-       ssize_t length;
-       struct task_struct *task = get_proc_task(inode);
-
-       length = -ESRCH;
-       if (!task)
-               goto out_no_task;
+       int rv;
 
+       rcu_read_lock();
+       task = pid_task(proc_pid(inode), PIDTYPE_PID);
+       if (!task) {
+               rcu_read_unlock();
+               return -ESRCH;
+       }
        /* A task may only write its own attributes. */
-       length = -EACCES;
-       if (current != task)
-               goto out;
+       if (current != task) {
+               rcu_read_unlock();
+               return -EACCES;
+       }
+       rcu_read_unlock();
 
        if (count > PAGE_SIZE)
                count = PAGE_SIZE;
 
        /* No partial writes. */
-       length = -EINVAL;
        if (*ppos != 0)
-               goto out;
+               return -EINVAL;
 
        page = memdup_user(buf, count);
        if (IS_ERR(page)) {
-               length = PTR_ERR(page);
+               rv = PTR_ERR(page);
                goto out;
        }
 
        /* Guard against adverse ptrace interaction */
-       length = mutex_lock_interruptible(&current->signal->cred_guard_mutex);
-       if (length < 0)
+       rv = mutex_lock_interruptible(&current->signal->cred_guard_mutex);
+       if (rv < 0)
                goto out_free;
 
-       length = security_setprocattr(file->f_path.dentry->d_name.name,
-                                     page, count);
+       rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count);
        mutex_unlock(&current->signal->cred_guard_mutex);
 out_free:
        kfree(page);
 out:
-       put_task_struct(task);
-out_no_task:
-       return length;
+       return rv;
 }
 
 static const struct file_operations proc_pid_attr_operations = {
@@ -3309,12 +3307,12 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("cmdline",   S_IRUGO, proc_pid_cmdline_ops),
        ONE("stat",      S_IRUGO, proc_tid_stat),
        ONE("statm",     S_IRUGO, proc_pid_statm),
-       REG("maps",      S_IRUGO, proc_tid_maps_operations),
+       REG("maps",      S_IRUGO, proc_pid_maps_operations),
 #ifdef CONFIG_PROC_CHILDREN
        REG("children",  S_IRUGO, proc_tid_children_operations),
 #endif
 #ifdef CONFIG_NUMA
-       REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations),
+       REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations),
 #endif
        REG("mem",       S_IRUSR|S_IWUSR, proc_mem_operations),
        LNK("cwd",       proc_cwd_link),
@@ -3324,7 +3322,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("mountinfo",  S_IRUGO, proc_mountinfo_operations),
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
-       REG("smaps",     S_IRUGO, proc_tid_smaps_operations),
+       REG("smaps",     S_IRUGO, proc_pid_smaps_operations),
        REG("smaps_rollup", S_IRUGO, proc_pid_smaps_rollup_operations),
        REG("pagemap",    S_IRUSR, proc_pagemap_operations),
 #endif
index bb1c1625b158d03f5c8685f55e370267e1cc76fb..8ae109429a883939ed0241c1e122db7ba857ac1a 100644 (file)
@@ -286,9 +286,9 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
        if (!dir_emit_dots(file, ctx))
                return 0;
 
+       i = ctx->pos - 2;
        read_lock(&proc_subdir_lock);
        de = pde_subdir_first(de);
-       i = ctx->pos - 2;
        for (;;) {
                if (!de) {
                        read_unlock(&proc_subdir_lock);
@@ -309,8 +309,8 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
                        pde_put(de);
                        return 0;
                }
-               read_lock(&proc_subdir_lock);
                ctx->pos++;
+               read_lock(&proc_subdir_lock);
                next = pde_subdir_next(de);
                pde_put(de);
                de = next;
index 85ffbd27f2883a8e6fb3dfe8275c2e1a36ac3ffe..fc5306a31a1d8b489dc16483d79cf83b6445f387 100644 (file)
@@ -105,8 +105,10 @@ void __init proc_init_kmemcache(void)
                kmem_cache_create("pde_opener", sizeof(struct pde_opener), 0,
                                  SLAB_ACCOUNT|SLAB_PANIC, NULL);
        proc_dir_entry_cache = kmem_cache_create_usercopy(
-               "proc_dir_entry", SIZEOF_PDE_SLOT, 0, SLAB_PANIC,
-               OFFSETOF_PDE_NAME, SIZEOF_PDE_INLINE_NAME, NULL);
+               "proc_dir_entry", SIZEOF_PDE, 0, SLAB_PANIC,
+               offsetof(struct proc_dir_entry, inline_name),
+               SIZEOF_PDE_INLINE_NAME, NULL);
+       BUILD_BUG_ON(sizeof(struct proc_dir_entry) >= SIZEOF_PDE);
 }
 
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
index da3dbfa09e79c2f82a4f601f2eb103c00f716a23..5185d7f6a51ee845fc12c6d49d4497d766af6c23 100644 (file)
@@ -65,16 +65,13 @@ struct proc_dir_entry {
        char inline_name[];
 } __randomize_layout;
 
-#define OFFSETOF_PDE_NAME offsetof(struct proc_dir_entry, inline_name)
-#define SIZEOF_PDE_SLOT                                        \
-       (OFFSETOF_PDE_NAME + 34 <= 64 ? 64 :            \
-        OFFSETOF_PDE_NAME + 34 <= 128 ? 128 :          \
-        OFFSETOF_PDE_NAME + 34 <= 192 ? 192 :          \
-        OFFSETOF_PDE_NAME + 34 <= 256 ? 256 :          \
-        OFFSETOF_PDE_NAME + 34 <= 512 ? 512 :          \
-        0)
-
-#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE_SLOT - OFFSETOF_PDE_NAME)
+#define SIZEOF_PDE     (                               \
+       sizeof(struct proc_dir_entry) < 128 ? 128 :     \
+       sizeof(struct proc_dir_entry) < 192 ? 192 :     \
+       sizeof(struct proc_dir_entry) < 256 ? 256 :     \
+       sizeof(struct proc_dir_entry) < 512 ? 512 :     \
+       0)
+#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE - sizeof(struct proc_dir_entry))
 
 extern struct kmem_cache *proc_dir_entry_cache;
 void pde_free(struct proc_dir_entry *pde);
@@ -116,12 +113,12 @@ static inline void *__PDE_DATA(const struct inode *inode)
        return PDE(inode)->data;
 }
 
-static inline struct pid *proc_pid(struct inode *inode)
+static inline struct pid *proc_pid(const struct inode *inode)
 {
        return PROC_I(inode)->pid;
 }
 
-static inline struct task_struct *get_proc_task(struct inode *inode)
+static inline struct task_struct *get_proc_task(const struct inode *inode)
 {
        return get_pid_task(proc_pid(inode), PIDTYPE_PID);
 }
@@ -285,7 +282,6 @@ struct proc_maps_private {
        struct inode *inode;
        struct task_struct *task;
        struct mm_struct *mm;
-       struct mem_size_stats *rollup;
 #ifdef CONFIG_MMU
        struct vm_area_struct *tail_vma;
 #endif
@@ -297,12 +293,9 @@ struct proc_maps_private {
 struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode);
 
 extern const struct file_operations proc_pid_maps_operations;
-extern const struct file_operations proc_tid_maps_operations;
 extern const struct file_operations proc_pid_numa_maps_operations;
-extern const struct file_operations proc_tid_numa_maps_operations;
 extern const struct file_operations proc_pid_smaps_operations;
 extern const struct file_operations proc_pid_smaps_rollup_operations;
-extern const struct file_operations proc_tid_smaps_operations;
 extern const struct file_operations proc_clear_refs_operations;
 extern const struct file_operations proc_pagemap_operations;
 
index e64ecb9f272090bf6b23772a0d36e56b63b8106a..80464432dfe6459eeec7d41498a65abb4f9d0dbe 100644 (file)
@@ -10,6 +10,7 @@
  *     Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com>
  */
 
+#include <linux/crash_core.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/kcore.h>
@@ -49,32 +50,23 @@ static struct proc_dir_entry *proc_root_kcore;
 #define        kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET)
 #endif
 
-/* An ELF note in memory */
-struct memelfnote
-{
-       const char *name;
-       int type;
-       unsigned int datasz;
-       void *data;
-};
-
 static LIST_HEAD(kclist_head);
-static DEFINE_RWLOCK(kclist_lock);
+static DECLARE_RWSEM(kclist_lock);
 static int kcore_need_update = 1;
 
-void
-kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
+/* This doesn't grab kclist_lock, so it should only be used at init time. */
+void __init kclist_add(struct kcore_list *new, void *addr, size_t size,
+                      int type)
 {
        new->addr = (unsigned long)addr;
        new->size = size;
        new->type = type;
 
-       write_lock(&kclist_lock);
        list_add_tail(&new->list, &kclist_head);
-       write_unlock(&kclist_lock);
 }
 
-static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
+static size_t get_kcore_size(int *nphdr, size_t *phdrs_len, size_t *notes_len,
+                            size_t *data_offset)
 {
        size_t try, size;
        struct kcore_list *m;
@@ -88,53 +80,19 @@ static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
                        size = try;
                *nphdr = *nphdr + 1;
        }
-       *elf_buflen =   sizeof(struct elfhdr) + 
-                       (*nphdr + 2)*sizeof(struct elf_phdr) + 
-                       3 * ((sizeof(struct elf_note)) +
-                            roundup(sizeof(CORE_STR), 4)) +
-                       roundup(sizeof(struct elf_prstatus), 4) +
-                       roundup(sizeof(struct elf_prpsinfo), 4) +
-                       roundup(arch_task_struct_size, 4);
-       *elf_buflen = PAGE_ALIGN(*elf_buflen);
-       return size + *elf_buflen;
-}
-
-static void free_kclist_ents(struct list_head *head)
-{
-       struct kcore_list *tmp, *pos;
 
-       list_for_each_entry_safe(pos, tmp, head, list) {
-               list_del(&pos->list);
-               kfree(pos);
-       }
+       *phdrs_len = *nphdr * sizeof(struct elf_phdr);
+       *notes_len = (4 * sizeof(struct elf_note) +
+                     3 * ALIGN(sizeof(CORE_STR), 4) +
+                     VMCOREINFO_NOTE_NAME_BYTES +
+                     ALIGN(sizeof(struct elf_prstatus), 4) +
+                     ALIGN(sizeof(struct elf_prpsinfo), 4) +
+                     ALIGN(arch_task_struct_size, 4) +
+                     ALIGN(vmcoreinfo_size, 4));
+       *data_offset = PAGE_ALIGN(sizeof(struct elfhdr) + *phdrs_len +
+                                 *notes_len);
+       return *data_offset + size;
 }
-/*
- * Replace all KCORE_RAM/KCORE_VMEMMAP information with passed list.
- */
-static void __kcore_update_ram(struct list_head *list)
-{
-       int nphdr;
-       size_t size;
-       struct kcore_list *tmp, *pos;
-       LIST_HEAD(garbage);
-
-       write_lock(&kclist_lock);
-       if (kcore_need_update) {
-               list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
-                       if (pos->type == KCORE_RAM
-                               || pos->type == KCORE_VMEMMAP)
-                               list_move(&pos->list, &garbage);
-               }
-               list_splice_tail(list, &kclist_head);
-       } else
-               list_splice(list, &garbage);
-       kcore_need_update = 0;
-       proc_root_kcore->size = get_kcore_size(&nphdr, &size);
-       write_unlock(&kclist_lock);
-
-       free_kclist_ents(&garbage);
-}
-
 
 #ifdef CONFIG_HIGHMEM
 /*
@@ -142,11 +100,9 @@ static void __kcore_update_ram(struct list_head *list)
  * because memory hole is not as big as !HIGHMEM case.
  * (HIGHMEM is special because part of memory is _invisible_ from the kernel.)
  */
-static int kcore_update_ram(void)
+static int kcore_ram_list(struct list_head *head)
 {
-       LIST_HEAD(head);
        struct kcore_list *ent;
-       int ret = 0;
 
        ent = kmalloc(sizeof(*ent), GFP_KERNEL);
        if (!ent)
@@ -154,9 +110,8 @@ static int kcore_update_ram(void)
        ent->addr = (unsigned long)__va(0);
        ent->size = max_low_pfn << PAGE_SHIFT;
        ent->type = KCORE_RAM;
-       list_add(&ent->list, &head);
-       __kcore_update_ram(&head);
-       return ret;
+       list_add(&ent->list, head);
+       return 0;
 }
 
 #else /* !CONFIG_HIGHMEM */
@@ -255,11 +210,10 @@ free_out:
        return 1;
 }
 
-static int kcore_update_ram(void)
+static int kcore_ram_list(struct list_head *list)
 {
        int nid, ret;
        unsigned long end_pfn;
-       LIST_HEAD(head);
 
        /* Not inialized....update now */
        /* find out "max pfn" */
@@ -271,258 +225,255 @@ static int kcore_update_ram(void)
                        end_pfn = node_end;
        }
        /* scan 0 to max_pfn */
-       ret = walk_system_ram_range(0, end_pfn, &head, kclist_add_private);
-       if (ret) {
-               free_kclist_ents(&head);
+       ret = walk_system_ram_range(0, end_pfn, list, kclist_add_private);
+       if (ret)
                return -ENOMEM;
-       }
-       __kcore_update_ram(&head);
-       return ret;
+       return 0;
 }
 #endif /* CONFIG_HIGHMEM */
 
-/*****************************************************************************/
-/*
- * determine size of ELF note
- */
-static int notesize(struct memelfnote *en)
-{
-       int sz;
-
-       sz = sizeof(struct elf_note);
-       sz += roundup((strlen(en->name) + 1), 4);
-       sz += roundup(en->datasz, 4);
-
-       return sz;
-} /* end notesize() */
-
-/*****************************************************************************/
-/*
- * store a note in the header buffer
- */
-static char *storenote(struct memelfnote *men, char *bufp)
+static int kcore_update_ram(void)
 {
-       struct elf_note en;
-
-#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
-
-       en.n_namesz = strlen(men->name) + 1;
-       en.n_descsz = men->datasz;
-       en.n_type = men->type;
-
-       DUMP_WRITE(&en, sizeof(en));
-       DUMP_WRITE(men->name, en.n_namesz);
-
-       /* XXX - cast from long long to long to avoid need for libgcc.a */
-       bufp = (char*) roundup((unsigned long)bufp,4);
-       DUMP_WRITE(men->data, men->datasz);
-       bufp = (char*) roundup((unsigned long)bufp,4);
-
-#undef DUMP_WRITE
-
-       return bufp;
-} /* end storenote() */
+       LIST_HEAD(list);
+       LIST_HEAD(garbage);
+       int nphdr;
+       size_t phdrs_len, notes_len, data_offset;
+       struct kcore_list *tmp, *pos;
+       int ret = 0;
 
-/*
- * store an ELF coredump header in the supplied buffer
- * nphdr is the number of elf_phdr to insert
- */
-static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
-{
-       struct elf_prstatus prstatus;   /* NT_PRSTATUS */
-       struct elf_prpsinfo prpsinfo;   /* NT_PRPSINFO */
-       struct elf_phdr *nhdr, *phdr;
-       struct elfhdr *elf;
-       struct memelfnote notes[3];
-       off_t offset = 0;
-       struct kcore_list *m;
+       down_write(&kclist_lock);
+       if (!xchg(&kcore_need_update, 0))
+               goto out;
 
-       /* setup ELF header */
-       elf = (struct elfhdr *) bufp;
-       bufp += sizeof(struct elfhdr);
-       offset += sizeof(struct elfhdr);
-       memcpy(elf->e_ident, ELFMAG, SELFMAG);
-       elf->e_ident[EI_CLASS]  = ELF_CLASS;
-       elf->e_ident[EI_DATA]   = ELF_DATA;
-       elf->e_ident[EI_VERSION]= EV_CURRENT;
-       elf->e_ident[EI_OSABI] = ELF_OSABI;
-       memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-       elf->e_type     = ET_CORE;
-       elf->e_machine  = ELF_ARCH;
-       elf->e_version  = EV_CURRENT;
-       elf->e_entry    = 0;
-       elf->e_phoff    = sizeof(struct elfhdr);
-       elf->e_shoff    = 0;
-       elf->e_flags    = ELF_CORE_EFLAGS;
-       elf->e_ehsize   = sizeof(struct elfhdr);
-       elf->e_phentsize= sizeof(struct elf_phdr);
-       elf->e_phnum    = nphdr;
-       elf->e_shentsize= 0;
-       elf->e_shnum    = 0;
-       elf->e_shstrndx = 0;
-
-       /* setup ELF PT_NOTE program header */
-       nhdr = (struct elf_phdr *) bufp;
-       bufp += sizeof(struct elf_phdr);
-       offset += sizeof(struct elf_phdr);
-       nhdr->p_type    = PT_NOTE;
-       nhdr->p_offset  = 0;
-       nhdr->p_vaddr   = 0;
-       nhdr->p_paddr   = 0;
-       nhdr->p_filesz  = 0;
-       nhdr->p_memsz   = 0;
-       nhdr->p_flags   = 0;
-       nhdr->p_align   = 0;
-
-       /* setup ELF PT_LOAD program header for every area */
-       list_for_each_entry(m, &kclist_head, list) {
-               phdr = (struct elf_phdr *) bufp;
-               bufp += sizeof(struct elf_phdr);
-               offset += sizeof(struct elf_phdr);
-
-               phdr->p_type    = PT_LOAD;
-               phdr->p_flags   = PF_R|PF_W|PF_X;
-               phdr->p_offset  = kc_vaddr_to_offset(m->addr) + dataoff;
-               phdr->p_vaddr   = (size_t)m->addr;
-               if (m->type == KCORE_RAM || m->type == KCORE_TEXT)
-                       phdr->p_paddr   = __pa(m->addr);
-               else
-                       phdr->p_paddr   = (elf_addr_t)-1;
-               phdr->p_filesz  = phdr->p_memsz = m->size;
-               phdr->p_align   = PAGE_SIZE;
+       ret = kcore_ram_list(&list);
+       if (ret) {
+               /* Couldn't get the RAM list, try again next time. */
+               WRITE_ONCE(kcore_need_update, 1);
+               list_splice_tail(&list, &garbage);
+               goto out;
        }
 
-       /*
-        * Set up the notes in similar form to SVR4 core dumps made
-        * with info from their /proc.
-        */
-       nhdr->p_offset  = offset;
-
-       /* set up the process status */
-       notes[0].name = CORE_STR;
-       notes[0].type = NT_PRSTATUS;
-       notes[0].datasz = sizeof(struct elf_prstatus);
-       notes[0].data = &prstatus;
-
-       memset(&prstatus, 0, sizeof(struct elf_prstatus));
-
-       nhdr->p_filesz  = notesize(&notes[0]);
-       bufp = storenote(&notes[0], bufp);
-
-       /* set up the process info */
-       notes[1].name   = CORE_STR;
-       notes[1].type   = NT_PRPSINFO;
-       notes[1].datasz = sizeof(struct elf_prpsinfo);
-       notes[1].data   = &prpsinfo;
-
-       memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
-       prpsinfo.pr_state       = 0;
-       prpsinfo.pr_sname       = 'R';
-       prpsinfo.pr_zomb        = 0;
-
-       strcpy(prpsinfo.pr_fname, "vmlinux");
-       strlcpy(prpsinfo.pr_psargs, saved_command_line, sizeof(prpsinfo.pr_psargs));
-
-       nhdr->p_filesz  += notesize(&notes[1]);
-       bufp = storenote(&notes[1], bufp);
+       list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
+               if (pos->type == KCORE_RAM || pos->type == KCORE_VMEMMAP)
+                       list_move(&pos->list, &garbage);
+       }
+       list_splice_tail(&list, &kclist_head);
 
-       /* set up the task structure */
-       notes[2].name   = CORE_STR;
-       notes[2].type   = NT_TASKSTRUCT;
-       notes[2].datasz = arch_task_struct_size;
-       notes[2].data   = current;
+       proc_root_kcore->size = get_kcore_size(&nphdr, &phdrs_len, &notes_len,
+                                              &data_offset);
 
-       nhdr->p_filesz  += notesize(&notes[2]);
-       bufp = storenote(&notes[2], bufp);
+out:
+       up_write(&kclist_lock);
+       list_for_each_entry_safe(pos, tmp, &garbage, list) {
+               list_del(&pos->list);
+               kfree(pos);
+       }
+       return ret;
+}
 
-} /* end elf_kcore_store_hdr() */
+static void append_kcore_note(char *notes, size_t *i, const char *name,
+                             unsigned int type, const void *desc,
+                             size_t descsz)
+{
+       struct elf_note *note = (struct elf_note *)&notes[*i];
+
+       note->n_namesz = strlen(name) + 1;
+       note->n_descsz = descsz;
+       note->n_type = type;
+       *i += sizeof(*note);
+       memcpy(&notes[*i], name, note->n_namesz);
+       *i = ALIGN(*i + note->n_namesz, 4);
+       memcpy(&notes[*i], desc, descsz);
+       *i = ALIGN(*i + descsz, 4);
+}
 
-/*****************************************************************************/
-/*
- * read from the ELF header and then kernel memory
- */
 static ssize_t
 read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
 {
        char *buf = file->private_data;
-       ssize_t acc = 0;
-       size_t size, tsz;
-       size_t elf_buflen;
+       size_t phdrs_offset, notes_offset, data_offset;
+       size_t phdrs_len, notes_len;
+       struct kcore_list *m;
+       size_t tsz;
        int nphdr;
        unsigned long start;
+       size_t orig_buflen = buflen;
+       int ret = 0;
 
-       read_lock(&kclist_lock);
-       size = get_kcore_size(&nphdr, &elf_buflen);
+       down_read(&kclist_lock);
+
+       get_kcore_size(&nphdr, &phdrs_len, &notes_len, &data_offset);
+       phdrs_offset = sizeof(struct elfhdr);
+       notes_offset = phdrs_offset + phdrs_len;
+
+       /* ELF file header. */
+       if (buflen && *fpos < sizeof(struct elfhdr)) {
+               struct elfhdr ehdr = {
+                       .e_ident = {
+                               [EI_MAG0] = ELFMAG0,
+                               [EI_MAG1] = ELFMAG1,
+                               [EI_MAG2] = ELFMAG2,
+                               [EI_MAG3] = ELFMAG3,
+                               [EI_CLASS] = ELF_CLASS,
+                               [EI_DATA] = ELF_DATA,
+                               [EI_VERSION] = EV_CURRENT,
+                               [EI_OSABI] = ELF_OSABI,
+                       },
+                       .e_type = ET_CORE,
+                       .e_machine = ELF_ARCH,
+                       .e_version = EV_CURRENT,
+                       .e_phoff = sizeof(struct elfhdr),
+                       .e_flags = ELF_CORE_EFLAGS,
+                       .e_ehsize = sizeof(struct elfhdr),
+                       .e_phentsize = sizeof(struct elf_phdr),
+                       .e_phnum = nphdr,
+               };
+
+               tsz = min_t(size_t, buflen, sizeof(struct elfhdr) - *fpos);
+               if (copy_to_user(buffer, (char *)&ehdr + *fpos, tsz)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
 
-       if (buflen == 0 || *fpos >= size) {
-               read_unlock(&kclist_lock);
-               return 0;
+               buffer += tsz;
+               buflen -= tsz;
+               *fpos += tsz;
        }
 
-       /* trim buflen to not go beyond EOF */
-       if (buflen > size - *fpos)
-               buflen = size - *fpos;
-
-       /* construct an ELF core header if we'll need some of it */
-       if (*fpos < elf_buflen) {
-               char * elf_buf;
-
-               tsz = elf_buflen - *fpos;
-               if (buflen < tsz)
-                       tsz = buflen;
-               elf_buf = kzalloc(elf_buflen, GFP_ATOMIC);
-               if (!elf_buf) {
-                       read_unlock(&kclist_lock);
-                       return -ENOMEM;
+       /* ELF program headers. */
+       if (buflen && *fpos < phdrs_offset + phdrs_len) {
+               struct elf_phdr *phdrs, *phdr;
+
+               phdrs = kzalloc(phdrs_len, GFP_KERNEL);
+               if (!phdrs) {
+                       ret = -ENOMEM;
+                       goto out;
                }
-               elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
-               read_unlock(&kclist_lock);
-               if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
-                       kfree(elf_buf);
-                       return -EFAULT;
+
+               phdrs[0].p_type = PT_NOTE;
+               phdrs[0].p_offset = notes_offset;
+               phdrs[0].p_filesz = notes_len;
+
+               phdr = &phdrs[1];
+               list_for_each_entry(m, &kclist_head, list) {
+                       phdr->p_type = PT_LOAD;
+                       phdr->p_flags = PF_R | PF_W | PF_X;
+                       phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset;
+                       phdr->p_vaddr = (size_t)m->addr;
+                       if (m->type == KCORE_RAM)
+                               phdr->p_paddr = __pa(m->addr);
+                       else if (m->type == KCORE_TEXT)
+                               phdr->p_paddr = __pa_symbol(m->addr);
+                       else
+                               phdr->p_paddr = (elf_addr_t)-1;
+                       phdr->p_filesz = phdr->p_memsz = m->size;
+                       phdr->p_align = PAGE_SIZE;
+                       phdr++;
                }
-               kfree(elf_buf);
+
+               tsz = min_t(size_t, buflen, phdrs_offset + phdrs_len - *fpos);
+               if (copy_to_user(buffer, (char *)phdrs + *fpos - phdrs_offset,
+                                tsz)) {
+                       kfree(phdrs);
+                       ret = -EFAULT;
+                       goto out;
+               }
+               kfree(phdrs);
+
+               buffer += tsz;
                buflen -= tsz;
                *fpos += tsz;
-               buffer += tsz;
-               acc += tsz;
+       }
+
+       /* ELF note segment. */
+       if (buflen && *fpos < notes_offset + notes_len) {
+               struct elf_prstatus prstatus = {};
+               struct elf_prpsinfo prpsinfo = {
+                       .pr_sname = 'R',
+                       .pr_fname = "vmlinux",
+               };
+               char *notes;
+               size_t i = 0;
+
+               strlcpy(prpsinfo.pr_psargs, saved_command_line,
+                       sizeof(prpsinfo.pr_psargs));
+
+               notes = kzalloc(notes_len, GFP_KERNEL);
+               if (!notes) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               append_kcore_note(notes, &i, CORE_STR, NT_PRSTATUS, &prstatus,
+                                 sizeof(prstatus));
+               append_kcore_note(notes, &i, CORE_STR, NT_PRPSINFO, &prpsinfo,
+                                 sizeof(prpsinfo));
+               append_kcore_note(notes, &i, CORE_STR, NT_TASKSTRUCT, current,
+                                 arch_task_struct_size);
+               /*
+                * vmcoreinfo_size is mostly constant after init time, but it
+                * can be changed by crash_save_vmcoreinfo(). Racing here with a
+                * panic on another CPU before the machine goes down is insanely
+                * unlikely, but it's better to not leave potential buffer
+                * overflows lying around, regardless.
+                */
+               append_kcore_note(notes, &i, VMCOREINFO_NOTE_NAME, 0,
+                                 vmcoreinfo_data,
+                                 min(vmcoreinfo_size, notes_len - i));
+
+               tsz = min_t(size_t, buflen, notes_offset + notes_len - *fpos);
+               if (copy_to_user(buffer, notes + *fpos - notes_offset, tsz)) {
+                       kfree(notes);
+                       ret = -EFAULT;
+                       goto out;
+               }
+               kfree(notes);
 
-               /* leave now if filled buffer already */
-               if (buflen == 0)
-                       return acc;
-       } else
-               read_unlock(&kclist_lock);
+               buffer += tsz;
+               buflen -= tsz;
+               *fpos += tsz;
+       }
 
        /*
         * Check to see if our file offset matches with any of
         * the addresses in the elf_phdr on our list.
         */
-       start = kc_offset_to_vaddr(*fpos - elf_buflen);
+       start = kc_offset_to_vaddr(*fpos - data_offset);
        if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
                tsz = buflen;
-               
-       while (buflen) {
-               struct kcore_list *m;
 
-               read_lock(&kclist_lock);
-               list_for_each_entry(m, &kclist_head, list) {
-                       if (start >= m->addr && start < (m->addr+m->size))
-                               break;
+       m = NULL;
+       while (buflen) {
+               /*
+                * If this is the first iteration or the address is not within
+                * the previous entry, search for a matching entry.
+                */
+               if (!m || start < m->addr || start >= m->addr + m->size) {
+                       list_for_each_entry(m, &kclist_head, list) {
+                               if (start >= m->addr &&
+                                   start < m->addr + m->size)
+                                       break;
+                       }
                }
-               read_unlock(&kclist_lock);
 
                if (&m->list == &kclist_head) {
-                       if (clear_user(buffer, tsz))
-                               return -EFAULT;
+                       if (clear_user(buffer, tsz)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
                } else if (m->type == KCORE_VMALLOC) {
                        vread(buf, (char *)start, tsz);
                        /* we have to zero-fill user buffer even if no read */
-                       if (copy_to_user(buffer, buf, tsz))
-                               return -EFAULT;
+                       if (copy_to_user(buffer, buf, tsz)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
                } else if (m->type == KCORE_USER) {
                        /* User page is handled prior to normal kernel page: */
-                       if (copy_to_user(buffer, (char *)start, tsz))
-                               return -EFAULT;
+                       if (copy_to_user(buffer, (char *)start, tsz)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
                } else {
                        if (kern_addr_valid(start)) {
                                /*
@@ -530,29 +481,37 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                                 * hardened user copy kernel text checks.
                                 */
                                if (probe_kernel_read(buf, (void *) start, tsz)) {
-                                       if (clear_user(buffer, tsz))
-                                               return -EFAULT;
+                                       if (clear_user(buffer, tsz)) {
+                                               ret = -EFAULT;
+                                               goto out;
+                                       }
                                } else {
-                                       if (copy_to_user(buffer, buf, tsz))
-                                               return -EFAULT;
+                                       if (copy_to_user(buffer, buf, tsz)) {
+                                               ret = -EFAULT;
+                                               goto out;
+                                       }
                                }
                        } else {
-                               if (clear_user(buffer, tsz))
-                                       return -EFAULT;
+                               if (clear_user(buffer, tsz)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
                        }
                }
                buflen -= tsz;
                *fpos += tsz;
                buffer += tsz;
-               acc += tsz;
                start += tsz;
                tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
        }
 
-       return acc;
+out:
+       up_read(&kclist_lock);
+       if (ret)
+               return ret;
+       return orig_buflen - buflen;
 }
 
-
 static int open_kcore(struct inode *inode, struct file *filp)
 {
        if (!capable(CAP_SYS_RAWIO))
@@ -592,9 +551,8 @@ static int __meminit kcore_callback(struct notifier_block *self,
        switch (action) {
        case MEM_ONLINE:
        case MEM_OFFLINE:
-               write_lock(&kclist_lock);
                kcore_need_update = 1;
-               write_unlock(&kclist_lock);
+               break;
        }
        return NOTIFY_OK;
 }
index 2fb04846ed11618666be529393732f5d706725d0..edda898714eb7bb23585241dc6631800c6ba1dfb 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/mman.h>
 #include <linux/mmzone.h>
 #include <linux/proc_fs.h>
+#include <linux/percpu.h>
 #include <linux/quicklist.h>
 #include <linux/seq_file.h>
 #include <linux/swap.h>
@@ -121,6 +122,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                   (unsigned long)VMALLOC_TOTAL >> 10);
        show_val_kb(m, "VmallocUsed:    ", 0ul);
        show_val_kb(m, "VmallocChunk:   ", 0ul);
+       show_val_kb(m, "Percpu:         ", pcpu_nr_pages());
 
 #ifdef CONFIG_MEMORY_FAILURE
        seq_printf(m, "HardwareCorrupted: %5lu kB\n",
index 59749dfaef6743c270a00fdee97e378929a03899..535eda7857cfd5d16545edd40ce0c3cae0fb8f10 100644 (file)
@@ -183,7 +183,7 @@ static int show_stat(struct seq_file *p, void *v)
 
 static int stat_open(struct inode *inode, struct file *file)
 {
-       size_t size = 1024 + 128 * num_online_cpus();
+       unsigned int size = 1024 + 128 * num_online_cpus();
 
        /* minimum size to display an interrupt count : 2 bytes */
        size += 2 * nr_irqs;
index dfd73a4616ce565bfccb996a50f5eb549fe41fe8..5ea1d64cb0b4c19c185ad67d5990c0ce03e82561 100644 (file)
@@ -247,7 +247,6 @@ static int proc_map_release(struct inode *inode, struct file *file)
        if (priv->mm)
                mmdrop(priv->mm);
 
-       kfree(priv->rollup);
        return seq_release_private(inode, file);
 }
 
@@ -294,7 +293,7 @@ static void show_vma_header_prefix(struct seq_file *m,
 }
 
 static void
-show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
+show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
 {
        struct mm_struct *mm = vma->vm_mm;
        struct file *file = vma->vm_file;
@@ -357,35 +356,18 @@ done:
        seq_putc(m, '\n');
 }
 
-static int show_map(struct seq_file *m, void *v, int is_pid)
+static int show_map(struct seq_file *m, void *v)
 {
-       show_map_vma(m, v, is_pid);
+       show_map_vma(m, v);
        m_cache_vma(m, v);
        return 0;
 }
 
-static int show_pid_map(struct seq_file *m, void *v)
-{
-       return show_map(m, v, 1);
-}
-
-static int show_tid_map(struct seq_file *m, void *v)
-{
-       return show_map(m, v, 0);
-}
-
 static const struct seq_operations proc_pid_maps_op = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
-       .show   = show_pid_map
-};
-
-static const struct seq_operations proc_tid_maps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_tid_map
+       .show   = show_map
 };
 
 static int pid_maps_open(struct inode *inode, struct file *file)
@@ -393,11 +375,6 @@ static int pid_maps_open(struct inode *inode, struct file *file)
        return do_maps_open(inode, file, &proc_pid_maps_op);
 }
 
-static int tid_maps_open(struct inode *inode, struct file *file)
-{
-       return do_maps_open(inode, file, &proc_tid_maps_op);
-}
-
 const struct file_operations proc_pid_maps_operations = {
        .open           = pid_maps_open,
        .read           = seq_read,
@@ -405,13 +382,6 @@ const struct file_operations proc_pid_maps_operations = {
        .release        = proc_map_release,
 };
 
-const struct file_operations proc_tid_maps_operations = {
-       .open           = tid_maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = proc_map_release,
-};
-
 /*
  * Proportional Set Size(PSS): my share of RSS.
  *
@@ -433,7 +403,6 @@ const struct file_operations proc_tid_maps_operations = {
 
 #ifdef CONFIG_PROC_PAGE_MONITOR
 struct mem_size_stats {
-       bool first;
        unsigned long resident;
        unsigned long shared_clean;
        unsigned long shared_dirty;
@@ -447,7 +416,6 @@ struct mem_size_stats {
        unsigned long swap;
        unsigned long shared_hugetlb;
        unsigned long private_hugetlb;
-       unsigned long first_vma_start;
        u64 pss;
        u64 pss_locked;
        u64 swap_pss;
@@ -731,14 +699,9 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 }
 #endif /* HUGETLB_PAGE */
 
-#define SEQ_PUT_DEC(str, val) \
-               seq_put_decimal_ull_width(m, str, (val) >> 10, 8)
-static int show_smap(struct seq_file *m, void *v, int is_pid)
+static void smap_gather_stats(struct vm_area_struct *vma,
+                            struct mem_size_stats *mss)
 {
-       struct proc_maps_private *priv = m->private;
-       struct vm_area_struct *vma = v;
-       struct mem_size_stats mss_stack;
-       struct mem_size_stats *mss;
        struct mm_walk smaps_walk = {
                .pmd_entry = smaps_pte_range,
 #ifdef CONFIG_HUGETLB_PAGE
@@ -746,23 +709,6 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
 #endif
                .mm = vma->vm_mm,
        };
-       int ret = 0;
-       bool rollup_mode;
-       bool last_vma;
-
-       if (priv->rollup) {
-               rollup_mode = true;
-               mss = priv->rollup;
-               if (mss->first) {
-                       mss->first_vma_start = vma->vm_start;
-                       mss->first = false;
-               }
-               last_vma = !m_next_vma(priv, vma);
-       } else {
-               rollup_mode = false;
-               memset(&mss_stack, 0, sizeof(mss_stack));
-               mss = &mss_stack;
-       }
 
        smaps_walk.private = mss;
 
@@ -794,79 +740,116 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
        walk_page_vma(vma, &smaps_walk);
        if (vma->vm_flags & VM_LOCKED)
                mss->pss_locked += mss->pss;
+}
 
-       if (!rollup_mode) {
-               show_map_vma(m, vma, is_pid);
-       } else if (last_vma) {
-               show_vma_header_prefix(
-                       m, mss->first_vma_start, vma->vm_end, 0, 0, 0, 0);
-               seq_pad(m, ' ');
-               seq_puts(m, "[rollup]\n");
-       } else {
-               ret = SEQ_SKIP;
-       }
-
-       if (!rollup_mode) {
-               SEQ_PUT_DEC("Size:           ", vma->vm_end - vma->vm_start);
-               SEQ_PUT_DEC(" kB\nKernelPageSize: ", vma_kernel_pagesize(vma));
-               SEQ_PUT_DEC(" kB\nMMUPageSize:    ", vma_mmu_pagesize(vma));
-               seq_puts(m, " kB\n");
-       }
+#define SEQ_PUT_DEC(str, val) \
+               seq_put_decimal_ull_width(m, str, (val) >> 10, 8)
 
-       if (!rollup_mode || last_vma) {
-               SEQ_PUT_DEC("Rss:            ", mss->resident);
-               SEQ_PUT_DEC(" kB\nPss:            ", mss->pss >> PSS_SHIFT);
-               SEQ_PUT_DEC(" kB\nShared_Clean:   ", mss->shared_clean);
-               SEQ_PUT_DEC(" kB\nShared_Dirty:   ", mss->shared_dirty);
-               SEQ_PUT_DEC(" kB\nPrivate_Clean:  ", mss->private_clean);
-               SEQ_PUT_DEC(" kB\nPrivate_Dirty:  ", mss->private_dirty);
-               SEQ_PUT_DEC(" kB\nReferenced:     ", mss->referenced);
-               SEQ_PUT_DEC(" kB\nAnonymous:      ", mss->anonymous);
-               SEQ_PUT_DEC(" kB\nLazyFree:       ", mss->lazyfree);
-               SEQ_PUT_DEC(" kB\nAnonHugePages:  ", mss->anonymous_thp);
-               SEQ_PUT_DEC(" kB\nShmemPmdMapped: ", mss->shmem_thp);
-               SEQ_PUT_DEC(" kB\nShared_Hugetlb: ", mss->shared_hugetlb);
-               seq_put_decimal_ull_width(m, " kB\nPrivate_Hugetlb: ",
-                                         mss->private_hugetlb >> 10, 7);
-               SEQ_PUT_DEC(" kB\nSwap:           ", mss->swap);
-               SEQ_PUT_DEC(" kB\nSwapPss:        ",
-                                               mss->swap_pss >> PSS_SHIFT);
-               SEQ_PUT_DEC(" kB\nLocked:         ",
-                                               mss->pss_locked >> PSS_SHIFT);
-               seq_puts(m, " kB\n");
-       }
-       if (!rollup_mode) {
-               if (arch_pkeys_enabled())
-                       seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
-               show_smap_vma_flags(m, vma);
-       }
-       m_cache_vma(m, vma);
-       return ret;
+/* Show the contents common for smaps and smaps_rollup */
+static void __show_smap(struct seq_file *m, const struct mem_size_stats *mss)
+{
+       SEQ_PUT_DEC("Rss:            ", mss->resident);
+       SEQ_PUT_DEC(" kB\nPss:            ", mss->pss >> PSS_SHIFT);
+       SEQ_PUT_DEC(" kB\nShared_Clean:   ", mss->shared_clean);
+       SEQ_PUT_DEC(" kB\nShared_Dirty:   ", mss->shared_dirty);
+       SEQ_PUT_DEC(" kB\nPrivate_Clean:  ", mss->private_clean);
+       SEQ_PUT_DEC(" kB\nPrivate_Dirty:  ", mss->private_dirty);
+       SEQ_PUT_DEC(" kB\nReferenced:     ", mss->referenced);
+       SEQ_PUT_DEC(" kB\nAnonymous:      ", mss->anonymous);
+       SEQ_PUT_DEC(" kB\nLazyFree:       ", mss->lazyfree);
+       SEQ_PUT_DEC(" kB\nAnonHugePages:  ", mss->anonymous_thp);
+       SEQ_PUT_DEC(" kB\nShmemPmdMapped: ", mss->shmem_thp);
+       SEQ_PUT_DEC(" kB\nShared_Hugetlb: ", mss->shared_hugetlb);
+       seq_put_decimal_ull_width(m, " kB\nPrivate_Hugetlb: ",
+                                 mss->private_hugetlb >> 10, 7);
+       SEQ_PUT_DEC(" kB\nSwap:           ", mss->swap);
+       SEQ_PUT_DEC(" kB\nSwapPss:        ",
+                                       mss->swap_pss >> PSS_SHIFT);
+       SEQ_PUT_DEC(" kB\nLocked:         ",
+                                       mss->pss_locked >> PSS_SHIFT);
+       seq_puts(m, " kB\n");
 }
-#undef SEQ_PUT_DEC
 
-static int show_pid_smap(struct seq_file *m, void *v)
+static int show_smap(struct seq_file *m, void *v)
 {
-       return show_smap(m, v, 1);
+       struct vm_area_struct *vma = v;
+       struct mem_size_stats mss;
+
+       memset(&mss, 0, sizeof(mss));
+
+       smap_gather_stats(vma, &mss);
+
+       show_map_vma(m, vma);
+
+       SEQ_PUT_DEC("Size:           ", vma->vm_end - vma->vm_start);
+       SEQ_PUT_DEC(" kB\nKernelPageSize: ", vma_kernel_pagesize(vma));
+       SEQ_PUT_DEC(" kB\nMMUPageSize:    ", vma_mmu_pagesize(vma));
+       seq_puts(m, " kB\n");
+
+       __show_smap(m, &mss);
+
+       if (arch_pkeys_enabled())
+               seq_printf(m, "ProtectionKey:  %8u\n", vma_pkey(vma));
+       show_smap_vma_flags(m, vma);
+
+       m_cache_vma(m, vma);
+
+       return 0;
 }
 
-static int show_tid_smap(struct seq_file *m, void *v)
+static int show_smaps_rollup(struct seq_file *m, void *v)
 {
-       return show_smap(m, v, 0);
+       struct proc_maps_private *priv = m->private;
+       struct mem_size_stats mss;
+       struct mm_struct *mm;
+       struct vm_area_struct *vma;
+       unsigned long last_vma_end = 0;
+       int ret = 0;
+
+       priv->task = get_proc_task(priv->inode);
+       if (!priv->task)
+               return -ESRCH;
+
+       mm = priv->mm;
+       if (!mm || !mmget_not_zero(mm)) {
+               ret = -ESRCH;
+               goto out_put_task;
+       }
+
+       memset(&mss, 0, sizeof(mss));
+
+       down_read(&mm->mmap_sem);
+       hold_task_mempolicy(priv);
+
+       for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
+               smap_gather_stats(vma, &mss);
+               last_vma_end = vma->vm_end;
+       }
+
+       show_vma_header_prefix(m, priv->mm->mmap->vm_start,
+                              last_vma_end, 0, 0, 0, 0);
+       seq_pad(m, ' ');
+       seq_puts(m, "[rollup]\n");
+
+       __show_smap(m, &mss);
+
+       release_task_mempolicy(priv);
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+
+out_put_task:
+       put_task_struct(priv->task);
+       priv->task = NULL;
+
+       return ret;
 }
+#undef SEQ_PUT_DEC
 
 static const struct seq_operations proc_pid_smaps_op = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
-       .show   = show_pid_smap
-};
-
-static const struct seq_operations proc_tid_smaps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_tid_smap
+       .show   = show_smap
 };
 
 static int pid_smaps_open(struct inode *inode, struct file *file)
@@ -874,28 +857,45 @@ static int pid_smaps_open(struct inode *inode, struct file *file)
        return do_maps_open(inode, file, &proc_pid_smaps_op);
 }
 
-static int pid_smaps_rollup_open(struct inode *inode, struct file *file)
+static int smaps_rollup_open(struct inode *inode, struct file *file)
 {
-       struct seq_file *seq;
+       int ret;
        struct proc_maps_private *priv;
-       int ret = do_maps_open(inode, file, &proc_pid_smaps_op);
-
-       if (ret < 0)
-               return ret;
-       seq = file->private_data;
-       priv = seq->private;
-       priv->rollup = kzalloc(sizeof(*priv->rollup), GFP_KERNEL);
-       if (!priv->rollup) {
-               proc_map_release(inode, file);
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL_ACCOUNT);
+       if (!priv)
                return -ENOMEM;
+
+       ret = single_open(file, show_smaps_rollup, priv);
+       if (ret)
+               goto out_free;
+
+       priv->inode = inode;
+       priv->mm = proc_mem_open(inode, PTRACE_MODE_READ);
+       if (IS_ERR(priv->mm)) {
+               ret = PTR_ERR(priv->mm);
+
+               single_release(inode, file);
+               goto out_free;
        }
-       priv->rollup->first = true;
+
        return 0;
+
+out_free:
+       kfree(priv);
+       return ret;
 }
 
-static int tid_smaps_open(struct inode *inode, struct file *file)
+static int smaps_rollup_release(struct inode *inode, struct file *file)
 {
-       return do_maps_open(inode, file, &proc_tid_smaps_op);
+       struct seq_file *seq = file->private_data;
+       struct proc_maps_private *priv = seq->private;
+
+       if (priv->mm)
+               mmdrop(priv->mm);
+
+       kfree(priv);
+       return single_release(inode, file);
 }
 
 const struct file_operations proc_pid_smaps_operations = {
@@ -906,17 +906,10 @@ const struct file_operations proc_pid_smaps_operations = {
 };
 
 const struct file_operations proc_pid_smaps_rollup_operations = {
-       .open           = pid_smaps_rollup_open,
+       .open           = smaps_rollup_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = proc_map_release,
-};
-
-const struct file_operations proc_tid_smaps_operations = {
-       .open           = tid_smaps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = proc_map_release,
+       .release        = smaps_rollup_release,
 };
 
 enum clear_refs_types {
@@ -1728,7 +1721,7 @@ static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
 /*
  * Display pages allocated per node and memory policy via /proc.
  */
-static int show_numa_map(struct seq_file *m, void *v, int is_pid)
+static int show_numa_map(struct seq_file *m, void *v)
 {
        struct numa_maps_private *numa_priv = m->private;
        struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
@@ -1812,45 +1805,17 @@ out:
        return 0;
 }
 
-static int show_pid_numa_map(struct seq_file *m, void *v)
-{
-       return show_numa_map(m, v, 1);
-}
-
-static int show_tid_numa_map(struct seq_file *m, void *v)
-{
-       return show_numa_map(m, v, 0);
-}
-
 static const struct seq_operations proc_pid_numa_maps_op = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
-       .show   = show_pid_numa_map,
+       .show   = show_numa_map,
 };
 
-static const struct seq_operations proc_tid_numa_maps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_tid_numa_map,
-};
-
-static int numa_maps_open(struct inode *inode, struct file *file,
-                         const struct seq_operations *ops)
-{
-       return proc_maps_open(inode, file, ops,
-                               sizeof(struct numa_maps_private));
-}
-
 static int pid_numa_maps_open(struct inode *inode, struct file *file)
 {
-       return numa_maps_open(inode, file, &proc_pid_numa_maps_op);
-}
-
-static int tid_numa_maps_open(struct inode *inode, struct file *file)
-{
-       return numa_maps_open(inode, file, &proc_tid_numa_maps_op);
+       return proc_maps_open(inode, file, &proc_pid_numa_maps_op,
+                               sizeof(struct numa_maps_private));
 }
 
 const struct file_operations proc_pid_numa_maps_operations = {
@@ -1860,10 +1825,4 @@ const struct file_operations proc_pid_numa_maps_operations = {
        .release        = proc_map_release,
 };
 
-const struct file_operations proc_tid_numa_maps_operations = {
-       .open           = tid_numa_maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = proc_map_release,
-};
 #endif /* CONFIG_NUMA */
index 5b62f57bd9bceed80b386057b93fbce3a43602b3..0b63d68dedb2a018e716aa4cb4e93663a8b46992 100644 (file)
@@ -142,8 +142,7 @@ static int is_stack(struct vm_area_struct *vma)
 /*
  * display a single VMA to a sequenced file
  */
-static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
-                         int is_pid)
+static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long ino = 0;
@@ -189,22 +188,11 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 /*
  * display mapping lines for a particular process's /proc/pid/maps
  */
-static int show_map(struct seq_file *m, void *_p, int is_pid)
+static int show_map(struct seq_file *m, void *_p)
 {
        struct rb_node *p = _p;
 
-       return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb),
-                             is_pid);
-}
-
-static int show_pid_map(struct seq_file *m, void *_p)
-{
-       return show_map(m, _p, 1);
-}
-
-static int show_tid_map(struct seq_file *m, void *_p)
-{
-       return show_map(m, _p, 0);
+       return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb));
 }
 
 static void *m_start(struct seq_file *m, loff_t *pos)
@@ -260,14 +248,7 @@ static const struct seq_operations proc_pid_maps_ops = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
-       .show   = show_pid_map
-};
-
-static const struct seq_operations proc_tid_maps_ops = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_tid_map
+       .show   = show_map
 };
 
 static int maps_open(struct inode *inode, struct file *file,
@@ -308,11 +289,6 @@ static int pid_maps_open(struct inode *inode, struct file *file)
        return maps_open(inode, file, &proc_pid_maps_ops);
 }
 
-static int tid_maps_open(struct inode *inode, struct file *file)
-{
-       return maps_open(inode, file, &proc_tid_maps_ops);
-}
-
 const struct file_operations proc_pid_maps_operations = {
        .open           = pid_maps_open,
        .read           = seq_read,
@@ -320,10 +296,3 @@ const struct file_operations proc_pid_maps_operations = {
        .release        = map_release,
 };
 
-const struct file_operations proc_tid_maps_operations = {
-       .open           = tid_maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = map_release,
-};
-
index 3f723cb478af31c721ec263b4db9fb3e9ac17054..a4c2791ab70baf8c5124a5e00d0e4a374652d13f 100644 (file)
@@ -9,7 +9,7 @@
 
 static int uptime_proc_show(struct seq_file *m, void *v)
 {
-       struct timespec uptime;
+       struct timespec64 uptime;
        struct timespec64 idle;
        u64 nsec;
        u32 rem;
@@ -19,7 +19,7 @@ static int uptime_proc_show(struct seq_file *m, void *v)
        for_each_possible_cpu(i)
                nsec += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
 
-       get_monotonic_boottime(&uptime);
+       ktime_get_boottime_ts64(&uptime);
        idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
        idle.tv_nsec = rem;
        seq_printf(m, "%lu.%02lu %lu.%02lu\n",
index cfb6674331fded9083883df0d02a7e7f45c40d55..6c1c2607e9e4cf392e5faf05182a572f1c4bb175 100644 (file)
@@ -379,7 +379,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
  * On s390 the fault handler is used for memory regions that can't be mapped
  * directly with remap_pfn_range().
  */
-static int mmap_vmcore_fault(struct vm_fault *vmf)
+static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
 {
 #ifdef CONFIG_S390
        struct address_space *mapping = vmf->vma->vm_file->f_mapping;
index e3c558d1b78c02c711ae9868fe409d349127103f..3a5a752d96c7bbfdb920193d9a5c427d08772423 100644 (file)
@@ -33,30 +33,22 @@ static int sd_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize)
        return 0;
 }
 
-static char *print_time(time_t t)
-{
-       static char timebuf[256];
-
-       sprintf(timebuf, "%ld", t);
-       return timebuf;
-}
-
 static void sd_print_item(struct item_head *ih, char *item)
 {
        printk("\tmode | size | nlinks | first direct | mtime\n");
        if (stat_data_v1(ih)) {
                struct stat_data_v1 *sd = (struct stat_data_v1 *)item;
 
-               printk("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd),
+               printk("\t0%-6o | %6u | %2u | %d | %u\n", sd_v1_mode(sd),
                       sd_v1_size(sd), sd_v1_nlink(sd),
                       sd_v1_first_direct_byte(sd),
-                      print_time(sd_v1_mtime(sd)));
+                      sd_v1_mtime(sd));
        } else {
                struct stat_data *sd = (struct stat_data *)item;
 
-               printk("\t0%-6o | %6llu | %2u | %d | %s\n", sd_v2_mode(sd),
+               printk("\t0%-6o | %6llu | %2u | %d | %u\n", sd_v2_mode(sd),
                       (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
-                      sd_v2_rdev(sd), print_time(sd_v2_mtime(sd)));
+                      sd_v2_rdev(sd), sd_v2_mtime(sd));
        }
 }
 
index 52eb5d293a343dc26a544c7f5d7b3fbec1de4b04..8a76f9d14bc661c5a6760d7815ac1e97352f8e0c 100644 (file)
@@ -2381,7 +2381,7 @@ static int journal_read(struct super_block *sb)
        struct reiserfs_journal_desc *desc;
        unsigned int oldest_trans_id = 0;
        unsigned int oldest_invalid_trans_id = 0;
-       time_t start;
+       time64_t start;
        unsigned long oldest_start = 0;
        unsigned long cur_dblock = 0;
        unsigned long newest_mount_id = 9;
@@ -2395,7 +2395,7 @@ static int journal_read(struct super_block *sb)
        cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(sb);
        reiserfs_info(sb, "checking transaction log (%pg)\n",
                      journal->j_dev_bd);
-       start = get_seconds();
+       start = ktime_get_seconds();
 
        /*
         * step 1, read in the journal header block.  Check the transaction
@@ -2556,7 +2556,7 @@ start_log_replay:
        if (replay_count > 0) {
                reiserfs_info(sb,
                              "replayed %d transactions in %lu seconds\n",
-                             replay_count, get_seconds() - start);
+                             replay_count, ktime_get_seconds() - start);
        }
        /* needed to satisfy the locking in _update_journal_header_block */
        reiserfs_write_lock(sb);
@@ -2914,7 +2914,7 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th,
                                   int new_alloc)
 {
        struct reiserfs_journal *journal = SB_JOURNAL(th->t_super);
-       time_t now = get_seconds();
+       time64_t now = ktime_get_seconds();
        /* cannot restart while nested */
        BUG_ON(!th->t_trans_id);
        if (th->t_refcount > 1)
@@ -3023,7 +3023,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
                              struct super_block *sb, unsigned long nblocks,
                              int join)
 {
-       time_t now = get_seconds();
+       time64_t now = ktime_get_seconds();
        unsigned int old_trans_id;
        struct reiserfs_journal *journal = SB_JOURNAL(sb);
        struct reiserfs_transaction_handle myth;
@@ -3056,7 +3056,7 @@ relock:
                PROC_INFO_INC(sb, journal.journal_relock_writers);
                goto relock;
        }
-       now = get_seconds();
+       now = ktime_get_seconds();
 
        /*
         * if there is no room in the journal OR
@@ -3119,7 +3119,7 @@ relock:
        }
        /* we are the first writer, set trans_id */
        if (journal->j_trans_start_time == 0) {
-               journal->j_trans_start_time = get_seconds();
+               journal->j_trans_start_time = ktime_get_seconds();
        }
        atomic_inc(&journal->j_wcount);
        journal->j_len_alloc += nblocks;
@@ -3559,11 +3559,11 @@ static void flush_async_commits(struct work_struct *work)
  */
 void reiserfs_flush_old_commits(struct super_block *sb)
 {
-       time_t now;
+       time64_t now;
        struct reiserfs_transaction_handle th;
        struct reiserfs_journal *journal = SB_JOURNAL(sb);
 
-       now = get_seconds();
+       now = ktime_get_seconds();
        /*
         * safety check so we don't flush while we are replaying the log during
         * mount
@@ -3613,7 +3613,7 @@ void reiserfs_flush_old_commits(struct super_block *sb)
 static int check_journal_end(struct reiserfs_transaction_handle *th, int flags)
 {
 
-       time_t now;
+       time64_t now;
        int flush = flags & FLUSH_ALL;
        int commit_now = flags & COMMIT_NOW;
        int wait_on_commit = flags & WAIT;
@@ -3694,7 +3694,7 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, int flags)
        }
 
        /* deal with old transactions where we are the last writers */
-       now = get_seconds();
+       now = ktime_get_seconds();
        if ((now - journal->j_trans_start_time) > journal->j_max_trans_age) {
                commit_now = 1;
                journal->j_next_async_flush = 1;
index e39b3910d24d981fb1eac72fbae8c809d9f3ae45..f2cf3441fdfc9f20ea6500ca2b8c6fddafb422fe 100644 (file)
@@ -297,6 +297,13 @@ static int show_oidmap(struct seq_file *m, void *unused)
        return 0;
 }
 
+static time64_t ktime_mono_to_real_seconds(time64_t mono)
+{
+       ktime_t kt = ktime_set(mono, NSEC_PER_SEC/2);
+
+       return ktime_divns(ktime_mono_to_real(kt), NSEC_PER_SEC);
+}
+
 static int show_journal(struct seq_file *m, void *unused)
 {
        struct super_block *sb = m->private;
@@ -325,7 +332,7 @@ static int show_journal(struct seq_file *m, void *unused)
                   "j_bcount: \t%lu\n"
                   "j_first_unflushed_offset: \t%lu\n"
                   "j_last_flush_trans_id: \t%u\n"
-                  "j_trans_start_time: \t%li\n"
+                  "j_trans_start_time: \t%lli\n"
                   "j_list_bitmap_index: \t%i\n"
                   "j_must_wait: \t%i\n"
                   "j_next_full_flush: \t%i\n"
@@ -366,7 +373,7 @@ static int show_journal(struct seq_file *m, void *unused)
                   JF(j_bcount),
                   JF(j_first_unflushed_offset),
                   JF(j_last_flush_trans_id),
-                  JF(j_trans_start_time),
+                  ktime_mono_to_real_seconds(JF(j_trans_start_time)),
                   JF(j_list_bitmap_index),
                   JF(j_must_wait),
                   JF(j_next_full_flush),
index ae4811fecc1fc793d531cbf6a709d8e89c9b2459..e5ca9ed79e54cda20606497abffa76470011d31d 100644 (file)
@@ -271,7 +271,7 @@ struct reiserfs_journal_list {
 
        struct mutex j_commit_mutex;
        unsigned int j_trans_id;
-       time_t j_timestamp;
+       time64_t j_timestamp; /* write-only but useful for crash dump analysis */
        struct reiserfs_list_bitmap *j_list_bitmap;
        struct buffer_head *j_commit_bh;        /* commit buffer head */
        struct reiserfs_journal_cnode *j_realblock;
@@ -331,7 +331,7 @@ struct reiserfs_journal {
 
        struct buffer_head *j_header_bh;
 
-       time_t j_trans_start_time;      /* time this transaction started */
+       time64_t j_trans_start_time;    /* time this transaction started */
        struct mutex j_mutex;
        struct mutex j_flush_mutex;
 
index ff94fad477e461435e335030dd7baf99c0783636..48cdfc81fe10641da6025849c27d8f307f968a50 100644 (file)
@@ -792,8 +792,10 @@ static int listxattr_filler(struct dir_context *ctx, const char *name,
                        return 0;
                size = namelen + 1;
                if (b->buf) {
-                       if (size > b->size)
+                       if (b->pos + size > b->size) {
+                               b->pos = -ERANGE;
                                return -ERANGE;
+                       }
                        memcpy(b->buf + b->pos, name, namelen);
                        b->buf[b->pos + namelen] = 0;
                }
index bec9f79adb25a207dca39feeb924b7e946f664db..499a20a5a0107f3ca8942485a7a5b3bc58737793 100644 (file)
@@ -35,7 +35,7 @@
 static int sysv_sync_fs(struct super_block *sb, int wait)
 {
        struct sysv_sb_info *sbi = SYSV_SB(sb);
-       unsigned long time = get_seconds(), old_time;
+       u32 time = (u32)ktime_get_real_seconds(), old_time;
 
        mutex_lock(&sbi->s_lock);
 
@@ -46,8 +46,8 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
         */
        old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
        if (sbi->s_type == FSTYPE_SYSV4) {
-               if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
-                       *sbi->s_sb_state = cpu_to_fs32(sbi, 0x7c269d38 - time);
+               if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38u - old_time))
+                       *sbi->s_sb_state = cpu_to_fs32(sbi, 0x7c269d38u - time);
                *sbi->s_sb_time = cpu_to_fs32(sbi, time);
                mark_buffer_dirty(sbi->s_bh2);
        }
index 15c265d450bf897568aed207c8fccdb6a00f40f9..f649023b19b5cec6a44c57189ddd754ffa6b2bce 100644 (file)
@@ -910,7 +910,7 @@ wakeup:
         */
        spin_lock(&ctx->fault_pending_wqh.lock);
        __wake_up_locked_key(&ctx->fault_pending_wqh, TASK_NORMAL, &range);
-       __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, &range);
+       __wake_up(&ctx->fault_wqh, TASK_NORMAL, 1, &range);
        spin_unlock(&ctx->fault_pending_wqh.lock);
 
        /* Flush pending events that may still wait on event_wqh */
@@ -1066,7 +1066,7 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
                         * anyway.
                         */
                        list_del(&uwq->wq.entry);
-                       __add_wait_queue(&ctx->fault_wqh, &uwq->wq);
+                       add_wait_queue(&ctx->fault_wqh, &uwq->wq);
 
                        write_seqcount_end(&ctx->refile_seq);
 
@@ -1215,7 +1215,7 @@ static void __wake_userfault(struct userfaultfd_ctx *ctx,
                __wake_up_locked_key(&ctx->fault_pending_wqh, TASK_NORMAL,
                                     range);
        if (waitqueue_active(&ctx->fault_wqh))
-               __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, range);
+               __wake_up(&ctx->fault_wqh, TASK_NORMAL, 1, range);
        spin_unlock(&ctx->fault_pending_wqh.lock);
 }
 
index a7613e1b0c87a4a38635b6fe99333afde18238b6..20561a60db9c4f077c68ee1a182eac38ff96d4dd 100644 (file)
@@ -75,9 +75,19 @@ struct bug_entry {
 
 /*
  * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
- * significant issues that need prompt attention if they should ever
- * appear at runtime.  Use the versions with printk format strings
- * to provide better diagnostics.
+ * significant kernel issues that need prompt attention if they should ever
+ * appear at runtime.
+ *
+ * Do not use these macros when checking for invalid external inputs
+ * (e.g. invalid system call arguments, or invalid data coming from
+ * network/devices), and on transient conditions like ENOMEM or EAGAIN.
+ * These macros should be used for recoverable kernel issues only.
+ * For invalid external inputs, transient conditions, etc use
+ * pr_err[_once/_ratelimited]() followed by dump_stack(), if necessary.
+ * Do not include "BUG"/"WARNING" in format strings manually to make these
+ * conditions distinguishable from kernel issues.
+ *
+ * Use the versions with printk format strings to provide better diagnostics.
  */
 #ifndef __WARN_TAINT
 extern __printf(3, 4)
index 68efb950a9184cae22225a38a0fc7d9053cffa8a..4d73e6e3c66c6977acd08e97fa93e2e229a9b283 100644 (file)
@@ -5,12 +5,10 @@
 #define KSYM_FUNC(x) x
 #endif
 #ifdef CONFIG_64BIT
-#define __put .quad
 #ifndef KSYM_ALIGN
 #define KSYM_ALIGN 8
 #endif
 #else
-#define __put .long
 #ifndef KSYM_ALIGN
 #define KSYM_ALIGN 4
 #endif
 #define KCRC_ALIGN 4
 #endif
 
+.macro __put, val, name
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+       .long   \val - ., \name - .
+#elif defined(CONFIG_64BIT)
+       .quad   \val, \name
+#else
+       .long   \val, \name
+#endif
+.endm
+
 /*
  * note on .section use: @progbits vs %progbits nastiness doesn't matter,
  * since we immediately emit into those sections anyway.
index 24251762c20c94edd238cfca1c1f55f0269d4e80..9a6bc0951cfaf1559607ea2a6a6df6f1abb106f0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/kref.h>
+#include <linux/refcount.h>
 
 struct page;
 struct device;
@@ -75,7 +76,7 @@ enum wb_reason {
  */
 struct bdi_writeback_congested {
        unsigned long state;            /* WB_[a]sync_congested flags */
-       atomic_t refcnt;                /* nr of attached wb's and blkg */
+       refcount_t refcnt;              /* nr of attached wb's and blkg */
 
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct backing_dev_info *__bdi; /* the associated bdi, set to NULL
index 72ca0f3d39f3039b0cda57c2a350c941075bdd62..c28a47cbe355ea8e74e94e72035cdae8d16cb168 100644 (file)
@@ -404,13 +404,13 @@ static inline bool inode_cgwb_enabled(struct inode *inode)
 static inline struct bdi_writeback_congested *
 wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp)
 {
-       atomic_inc(&bdi->wb_congested->refcnt);
+       refcount_inc(&bdi->wb_congested->refcnt);
        return bdi->wb_congested;
 }
 
 static inline void wb_congested_put(struct bdi_writeback_congested *congested)
 {
-       if (atomic_dec_and_test(&congested->refcnt))
+       if (refcount_dec_and_test(&congested->refcnt))
                kfree(congested);
 }
 
index af419012d77de428dd7df26c958001f615ab8c3f..7ddb1349394dbc4472779592ce590366d7571094 100644 (file)
@@ -4,7 +4,8 @@
 #include <asm/types.h>
 #include <linux/bits.h>
 
-#define BITS_TO_LONGS(nr)      DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
+#define BITS_TO_LONGS(nr)      DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
 
 extern unsigned int __sw_hweight8(unsigned int w);
 extern unsigned int __sw_hweight16(unsigned int w);
index 42506e4d1f53699a10d100e4d49a098c95d27b10..681d866efb1eb858c377cae5a35806e2931a97d8 100644 (file)
@@ -280,6 +280,25 @@ unsigned long read_word_at_a_time(const void *addr)
 
 #endif /* __KERNEL__ */
 
+/*
+ * Force the compiler to emit 'sym' as a symbol, so that we can reference
+ * it from inline assembler. Necessary in case 'sym' could be inlined
+ * otherwise, or eliminated entirely due to lack of references that are
+ * visible to the compiler.
+ */
+#define __ADDRESSABLE(sym) \
+       static void * __attribute__((section(".discard.addressable"), used)) \
+               __PASTE(__addressable_##sym, __LINE__) = (void *)&sym;
+
+/**
+ * offset_to_ptr - convert a relative memory offset to an absolute pointer
+ * @off:       the address of the 32-bit offset value
+ */
+static inline void *offset_to_ptr(const int *off)
+{
+       return (void *)((unsigned long)off + *off);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #ifndef __optimize
@@ -313,7 +332,7 @@ unsigned long read_word_at_a_time(const void *addr)
 #ifdef __OPTIMIZE__
 # define __compiletime_assert(condition, msg, prefix, suffix)          \
        do {                                                            \
-               bool __cond = !(condition);                             \
+               int __cond = !(condition);                              \
                extern void prefix ## suffix(void) __compiletime_error(msg); \
                if (__cond)                                             \
                        prefix ## suffix();                             \
index b511f6d24b42b0c4a2796bc33f494d86b7c7854b..525510a9f965f5877ce161f4e623cad9144bfd97 100644 (file)
@@ -60,6 +60,8 @@ phys_addr_t paddr_vmcoreinfo_note(void);
 #define VMCOREINFO_CONFIG(name) \
        vmcoreinfo_append_str("CONFIG_%s=y\n", #name)
 
+extern unsigned char *vmcoreinfo_data;
+extern size_t vmcoreinfo_size;
 extern u32 *vmcoreinfo_note;
 
 Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
diff --git a/include/linux/crc64.h b/include/linux/crc64.h
new file mode 100644 (file)
index 0000000..c756e65
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * See lib/crc64.c for the related specification and polynomial arithmetic.
+ */
+#ifndef _LINUX_CRC64_H
+#define _LINUX_CRC64_H
+
+#include <linux/types.h>
+
+u64 __pure crc64_be(u64 crc, const void *p, size_t len);
+#endif /* _LINUX_CRC64_H */
index b768d6dd3c9035de05452969642295ab50916460..ae072bc5aacf8365245bdbc50f6c19b9e3d5812c 100644 (file)
 #define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x)
 
 #ifndef __ASSEMBLY__
-struct kernel_symbol
-{
-       unsigned long value;
-       const char *name;
-};
-
 #ifdef MODULE
 extern struct module __this_module;
 #define THIS_MODULE (&__this_module)
@@ -54,19 +48,58 @@ extern struct module __this_module;
 #define __CRC_SYMBOL(sym, sec)
 #endif
 
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#include <linux/compiler.h>
+/*
+ * Emit the ksymtab entry as a pair of relative references: this reduces
+ * the size by half on 64-bit architectures, and eliminates the need for
+ * absolute relocations that require runtime processing on relocatable
+ * kernels.
+ */
+#define __KSYMTAB_ENTRY(sym, sec)                                      \
+       __ADDRESSABLE(sym)                                              \
+       asm("   .section \"___ksymtab" sec "+" #sym "\", \"a\"  \n"     \
+           "   .balign 8                                       \n"     \
+           "__ksymtab_" #sym ":                                \n"     \
+           "   .long   " #sym "- .                             \n"     \
+           "   .long   __kstrtab_" #sym "- .                   \n"     \
+           "   .previous                                       \n")
+
+struct kernel_symbol {
+       int value_offset;
+       int name_offset;
+};
+#else
+#define __KSYMTAB_ENTRY(sym, sec)                                      \
+       static const struct kernel_symbol __ksymtab_##sym               \
+       __attribute__((section("___ksymtab" sec "+" #sym), used))       \
+       = { (unsigned long)&sym, __kstrtab_##sym }
+
+struct kernel_symbol {
+       unsigned long value;
+       const char *name;
+};
+#endif
+
 /* For every exported symbol, place a struct in the __ksymtab section */
 #define ___EXPORT_SYMBOL(sym, sec)                                     \
        extern typeof(sym) sym;                                         \
        __CRC_SYMBOL(sym, sec)                                          \
        static const char __kstrtab_##sym[]                             \
-       __attribute__((section("__ksymtab_strings"), aligned(1)))       \
+       __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
        = #sym;                                                         \
-       static const struct kernel_symbol __ksymtab_##sym               \
-       __used                                                          \
-       __attribute__((section("___ksymtab" sec "+" #sym), used))       \
-       = { (unsigned long)&sym, __kstrtab_##sym }
+       __KSYMTAB_ENTRY(sym, sec)
+
+#if defined(__DISABLE_EXPORTS)
+
+/*
+ * Allow symbol exports to be disabled completely so that C code may
+ * be reused in other execution contexts such as the UEFI stub or the
+ * decompressor.
+ */
+#define __EXPORT_SYMBOL(sym, sec)
 
-#if defined(__KSYM_DEPS__)
+#elif defined(__KSYM_DEPS__)
 
 /*
  * For fine grained build dependencies, we want to tell the build system
index bc27cf03c41ea5a4b19d87bb82da0f3d36e9390e..2538d176dd1fac053c6ccac3ff907ab4e66b8118 100644 (file)
 typedef int (*initcall_t)(void);
 typedef void (*exitcall_t)(void);
 
-extern initcall_t __con_initcall_start[], __con_initcall_end[];
-extern initcall_t __security_initcall_start[], __security_initcall_end[];
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+typedef int initcall_entry_t;
+
+static inline initcall_t initcall_from_entry(initcall_entry_t *entry)
+{
+       return offset_to_ptr(entry);
+}
+#else
+typedef initcall_t initcall_entry_t;
+
+static inline initcall_t initcall_from_entry(initcall_entry_t *entry)
+{
+       return *entry;
+}
+#endif
+
+extern initcall_entry_t __con_initcall_start[], __con_initcall_end[];
+extern initcall_entry_t __security_initcall_start[], __security_initcall_end[];
 
 /* Used for contructor calls. */
 typedef void (*ctor_fn_t)(void);
@@ -167,9 +183,20 @@ extern bool initcall_debug;
  * as KEEP() in the linker script.
  */
 
-#define __define_initcall(fn, id) \
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#define ___define_initcall(fn, id, __sec)                      \
+       __ADDRESSABLE(fn)                                       \
+       asm(".section   \"" #__sec ".init\", \"a\"      \n"     \
+       "__initcall_" #fn #id ":                        \n"     \
+           ".long      " #fn " - .                     \n"     \
+           ".previous                                  \n");
+#else
+#define ___define_initcall(fn, id, __sec) \
        static initcall_t __initcall_##fn##id __used \
-       __attribute__((__section__(".initcall" #id ".init"))) = fn;
+               __attribute__((__section__(#__sec ".init"))) = fn;
+#endif
+
+#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
 
 /*
  * Early initcalls run before initializing SMP.
@@ -208,13 +235,8 @@ extern bool initcall_debug;
 #define __exitcall(fn)                                         \
        static exitcall_t __exitcall_##fn __exit_call = fn
 
-#define console_initcall(fn)                                   \
-       static initcall_t __initcall_##fn                       \
-       __used __section(.con_initcall.init) = fn
-
-#define security_initcall(fn)                                  \
-       static initcall_t __initcall_##fn                       \
-       __used __section(.security_initcall.init) = fn
+#define console_initcall(fn)   ___define_initcall(fn,, .con_initcall)
+#define security_initcall(fn)  ___define_initcall(fn,, .security_initcall)
 
 struct obs_kernel_param {
        const char *str;
index 6cea726612b770168eab5041259d8c52fc264bf2..6ab8c1bada3fccb11119f93130b1989ddb090ad3 100644 (file)
@@ -16,10 +16,9 @@ struct user_namespace;
 struct ipc_ids {
        int in_use;
        unsigned short seq;
-       bool tables_initialized;
        struct rw_semaphore rwsem;
        struct idr ipcs_idr;
-       int max_id;
+       int max_idx;
 #ifdef CONFIG_CHECKPOINT_RESTORE
        int next_id;
 #endif
index 8de55e4b5ee93bf824ba2a33a6cd4664c590acd8..c20f296438fbb84997474cb681a51e57eef558ef 100644 (file)
@@ -35,7 +35,7 @@ struct vmcoredd_node {
 };
 
 #ifdef CONFIG_PROC_KCORE
-extern void kclist_add(struct kcore_list *, void *, size_t, int type);
+void __init kclist_add(struct kcore_list *, void *, size_t, int type);
 #else
 static inline
 void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
index 941dc0a5a877998e46d11541bdb491655a5f34af..d6aac75b51baab469d05ad6ca816b46bcd590906 100644 (file)
  * arguments just once each.
  */
 #define __round_mask(x, y) ((__typeof__(x))((y)-1))
+/**
+ * round_up - round up to next specified power of 2
+ * @x: the value to round
+ * @y: multiple to round up to (must be a power of 2)
+ *
+ * Rounds @x up to next multiple of @y (which must be a power of 2).
+ * To perform arbitrary rounding up, use roundup() below.
+ */
 #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+/**
+ * round_down - round down to next specified power of 2
+ * @x: the value to round
+ * @y: multiple to round down to (must be a power of 2)
+ *
+ * Rounds @x down to next multiple of @y (which must be a power of 2).
+ * To perform arbitrary rounding down, use rounddown() below.
+ */
 #define round_down(x, y) ((x) & ~__round_mask(x, y))
 
 /**
 # define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d)
 #endif
 
-/* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
+/**
+ * roundup - round up to the next specified multiple
+ * @x: the value to up
+ * @y: multiple to round up to
+ *
+ * Rounds @x up to next multiple of @y. If @y will always be a power
+ * of 2, consider using the faster round_up().
+ *
+ * The `const' here prevents gcc-3.3 from calling __divdi3
+ */
 #define roundup(x, y) (                                        \
 {                                                      \
        const typeof(y) __y = y;                        \
        (((x) + (__y - 1)) / __y) * __y;                \
 }                                                      \
 )
+/**
+ * rounddown - round down to next specified multiple
+ * @x: the value to round
+ * @y: multiple to round down to
+ *
+ * Rounds @x down to next multiple of @y. If @y will always be a power
+ * of 2, consider using the faster round_down().
+ */
 #define rounddown(x, y) (                              \
 {                                                      \
        typeof(x) __x = (x);                            \
index 7c7362dd2faa9c549500756713ea5512c973cfcf..0205aee44dedd8522be52ffe7d3237dd3819656a 100644 (file)
@@ -1289,8 +1289,8 @@ static inline long kvm_arch_vcpu_async_ioctl(struct file *filp,
 }
 #endif /* CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL */
 
-void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
-               unsigned long start, unsigned long end);
+int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+               unsigned long start, unsigned long end, bool blockable);
 
 #ifdef CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE
 int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu);
index 0e6c515fb698f7a6e8c139b2fc87b9286342ca06..652f602167df49b58830acca591e3fbe5fb67185 100644 (file)
@@ -225,6 +225,11 @@ struct mem_cgroup {
         */
        bool use_hierarchy;
 
+       /*
+        * Should the OOM killer kill all belonging tasks, had it kill one?
+        */
+       bool oom_group;
+
        /* protected by memcg_oom_lock */
        bool            oom_lock;
        int             under_oom;
@@ -542,6 +547,9 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
 }
 
 bool mem_cgroup_oom_synchronize(bool wait);
+struct mem_cgroup *mem_cgroup_get_oom_group(struct task_struct *victim,
+                                           struct mem_cgroup *oom_domain);
+void mem_cgroup_print_oom_group(struct mem_cgroup *memcg);
 
 #ifdef CONFIG_MEMCG_SWAP
 extern int do_swap_account;
@@ -1001,6 +1009,16 @@ static inline bool mem_cgroup_oom_synchronize(bool wait)
        return false;
 }
 
+static inline struct mem_cgroup *mem_cgroup_get_oom_group(
+       struct task_struct *victim, struct mem_cgroup *oom_domain)
+{
+       return NULL;
+}
+
+static inline void mem_cgroup_print_oom_group(struct mem_cgroup *memcg)
+{
+}
+
 static inline unsigned long memcg_page_state(struct mem_cgroup *memcg,
                                             int idx)
 {
index 4e9828cda7a26ee6796b127c06a35513bd5a29d1..34a28227068dcba6cba30feb13e15aeff9f69b08 100644 (file)
@@ -319,6 +319,7 @@ static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
 static inline void remove_memory(int nid, u64 start, u64 size) {}
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+extern void __ref free_area_init_core_hotplug(int nid);
 extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
                void *arg, int (*func)(struct memory_block *, void *));
 extern int add_memory(int nid, u64 start, u64 size);
index a3cae495f9ce951716d4e13ca1a23e6c6e36bd83..a9e733b5fb76e8b37a8c12ec80876c519cdb4d8f 100644 (file)
@@ -456,6 +456,7 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 {
        static const struct vm_operations_struct dummy_vm_ops = {};
 
+       memset(vma, 0, sizeof(*vma));
        vma->vm_mm = mm;
        vma->vm_ops = &dummy_vm_ops;
        INIT_LIST_HEAD(&vma->anon_vma_chain);
@@ -959,15 +960,6 @@ static inline int page_zone_id(struct page *page)
        return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK;
 }
 
-static inline int zone_to_nid(struct zone *zone)
-{
-#ifdef CONFIG_NUMA
-       return zone->node;
-#else
-       return 0;
-#endif
-}
-
 #ifdef NODE_NOT_IN_PAGE_FLAGS
 extern int page_to_nid(const struct page *page);
 #else
@@ -2023,7 +2015,7 @@ static inline spinlock_t *pud_lock(struct mm_struct *mm, pud_t *pud)
 
 extern void __init pagecache_init(void);
 extern void free_area_init(unsigned long * zones_size);
-extern void free_area_init_node(int nid, unsigned long * zones_size,
+extern void __init free_area_init_node(int nid, unsigned long * zones_size,
                unsigned long zone_start_pfn, unsigned long *zholes_size);
 extern void free_initmem(void);
 
index 392e6af827016cb48d8bfffde0b096463378aaad..133ba78820ee5f2da69b865df43689c0a736ba3e 100644 (file)
@@ -151,13 +151,15 @@ struct mmu_notifier_ops {
         * address space but may still be referenced by sptes until
         * the last refcount is dropped.
         *
-        * If both of these callbacks cannot block, and invalidate_range
-        * cannot block, mmu_notifier_ops.flags should have
-        * MMU_INVALIDATE_DOES_NOT_BLOCK set.
+        * If blockable argument is set to false then the callback cannot
+        * sleep and has to return with -EAGAIN. 0 should be returned
+        * otherwise.
+        *
         */
-       void (*invalidate_range_start)(struct mmu_notifier *mn,
+       int (*invalidate_range_start)(struct mmu_notifier *mn,
                                       struct mm_struct *mm,
-                                      unsigned long start, unsigned long end);
+                                      unsigned long start, unsigned long end,
+                                      bool blockable);
        void (*invalidate_range_end)(struct mmu_notifier *mn,
                                     struct mm_struct *mm,
                                     unsigned long start, unsigned long end);
@@ -229,8 +231,9 @@ extern int __mmu_notifier_test_young(struct mm_struct *mm,
                                     unsigned long address);
 extern void __mmu_notifier_change_pte(struct mm_struct *mm,
                                      unsigned long address, pte_t pte);
-extern void __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
-                                 unsigned long start, unsigned long end);
+extern int __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end,
+                                 bool blockable);
 extern void __mmu_notifier_invalidate_range_end(struct mm_struct *mm,
                                  unsigned long start, unsigned long end,
                                  bool only_end);
@@ -281,7 +284,15 @@ static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm,
                                  unsigned long start, unsigned long end)
 {
        if (mm_has_notifiers(mm))
-               __mmu_notifier_invalidate_range_start(mm, start, end);
+               __mmu_notifier_invalidate_range_start(mm, start, end, true);
+}
+
+static inline int mmu_notifier_invalidate_range_start_nonblock(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end)
+{
+       if (mm_has_notifiers(mm))
+               return __mmu_notifier_invalidate_range_start(mm, start, end, false);
+       return 0;
 }
 
 static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm,
@@ -461,6 +472,12 @@ static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm,
 {
 }
 
+static inline int mmu_notifier_invalidate_range_start_nonblock(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end)
+{
+       return 0;
+}
+
 static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm,
                                  unsigned long start, unsigned long end)
 {
index 32699b2dc52a1f8bece62d3ae7d35d67cbe1e88f..1e22d96734e0099476b18d14ca7c11a991d3a470 100644 (file)
@@ -755,25 +755,6 @@ static inline bool pgdat_is_empty(pg_data_t *pgdat)
        return !pgdat->node_start_pfn && !pgdat->node_spanned_pages;
 }
 
-static inline int zone_id(const struct zone *zone)
-{
-       struct pglist_data *pgdat = zone->zone_pgdat;
-
-       return zone - pgdat->node_zones;
-}
-
-#ifdef CONFIG_ZONE_DEVICE
-static inline bool is_dev_zone(const struct zone *zone)
-{
-       return zone_id(zone) == ZONE_DEVICE;
-}
-#else
-static inline bool is_dev_zone(const struct zone *zone)
-{
-       return false;
-}
-#endif
-
 #include <linux/memory_hotplug.h>
 
 void build_all_zonelists(pg_data_t *pgdat);
@@ -824,6 +805,18 @@ static inline int local_memory_node(int node_id) { return node_id; };
  */
 #define zone_idx(zone)         ((zone) - (zone)->zone_pgdat->node_zones)
 
+#ifdef CONFIG_ZONE_DEVICE
+static inline bool is_dev_zone(const struct zone *zone)
+{
+       return zone_idx(zone) == ZONE_DEVICE;
+}
+#else
+static inline bool is_dev_zone(const struct zone *zone)
+{
+       return false;
+}
+#endif
+
 /*
  * Returns true if a zone has pages managed by the buddy allocator.
  * All the reclaim decisions have to use this function rather than
@@ -841,6 +834,25 @@ static inline bool populated_zone(struct zone *zone)
        return zone->present_pages;
 }
 
+#ifdef CONFIG_NUMA
+static inline int zone_to_nid(struct zone *zone)
+{
+       return zone->node;
+}
+
+static inline void zone_set_nid(struct zone *zone, int nid)
+{
+       zone->node = nid;
+}
+#else
+static inline int zone_to_nid(struct zone *zone)
+{
+       return 0;
+}
+
+static inline void zone_set_nid(struct zone *zone, int nid) {}
+#endif
+
 extern int movable_zone;
 
 #ifdef CONFIG_HIGHMEM
@@ -956,12 +968,7 @@ static inline int zonelist_zone_idx(struct zoneref *zoneref)
 
 static inline int zonelist_node_idx(struct zoneref *zoneref)
 {
-#ifdef CONFIG_NUMA
-       /* zone_to_nid not available in this context */
-       return zoneref->zone->node;
-#else
-       return 0;
-#endif /* CONFIG_NUMA */
+       return zone_to_nid(zoneref->zone);
 }
 
 struct zoneref *__next_zones_zonelist(struct zoneref *z,
index db99240d00bdfea565ea6ed838bbfe5eeba4aa33..c79e859408e62d7cd7306407bbaf4c6489103905 100644 (file)
@@ -363,7 +363,6 @@ static inline void net_dim_sample(u16 event_ctr,
 }
 
 #define NET_DIM_NEVENTS 64
-#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
 #define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1))
 
 static inline void net_dim_calc_stats(struct net_dim_sample *start,
index 1fbde8a880d9a08b43cf57373f134b306c136dd3..5a30ad594ccc11d40879ec8438b587f519b5c791 100644 (file)
@@ -518,7 +518,7 @@ static inline int node_random(const nodemask_t *mask)
  * NODEMASK_ALLOC(type, name) allocates an object with a specified type and
  * name.
  */
-#if NODES_SHIFT > 8 /* nodemask_t > 256 bytes */
+#if NODES_SHIFT > 8 /* nodemask_t > 32 bytes */
 #define NODEMASK_ALLOC(type, name, gfp_flags)  \
                        type *name = kmalloc(sizeof(*name), gfp_flags)
 #define NODEMASK_FREE(m)                       kfree(m)
index 6adac113e96d29b5059ed65ac0522237c9b94388..92f70e4c62529fff53e592f99be9ec12d6372ce2 100644 (file)
@@ -95,7 +95,7 @@ static inline int check_stable_address_space(struct mm_struct *mm)
        return 0;
 }
 
-void __oom_reap_task_mm(struct mm_struct *mm);
+bool __oom_reap_task_mm(struct mm_struct *mm);
 
 extern unsigned long oom_badness(struct task_struct *p,
                struct mem_cgroup *memcg, const nodemask_t *nodemask,
index 9b87f19369067db116e4fab9086a571b2406a89c..e72ca8dd6241b88cae56cc27de7e05e10182f267 100644 (file)
@@ -1809,7 +1809,11 @@ struct pci_fixup {
        u16 device;                     /* Or PCI_ANY_ID */
        u32 class;                      /* Or PCI_ANY_ID */
        unsigned int class_shift;       /* should be 0, 8, 16 */
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+       int hook_offset;
+#else
        void (*hook)(struct pci_dev *dev);
+#endif
 };
 
 enum pci_fixup_pass {
@@ -1823,12 +1827,28 @@ enum pci_fixup_pass {
        pci_fixup_suspend_late, /* pci_device_suspend_late() */
 };
 
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#define __DECLARE_PCI_FIXUP_SECTION(sec, name, vendor, device, class,  \
+                                   class_shift, hook)                  \
+       __ADDRESSABLE(hook)                                             \
+       asm(".section " #sec ", \"a\"                           \n"     \
+           ".balign    16                                      \n"     \
+           ".short "   #vendor ", " #device "                  \n"     \
+           ".long "    #class ", " #class_shift "              \n"     \
+           ".long "    #hook " - .                             \n"     \
+           ".previous                                          \n");
+#define DECLARE_PCI_FIXUP_SECTION(sec, name, vendor, device, class,    \
+                                 class_shift, hook)                    \
+       __DECLARE_PCI_FIXUP_SECTION(sec, name, vendor, device, class,   \
+                                 class_shift, hook)
+#else
 /* Anonymous variables would be nice... */
 #define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class,        \
                                  class_shift, hook)                    \
        static const struct pci_fixup __PASTE(__pci_fixup_##name,__LINE__) __used       \
        __attribute__((__section__(#section), aligned((sizeof(void *)))))    \
                = { vendor, device, class, class_shift, hook };
+#endif
 
 #define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class,           \
                                         class_shift, hook)             \
index 296bbe49d5d18368737e89203cf96d6937f8f016..70b7123f38c7c9044bb262a2cecc96ab415b1f4d 100644 (file)
@@ -149,4 +149,6 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
        (typeof(type) __percpu *)__alloc_percpu(sizeof(type),           \
                                                __alignof__(type))
 
+extern unsigned long pcpu_nr_pages(void);
+
 #endif /* __LINUX_PERCPU_H */
index 626fc65c433640c5d6c6302949c9a3028c84a6de..d0e1f1522a78e4213381614f77eea1a0d37d3f9e 100644 (file)
@@ -129,7 +129,7 @@ int open_related_ns(struct ns_common *ns,
                   struct ns_common *(*get_ns)(struct ns_common *ns));
 
 /* get the associated pid namespace for a file in procfs */
-static inline struct pid_namespace *proc_pid_ns(struct inode *inode)
+static inline struct pid_namespace *proc_pid_ns(const struct inode *inode)
 {
        return inode->i_sb->s_fs_info;
 }
index 00de3e950dd486679a8cd4bcb4fa7b4fd7aeac8a..977cb57d7bc9e7183e6ca628e4f75d236ddf3951 100644 (file)
@@ -854,6 +854,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_DETECT_HUNG_TASK
        unsigned long                   last_switch_count;
+       unsigned long                   last_switch_time;
 #endif
        /* Filesystem information: */
        struct fs_struct                *fs;
index 4e9b77fb702de0604e04687a7aef9d107eed1726..1be35729c2c5b9c0bb915653d7778e0acbdfd29b 100644 (file)
@@ -323,7 +323,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey);
 int force_sig_ptrace_errno_trap(int errno, void __user *addr);
 
 extern int send_sig_info(int, struct siginfo *, struct task_struct *);
-extern int force_sigsegv(int, struct task_struct *);
+extern void force_sigsegv(int sig, struct task_struct *p);
 extern int force_sig_info(int, struct siginfo *, struct task_struct *);
 extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
 extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
index 913488d828cb609e15d3bb4f379b49f60f62a659..a9c32daeb9d88376a4e7ce79e7de13534c95b2ea 100644 (file)
@@ -10,6 +10,7 @@ struct ctl_table;
 extern int          sysctl_hung_task_check_count;
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_timeout_secs;
+extern unsigned long sysctl_hung_task_check_interval_secs;
 extern int sysctl_hung_task_warnings;
 extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
                                         void __user *buffer,
index 96fe289c4c6e496fefd005d3100c84bf58f81698..39ad98c09c5808e42a04c5155f0d52aef92cbae8 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/uidgid.h>
 #include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/ratelimit.h>
 
 struct key;
@@ -12,7 +13,7 @@ struct key;
  * Some day this will be a full-fledged user tracking system..
  */
 struct user_struct {
-       atomic_t __count;       /* reference count */
+       refcount_t __count;     /* reference count */
        atomic_t processes;     /* How many processes does this user have? */
        atomic_t sigpending;    /* How many pending signals does this user have? */
 #ifdef CONFIG_FANOTIFY
@@ -59,7 +60,7 @@ extern struct user_struct root_user;
 extern struct user_struct * alloc_uid(kuid_t);
 static inline struct user_struct *get_uid(struct user_struct *u)
 {
-       atomic_inc(&u->__count);
+       refcount_inc(&u->__count);
        return u;
 }
 extern void free_uid(struct user_struct *);
index b154fd2b084c11ab3718ba8a6afcbc69481acf49..9443cafd19696a65919514abb140a522ea6312b6 100644 (file)
@@ -12,6 +12,9 @@
 struct shrink_control {
        gfp_t gfp_mask;
 
+       /* current node being shrunk (for NUMA aware shrinkers) */
+       int nid;
+
        /*
         * How many objects scan_objects should scan and try to reclaim.
         * This is reset before every call, so it is safe for callees
@@ -26,9 +29,6 @@ struct shrink_control {
         */
        unsigned long nr_scanned;
 
-       /* current node being shrunk (for NUMA aware shrinkers) */
-       int nid;
-
        /* current memcg being shrunk (for memcg aware shrinkers) */
        struct mem_cgroup *memcg;
 };
@@ -63,9 +63,9 @@ struct shrinker {
        unsigned long (*scan_objects)(struct shrinker *,
                                      struct shrink_control *sc);
 
-       int seeks;      /* seeks to recreate an obj */
        long batch;     /* reclaim batch size, 0 = default */
-       unsigned long flags;
+       int seeks;      /* seeks to recreate an obj */
+       unsigned flags;
 
        /* These are for internal use */
        struct list_head list;
index fe125b0335f7dba28ac0344b6527d86505da605e..3d4cd5db30a966b015a89cccc78b9fc2301bb895 100644 (file)
@@ -267,7 +267,7 @@ extern void set_current_blocked(sigset_t *);
 extern void __set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
 
-extern int get_signal(struct ksignal *ksig);
+extern bool get_signal(struct ksignal *ksig);
 extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping);
 extern void exit_signals(struct task_struct *tsk);
 extern void kernel_sigaction(int, __sighandler_t);
@@ -289,7 +289,7 @@ static inline void disallow_signal(int sig)
 
 extern struct kmem_cache *sighand_cachep;
 
-int unhandled_signal(struct task_struct *tsk, int sig);
+extern bool unhandled_signal(struct task_struct *tsk, int sig);
 
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
index 1a8bd05a335ed787b29142913035eacef7c36273..8e2c11e692baf9bba6380d63888cfbf5a206cf0b 100644 (file)
@@ -447,7 +447,7 @@ extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(struct page *page);
 extern void put_swap_page(struct page *page, swp_entry_t entry);
 extern swp_entry_t get_swap_page_of_type(int);
-extern int get_swap_pages(int n, bool cluster, swp_entry_t swp_entries[]);
+extern int get_swap_pages(int n, swp_entry_t swp_entries[], int entry_size);
 extern int add_swap_count_continuation(swp_entry_t, gfp_t);
 extern void swap_shmem_alloc(swp_entry_t);
 extern int swap_duplicate(swp_entry_t);
index d9a084c72541c0ea1c39823687bfcb33289fa580..7f2e16e76ac476b4fb07223af23d15490c14b4d4 100644 (file)
@@ -249,6 +249,19 @@ extern void syscall_unregfunc(void);
                return static_key_false(&__tracepoint_##name.key);      \
        }
 
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#define __TRACEPOINT_ENTRY(name)                                       \
+       asm("   .section \"__tracepoints_ptrs\", \"a\"          \n"     \
+           "   .balign 4                                       \n"     \
+           "   .long   __tracepoint_" #name " - .              \n"     \
+           "   .previous                                       \n")
+#else
+#define __TRACEPOINT_ENTRY(name)                                        \
+       static struct tracepoint * const __tracepoint_ptr_##name __used  \
+       __attribute__((section("__tracepoints_ptrs"))) =                 \
+               &__tracepoint_##name
+#endif
+
 /*
  * We have no guarantee that gcc and the linker won't up-align the tracepoint
  * structures, so we create an array of pointers that will be used for iteration
@@ -258,11 +271,9 @@ extern void syscall_unregfunc(void);
        static const char __tpstrtab_##name[]                            \
        __attribute__((section("__tracepoints_strings"))) = #name;       \
        struct tracepoint __tracepoint_##name                            \
-       __attribute__((section("__tracepoints"))) =                      \
+       __attribute__((section("__tracepoints"), used)) =                \
                { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\
-       static struct tracepoint * const __tracepoint_ptr_##name __used  \
-       __attribute__((section("__tracepoints_ptrs"))) =                 \
-               &__tracepoint_##name;
+       __TRACEPOINT_ENTRY(name);
 
 #define DEFINE_TRACE(name)                                             \
        DEFINE_TRACE_FN(name, NULL, NULL);
index 6a17f856f8418b199f78108833d576e18daa142f..381cdf5a9bd1ea5da114e41c068f81c92c879c1e 100644 (file)
@@ -119,7 +119,8 @@ typedef int (*umem_call_back)(struct ib_umem *item, u64 start, u64 end,
  */
 int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root,
                                  u64 start, u64 end,
-                                 umem_call_back cb, void *cookie);
+                                 umem_call_back cb,
+                                 bool blockable, void *cookie);
 
 /*
  * Find first region intersecting with address range.
index e13eec3dfb2f86dca4a06830cc64b9ab91c62cf4..df31aa9c9a8c3abe699e5875d814eb354257bd25 100644 (file)
@@ -23,7 +23,7 @@
 #define AUTOFS_MIN_PROTO_VERSION       3
 #define AUTOFS_MAX_PROTO_VERSION       5
 
-#define AUTOFS_PROTO_SUBVERSION                2
+#define AUTOFS_PROTO_SUBVERSION                3
 
 /*
  * The wait_queue_token (autofs_wqt_t) is part of a structure which is passed
@@ -90,8 +90,10 @@ enum {
 /* autofs version 4 and later definitions */
 
 /* Mask for expire behaviour */
-#define AUTOFS_EXP_IMMEDIATE           1
-#define AUTOFS_EXP_LEAVES              2
+#define AUTOFS_EXP_NORMAL              0x00
+#define AUTOFS_EXP_IMMEDIATE           0x01
+#define AUTOFS_EXP_LEAVES              0x02
+#define AUTOFS_EXP_FORCED              0x04
 
 #define AUTOFS_TYPE_ANY                        0U
 #define AUTOFS_TYPE_INDIRECT           1U
index 9bd50ba8253f73ef4c5d064416129f6ce09ac1ca..641dd7dd7c8ab71ae7f7d385ce03412b18477892 100644 (file)
@@ -436,7 +436,7 @@ config BSD_PROCESS_ACCT_V3
        help
          If you say Y here, the process accounting information is written
          in a new file format that also logs the process IDs of each
-         process and it's parent. Note that this file format is incompatible
+         process and its parent. Note that this file format is incompatible
          with previous v0/v1/v2 file formats, so you will need updated tools
          for processing it. A preliminary version of these tools is available
          at <http://www.gnu.org/software/acct/>.
@@ -967,6 +967,18 @@ config NET_NS
 
 endif # NAMESPACES
 
+config CHECKPOINT_RESTORE
+       bool "Checkpoint/restore support"
+       select PROC_CHILDREN
+       default n
+       help
+         Enables additional kernel features in a sake of checkpoint/restore.
+         In particular it adds auxiliary prctl codes to setup process text,
+         data and heap segment sizes, and a few additional /proc filesystem
+         entries.
+
+         If unsure, say N here.
+
 config SCHED_AUTOGROUP
        bool "Automatic process group scheduling"
        select CGROUPS
@@ -1383,18 +1395,6 @@ config MEMBARRIER
 
          If unsure, say Y.
 
-config CHECKPOINT_RESTORE
-       bool "Checkpoint/restore support" if EXPERT
-       select PROC_CHILDREN
-       default n
-       help
-         Enables additional kernel features in a sake of checkpoint/restore.
-         In particular it adds auxiliary prctl codes to setup process text,
-         data and heap segment sizes, and a few additional /proc filesystem
-         entries.
-
-         If unsure, say N here.
-
 config KALLSYMS
         bool "Load all symbols for debugging/ksymoops" if EXPERT
         default y
@@ -1702,7 +1702,7 @@ config MMAP_ALLOW_UNINITIALIZED
        default n
        help
          Normally, and according to the Linux spec, anonymous memory obtained
-         from mmap() has it's contents cleared before it is passed to
+         from mmap() has its contents cleared before it is passed to
          userspace.  Enabling this config option allows you to request that
          mmap() skip that if it is given an MAP_UNINITIALIZED flag, thus
          providing a huge performance boost.  If this option is not enabled,
index 2c71dabe56260ee00283b78984f67ea9d5d61eba..e1c9afa9d8c9103fa1463a45a425c9468e4c1628 100644 (file)
@@ -1,13 +1,3 @@
-/*
- * Many of the syscalls used in this file expect some of the arguments
- * to be __user pointers not __kernel pointers.  To limit the sparse
- * noise, turn off sparse checking for this file.
- */
-#ifdef __CHECKER__
-#undef __CHECKER__
-#warning "Sparse checking disabled for this file"
-#endif
-
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/ctype.h>
index 5a91aefa7305b441328c613b8a8b10b740338e0d..d1a5d885ce13eb566667b5d32de782c6c4694944 100644 (file)
@@ -1,14 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Many of the syscalls used in this file expect some of the arguments
- * to be __user pointers not __kernel pointers.  To limit the sparse
- * noise, turn off sparse checking for this file.
- */
-#ifdef __CHECKER__
-#undef __CHECKER__
-#warning "Sparse checking disabled for this file"
-#endif
-
 #include <linux/unistd.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
index 7d85d172bc7e265ae2e4541a95d495799ee6446e..b84031528dd4466541a4ac75890e39738fd4c589 100644 (file)
@@ -1,14 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Many of the syscalls used in this file expect some of the arguments
- * to be __user pointers not __kernel pointers.  To limit the sparse
- * noise, turn off sparse checking for this file.
- */
-#ifdef __CHECKER__
-#undef __CHECKER__
-#warning "Sparse checking disabled for this file"
-#endif
-
 #include <linux/delay.h>
 #include <linux/raid/md_u.h>
 #include <linux/raid/md_p.h>
index 035a5f0ab26b9882d251784f2abd348d7eef2b9a..32fb049d18f9b40f95d000eb60e70bb7a87aa65c 100644 (file)
@@ -1,14 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Many of the syscalls used in this file expect some of the arguments
- * to be __user pointers not __kernel pointers.  To limit the sparse
- * noise, turn off sparse checking for this file.
- */
-#ifdef __CHECKER__
-#undef __CHECKER__
-#warning "Sparse checking disabled for this file"
-#endif
-
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
index 13643c46ebab2cc065b4bb8a985c2cc3756d0c1b..640557788026d8d947841c8da384056ec94ec4a0 100644 (file)
@@ -1,14 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Many of the syscalls used in this file expect some of the arguments
- * to be __user pointers not __kernel pointers.  To limit the sparse
- * noise, turn off sparse checking for this file.
- */
-#ifdef __CHECKER__
-#undef __CHECKER__
-#warning "Sparse checking disabled for this file"
-#endif
-
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
index b729e1f22838c0834f99edb8ee33b7a60b56cdd0..18f8f0140fa0351691b45f1152e64ee1b10e3f24 100644 (file)
@@ -902,18 +902,18 @@ int __init_or_module do_one_initcall(initcall_t fn)
 }
 
 
-extern initcall_t __initcall_start[];
-extern initcall_t __initcall0_start[];
-extern initcall_t __initcall1_start[];
-extern initcall_t __initcall2_start[];
-extern initcall_t __initcall3_start[];
-extern initcall_t __initcall4_start[];
-extern initcall_t __initcall5_start[];
-extern initcall_t __initcall6_start[];
-extern initcall_t __initcall7_start[];
-extern initcall_t __initcall_end[];
-
-static initcall_t *initcall_levels[] __initdata = {
+extern initcall_entry_t __initcall_start[];
+extern initcall_entry_t __initcall0_start[];
+extern initcall_entry_t __initcall1_start[];
+extern initcall_entry_t __initcall2_start[];
+extern initcall_entry_t __initcall3_start[];
+extern initcall_entry_t __initcall4_start[];
+extern initcall_entry_t __initcall5_start[];
+extern initcall_entry_t __initcall6_start[];
+extern initcall_entry_t __initcall7_start[];
+extern initcall_entry_t __initcall_end[];
+
+static initcall_entry_t *initcall_levels[] __initdata = {
        __initcall0_start,
        __initcall1_start,
        __initcall2_start,
@@ -939,7 +939,7 @@ static char *initcall_level_names[] __initdata = {
 
 static void __init do_initcall_level(int level)
 {
-       initcall_t *fn;
+       initcall_entry_t *fn;
 
        strcpy(initcall_command_line, saved_command_line);
        parse_args(initcall_level_names[level],
@@ -950,7 +950,7 @@ static void __init do_initcall_level(int level)
 
        trace_initcall_level(initcall_level_names[level]);
        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
-               do_one_initcall(*fn);
+               do_one_initcall(initcall_from_entry(fn));
 }
 
 static void __init do_initcalls(void)
@@ -981,11 +981,11 @@ static void __init do_basic_setup(void)
 
 static void __init do_pre_smp_initcalls(void)
 {
-       initcall_t *fn;
+       initcall_entry_t *fn;
 
        trace_initcall_level("early");
        for (fn = __initcall_start; fn < __initcall0_start; fn++)
-               do_one_initcall(*fn);
+               do_one_initcall(initcall_from_entry(fn));
 }
 
 /*
@@ -1002,6 +1002,7 @@ void __init load_default_modules(void)
 static int run_init_process(const char *init_filename)
 {
        argv_init[0] = init_filename;
+       pr_info("Run %s as init process\n", init_filename);
        return do_execve(getname_kernel(init_filename),
                (const char __user *const __user *)argv_init,
                (const char __user *const __user *)envp_init);
index 203281198079c660c18f9cabf8b9b61c26caf7d4..883642cf2b2767ae7c05b9eb19841d5f16c230ca 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -163,7 +163,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
        /* ipc_addid() locks msq upon success. */
        retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
        if (retval < 0) {
-               call_rcu(&msq->q_perm.rcu, msg_rcu_free);
+               ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
                return retval;
        }
 
@@ -386,7 +386,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
        down_write(&msg_ids(ns).rwsem);
        rcu_read_lock();
 
-       ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
+       ipcp = ipcctl_obtain_check(ns, &msg_ids(ns), msqid, cmd,
                                      &msqid64->msg_perm, msqid64->msg_qbytes);
        if (IS_ERR(ipcp)) {
                err = PTR_ERR(ipcp);
@@ -456,7 +456,7 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
                         int cmd, struct msginfo *msginfo)
 {
        int err;
-       int max_id;
+       int max_idx;
 
        /*
         * We must not return kernel stack data.
@@ -483,16 +483,15 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
                msginfo->msgpool = MSGPOOL;
                msginfo->msgtql = MSGTQL;
        }
-       max_id = ipc_get_maxid(&msg_ids(ns));
+       max_idx = ipc_get_maxidx(&msg_ids(ns));
        up_read(&msg_ids(ns).rwsem);
-       return (max_id < 0) ? 0 : max_id;
+       return (max_idx < 0) ? 0 : max_idx;
 }
 
 static int msgctl_stat(struct ipc_namespace *ns, int msqid,
                         int cmd, struct msqid64_ds *p)
 {
        struct msg_queue *msq;
-       int id = 0;
        int err;
 
        memset(p, 0, sizeof(*p));
@@ -504,7 +503,6 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
                        err = PTR_ERR(msq);
                        goto out_unlock;
                }
-               id = msq->q_perm.id;
        } else { /* IPC_STAT */
                msq = msq_obtain_object_check(ns, msqid);
                if (IS_ERR(msq)) {
@@ -549,10 +547,21 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
        p->msg_lspid  = pid_vnr(msq->q_lspid);
        p->msg_lrpid  = pid_vnr(msq->q_lrpid);
 
-       ipc_unlock_object(&msq->q_perm);
-       rcu_read_unlock();
-       return id;
+       if (cmd == IPC_STAT) {
+               /*
+                * As defined in SUS:
+                * Return 0 on success
+                */
+               err = 0;
+       } else {
+               /*
+                * MSG_STAT and MSG_STAT_ANY (both Linux specific)
+                * Return the full id, including the sequence number
+                */
+               err = msq->q_perm.id;
+       }
 
+       ipc_unlock_object(&msq->q_perm);
 out_unlock:
        rcu_read_unlock();
        return err;
@@ -1229,7 +1238,7 @@ COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
 }
 #endif
 
-int msg_init_ns(struct ipc_namespace *ns)
+void msg_init_ns(struct ipc_namespace *ns)
 {
        ns->msg_ctlmax = MSGMAX;
        ns->msg_ctlmnb = MSGMNB;
@@ -1237,7 +1246,7 @@ int msg_init_ns(struct ipc_namespace *ns)
 
        atomic_set(&ns->msg_bytes, 0);
        atomic_set(&ns->msg_hdrs, 0);
-       return ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
+       ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
 }
 
 #ifdef CONFIG_IPC_NS
@@ -1278,12 +1287,11 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
 }
 #endif
 
-int __init msg_init(void)
+void __init msg_init(void)
 {
-       const int err = msg_init_ns(&init_ipc_ns);
+       msg_init_ns(&init_ipc_ns);
 
        ipc_init_proc_interface("sysvipc/msg",
                                "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
                                IPC_MSG_IDS, sysvipc_msg_proc_show);
-       return err;
 }
index f59a89966f923bc1c782504f708969c1e232a806..21607791d62c800a80275770ea7e7d175bfbc866 100644 (file)
@@ -55,28 +55,16 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
        ns->user_ns = get_user_ns(user_ns);
        ns->ucounts = ucounts;
 
-       err = sem_init_ns(ns);
+       err = mq_init_ns(ns);
        if (err)
                goto fail_put;
-       err = msg_init_ns(ns);
-       if (err)
-               goto fail_destroy_sem;
-       err = shm_init_ns(ns);
-       if (err)
-               goto fail_destroy_msg;
 
-       err = mq_init_ns(ns);
-       if (err)
-               goto fail_destroy_shm;
+       sem_init_ns(ns);
+       msg_init_ns(ns);
+       shm_init_ns(ns);
 
        return ns;
 
-fail_destroy_shm:
-       shm_exit_ns(ns);
-fail_destroy_msg:
-       msg_exit_ns(ns);
-fail_destroy_sem:
-       sem_exit_ns(ns);
 fail_put:
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
index 00ef2f743a628e0c11d33ed64da2295f9c2441ca..26f8e37fcdcbcf428e8f03396625272fae763023 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -221,14 +221,14 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
 #define sc_semopm      sem_ctls[2]
 #define sc_semmni      sem_ctls[3]
 
-int sem_init_ns(struct ipc_namespace *ns)
+void sem_init_ns(struct ipc_namespace *ns)
 {
        ns->sc_semmsl = SEMMSL;
        ns->sc_semmns = SEMMNS;
        ns->sc_semopm = SEMOPM;
        ns->sc_semmni = SEMMNI;
        ns->used_sems = 0;
-       return ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
+       ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
 }
 
 #ifdef CONFIG_IPC_NS
@@ -240,14 +240,12 @@ void sem_exit_ns(struct ipc_namespace *ns)
 }
 #endif
 
-int __init sem_init(void)
+void __init sem_init(void)
 {
-       const int err = sem_init_ns(&init_ipc_ns);
-
+       sem_init_ns(&init_ipc_ns);
        ipc_init_proc_interface("sysvipc/sem",
                                "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
                                IPC_SEM_IDS, sysvipc_sem_proc_show);
-       return err;
 }
 
 /**
@@ -557,7 +555,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        /* ipc_addid() locks sma upon success. */
        retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
        if (retval < 0) {
-               call_rcu(&sma->sem_perm.rcu, sem_rcu_free);
+               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                return retval;
        }
        ns->used_sems += nsems;
@@ -1223,7 +1221,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
 {
        struct sem_array *sma;
        time64_t semotime;
-       int id = 0;
        int err;
 
        memset(semid64, 0, sizeof(*semid64));
@@ -1235,7 +1232,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
                        err = PTR_ERR(sma);
                        goto out_unlock;
                }
-               id = sma->sem_perm.id;
        } else { /* IPC_STAT */
                sma = sem_obtain_object_check(ns, semid);
                if (IS_ERR(sma)) {
@@ -1275,10 +1271,20 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
 #endif
        semid64->sem_nsems = sma->sem_nsems;
 
+       if (cmd == IPC_STAT) {
+               /*
+                * As defined in SUS:
+                * Return 0 on success
+                */
+               err = 0;
+       } else {
+               /*
+                * SEM_STAT and SEM_STAT_ANY (both Linux specific)
+                * Return the full id, including the sequence number
+                */
+               err = sma->sem_perm.id;
+       }
        ipc_unlock_object(&sma->sem_perm);
-       rcu_read_unlock();
-       return id;
-
 out_unlock:
        rcu_read_unlock();
        return err;
@@ -1288,7 +1294,7 @@ static int semctl_info(struct ipc_namespace *ns, int semid,
                         int cmd, void __user *p)
 {
        struct seminfo seminfo;
-       int max_id;
+       int max_idx;
        int err;
 
        err = security_sem_semctl(NULL, cmd);
@@ -1312,11 +1318,11 @@ static int semctl_info(struct ipc_namespace *ns, int semid,
                seminfo.semusz = SEMUSZ;
                seminfo.semaem = SEMAEM;
        }
-       max_id = ipc_get_maxid(&sem_ids(ns));
+       max_idx = ipc_get_maxidx(&sem_ids(ns));
        up_read(&sem_ids(ns).rwsem);
        if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
                return -EFAULT;
-       return (max_id < 0) ? 0 : max_id;
+       return (max_idx < 0) ? 0 : max_idx;
 }
 
 static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
@@ -1588,7 +1594,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
        down_write(&sem_ids(ns).rwsem);
        rcu_read_lock();
 
-       ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
+       ipcp = ipcctl_obtain_check(ns, &sem_ids(ns), semid, cmd,
                                      &semid64->sem_perm, 0);
        if (IS_ERR(ipcp)) {
                err = PTR_ERR(ipcp);
index b204feb3827402c7655aeef27bd655b0f426a011..b0eb3757ab895d07970bec60b55f9bd895f7bd8a 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -96,14 +96,14 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp);
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
 
-int shm_init_ns(struct ipc_namespace *ns)
+void shm_init_ns(struct ipc_namespace *ns)
 {
        ns->shm_ctlmax = SHMMAX;
        ns->shm_ctlall = SHMALL;
        ns->shm_ctlmni = SHMMNI;
        ns->shm_rmid_forced = 0;
        ns->shm_tot = 0;
-       return ipc_init_ids(&shm_ids(ns));
+       ipc_init_ids(&shm_ids(ns));
 }
 
 /*
@@ -136,9 +136,8 @@ void shm_exit_ns(struct ipc_namespace *ns)
 
 static int __init ipc_ns_init(void)
 {
-       const int err = shm_init_ns(&init_ipc_ns);
-       WARN(err, "ipc: sysv shm_init_ns failed: %d\n", err);
-       return err;
+       shm_init_ns(&init_ipc_ns);
+       return 0;
 }
 
 pure_initcall(ipc_ns_init);
@@ -180,16 +179,33 @@ static inline struct shmid_kernel *shm_obtain_object_check(struct ipc_namespace
  */
 static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 {
-       struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
+       struct kern_ipc_perm *ipcp;
+
+       rcu_read_lock();
+       ipcp = ipc_obtain_object_idr(&shm_ids(ns), id);
+       if (IS_ERR(ipcp))
+               goto err;
 
+       ipc_lock_object(ipcp);
+       /*
+        * ipc_rmid() may have already freed the ID while ipc_lock_object()
+        * was spinning: here verify that the structure is still valid.
+        * Upon races with RMID, return -EIDRM, thus indicating that
+        * the ID points to a removed identifier.
+        */
+       if (ipc_valid_object(ipcp)) {
+               /* return a locked ipc object upon success */
+               return container_of(ipcp, struct shmid_kernel, shm_perm);
+       }
+
+       ipc_unlock_object(ipcp);
+err:
+       rcu_read_unlock();
        /*
         * Callers of shm_lock() must validate the status of the returned ipc
-        * object pointer (as returned by ipc_lock()), and error out as
-        * appropriate.
+        * object pointer and error out as appropriate.
         */
-       if (IS_ERR(ipcp))
-               return (void *)ipcp;
-       return container_of(ipcp, struct shmid_kernel, shm_perm);
+       return (void *)ipcp;
 }
 
 static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
@@ -684,6 +700,8 @@ no_id:
        if (is_file_hugepages(file) && shp->mlock_user)
                user_shm_unlock(size, shp->mlock_user);
        fput(file);
+       ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
+       return error;
 no_file:
        call_rcu(&shp->shm_perm.rcu, shm_rcu_free);
        return error;
@@ -879,7 +897,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
        down_write(&shm_ids(ns).rwsem);
        rcu_read_lock();
 
-       ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
+       ipcp = ipcctl_obtain_check(ns, &shm_ids(ns), shmid, cmd,
                                      &shmid64->shm_perm, 0);
        if (IS_ERR(ipcp)) {
                err = PTR_ERR(ipcp);
@@ -930,7 +948,7 @@ static int shmctl_ipc_info(struct ipc_namespace *ns,
                shminfo->shmall = ns->shm_ctlall;
                shminfo->shmmin = SHMMIN;
                down_read(&shm_ids(ns).rwsem);
-               err = ipc_get_maxid(&shm_ids(ns));
+               err = ipc_get_maxidx(&shm_ids(ns));
                up_read(&shm_ids(ns).rwsem);
                if (err < 0)
                        err = 0;
@@ -950,7 +968,7 @@ static int shmctl_shm_info(struct ipc_namespace *ns,
                shm_info->shm_tot = ns->shm_tot;
                shm_info->swap_attempts = 0;
                shm_info->swap_successes = 0;
-               err = ipc_get_maxid(&shm_ids(ns));
+               err = ipc_get_maxidx(&shm_ids(ns));
                up_read(&shm_ids(ns).rwsem);
                if (err < 0)
                        err = 0;
@@ -962,7 +980,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
                        int cmd, struct shmid64_ds *tbuf)
 {
        struct shmid_kernel *shp;
-       int id = 0;
        int err;
 
        memset(tbuf, 0, sizeof(*tbuf));
@@ -974,7 +991,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
                        err = PTR_ERR(shp);
                        goto out_unlock;
                }
-               id = shp->shm_perm.id;
        } else { /* IPC_STAT */
                shp = shm_obtain_object_check(ns, shmid);
                if (IS_ERR(shp)) {
@@ -1024,10 +1040,21 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
        tbuf->shm_lpid  = pid_vnr(shp->shm_lprid);
        tbuf->shm_nattch = shp->shm_nattch;
 
-       ipc_unlock_object(&shp->shm_perm);
-       rcu_read_unlock();
-       return id;
+       if (cmd == IPC_STAT) {
+               /*
+                * As defined in SUS:
+                * Return 0 on success
+                */
+               err = 0;
+       } else {
+               /*
+                * SHM_STAT and SHM_STAT_ANY (both Linux specific)
+                * Return the full id, including the sequence number
+                */
+               err = shp->shm_perm.id;
+       }
 
+       ipc_unlock_object(&shp->shm_perm);
 out_unlock:
        rcu_read_unlock();
        return err;
index fdffff41f65b546f66a5ee9b69297b39c445b8a0..0af05752969f1bc4641a591d717edd1b46a18b5a 100644 (file)
@@ -88,16 +88,12 @@ struct ipc_proc_iface {
  */
 static int __init ipc_init(void)
 {
-       int err_sem, err_msg;
-
        proc_mkdir("sysvipc", NULL);
-       err_sem = sem_init();
-       WARN(err_sem, "ipc: sysv sem_init failed: %d\n", err_sem);
-       err_msg = msg_init();
-       WARN(err_msg, "ipc: sysv msg_init failed: %d\n", err_msg);
+       sem_init();
+       msg_init();
        shm_init();
 
-       return err_msg ? err_msg : err_sem;
+       return 0;
 }
 device_initcall(ipc_init);
 
@@ -116,22 +112,17 @@ static const struct rhashtable_params ipc_kht_params = {
  * Set up the sequence range to use for the ipc identifier range (limited
  * below IPCMNI) then initialise the keys hashtable and ids idr.
  */
-int ipc_init_ids(struct ipc_ids *ids)
+void ipc_init_ids(struct ipc_ids *ids)
 {
-       int err;
        ids->in_use = 0;
        ids->seq = 0;
        init_rwsem(&ids->rwsem);
-       err = rhashtable_init(&ids->key_ht, &ipc_kht_params);
-       if (err)
-               return err;
+       rhashtable_init(&ids->key_ht, &ipc_kht_params);
        idr_init(&ids->ipcs_idr);
-       ids->tables_initialized = true;
-       ids->max_id = -1;
+       ids->max_idx = -1;
 #ifdef CONFIG_CHECKPOINT_RESTORE
        ids->next_id = -1;
 #endif
-       return 0;
 }
 
 #ifdef CONFIG_PROC_FS
@@ -179,61 +170,66 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
  */
 static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
 {
-       struct kern_ipc_perm *ipcp = NULL;
+       struct kern_ipc_perm *ipcp;
 
-       if (likely(ids->tables_initialized))
-               ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
+       ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
                                              ipc_kht_params);
+       if (!ipcp)
+               return NULL;
 
-       if (ipcp) {
-               rcu_read_lock();
-               ipc_lock_object(ipcp);
-               return ipcp;
-       }
-
-       return NULL;
+       rcu_read_lock();
+       ipc_lock_object(ipcp);
+       return ipcp;
 }
 
-#ifdef CONFIG_CHECKPOINT_RESTORE
 /*
- * Specify desired id for next allocated IPC object.
+ * Insert new IPC object into idr tree, and set sequence number and id
+ * in the correct order.
+ * Especially:
+ * - the sequence number must be set before inserting the object into the idr,
+ *   because the sequence number is accessed without a lock.
+ * - the id can/must be set after inserting the object into the idr.
+ *   All accesses must be done after getting kern_ipc_perm.lock.
+ *
+ * The caller must own kern_ipc_perm.lock.of the new object.
+ * On error, the function returns a (negative) error code.
  */
-#define ipc_idr_alloc(ids, new)                                                \
-       idr_alloc(&(ids)->ipcs_idr, (new),                              \
-                 (ids)->next_id < 0 ? 0 : ipcid_to_idx((ids)->next_id),\
-                 0, GFP_NOWAIT)
-
-static inline int ipc_buildid(int id, struct ipc_ids *ids,
-                             struct kern_ipc_perm *new)
+static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
 {
-       if (ids->next_id < 0) { /* default, behave as !CHECKPOINT_RESTORE */
+       int idx, next_id = -1;
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       next_id = ids->next_id;
+       ids->next_id = -1;
+#endif
+
+       /*
+        * As soon as a new object is inserted into the idr,
+        * ipc_obtain_object_idr() or ipc_obtain_object_check() can find it,
+        * and the lockless preparations for ipc operations can start.
+        * This means especially: permission checks, audit calls, allocation
+        * of undo structures, ...
+        *
+        * Thus the object must be fully initialized, and if something fails,
+        * then the full tear-down sequence must be followed.
+        * (i.e.: set new->deleted, reduce refcount, call_rcu())
+        */
+
+       if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */
                new->seq = ids->seq++;
                if (ids->seq > IPCID_SEQ_MAX)
                        ids->seq = 0;
+               idx = idr_alloc(&ids->ipcs_idr, new, 0, 0, GFP_NOWAIT);
        } else {
-               new->seq = ipcid_to_seqx(ids->next_id);
-               ids->next_id = -1;
+               new->seq = ipcid_to_seqx(next_id);
+               idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id),
+                               0, GFP_NOWAIT);
        }
-
-       return SEQ_MULTIPLIER * new->seq + id;
+       if (idx >= 0)
+               new->id = SEQ_MULTIPLIER * new->seq + idx;
+       return idx;
 }
 
-#else
-#define ipc_idr_alloc(ids, new)                                        \
-       idr_alloc(&(ids)->ipcs_idr, (new), 0, 0, GFP_NOWAIT)
-
-static inline int ipc_buildid(int id, struct ipc_ids *ids,
-                             struct kern_ipc_perm *new)
-{
-       new->seq = ids->seq++;
-       if (ids->seq > IPCID_SEQ_MAX)
-               ids->seq = 0;
-
-       return SEQ_MULTIPLIER * new->seq + id;
-}
-
-#endif /* CONFIG_CHECKPOINT_RESTORE */
-
 /**
  * ipc_addid - add an ipc identifier
  * @ids: ipc identifier set
@@ -241,9 +237,11 @@ static inline int ipc_buildid(int id, struct ipc_ids *ids,
  * @limit: limit for the number of used ids
  *
  * Add an entry 'new' to the ipc ids idr. The permissions object is
- * initialised and the first free entry is set up and the id assigned
+ * initialised and the first free entry is set up and the index assigned
  * is returned. The 'new' entry is returned in a locked state on success.
+ *
  * On failure the entry is not locked and a negative err-code is returned.
+ * The caller must use ipc_rcu_putref() to free the identifier.
  *
  * Called with writer ipc_ids.rwsem held.
  */
@@ -251,19 +249,20 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
 {
        kuid_t euid;
        kgid_t egid;
-       int id, err;
+       int idx, err;
+
+       /* 1) Initialize the refcount so that ipc_rcu_putref works */
+       refcount_set(&new->refcount, 1);
 
        if (limit > IPCMNI)
                limit = IPCMNI;
 
-       if (!ids->tables_initialized || ids->in_use >= limit)
+       if (ids->in_use >= limit)
                return -ENOSPC;
 
        idr_preload(GFP_KERNEL);
 
-       refcount_set(&new->refcount, 1);
        spin_lock_init(&new->lock);
-       new->deleted = false;
        rcu_read_lock();
        spin_lock(&new->lock);
 
@@ -271,30 +270,30 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
        new->cuid = new->uid = euid;
        new->gid = new->cgid = egid;
 
-       id = ipc_idr_alloc(ids, new);
+       new->deleted = false;
+
+       idx = ipc_idr_alloc(ids, new);
        idr_preload_end();
 
-       if (id >= 0 && new->key != IPC_PRIVATE) {
+       if (idx >= 0 && new->key != IPC_PRIVATE) {
                err = rhashtable_insert_fast(&ids->key_ht, &new->khtnode,
                                             ipc_kht_params);
                if (err < 0) {
-                       idr_remove(&ids->ipcs_idr, id);
-                       id = err;
+                       idr_remove(&ids->ipcs_idr, idx);
+                       idx = err;
                }
        }
-       if (id < 0) {
+       if (idx < 0) {
+               new->deleted = true;
                spin_unlock(&new->lock);
                rcu_read_unlock();
-               return id;
+               return idx;
        }
 
        ids->in_use++;
-       if (id > ids->max_id)
-               ids->max_id = id;
-
-       new->id = ipc_buildid(id, ids, new);
-
-       return id;
+       if (idx > ids->max_idx)
+               ids->max_idx = idx;
+       return idx;
 }
 
 /**
@@ -432,20 +431,20 @@ static void ipc_kht_remove(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
  */
 void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
 {
-       int lid = ipcid_to_idx(ipcp->id);
+       int idx = ipcid_to_idx(ipcp->id);
 
-       idr_remove(&ids->ipcs_idr, lid);
+       idr_remove(&ids->ipcs_idr, idx);
        ipc_kht_remove(ids, ipcp);
        ids->in_use--;
        ipcp->deleted = true;
 
-       if (unlikely(lid == ids->max_id)) {
+       if (unlikely(idx == ids->max_idx)) {
                do {
-                       lid--;
-                       if (lid == -1)
+                       idx--;
+                       if (idx == -1)
                                break;
-               } while (!idr_find(&ids->ipcs_idr, lid));
-               ids->max_id = lid;
+               } while (!idr_find(&ids->ipcs_idr, idx));
+               ids->max_idx = idx;
        }
 }
 
@@ -463,7 +462,7 @@ void ipc_set_key_private(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
        ipcp->key = IPC_PRIVATE;
 }
 
-int ipc_rcu_getref(struct kern_ipc_perm *ptr)
+bool ipc_rcu_getref(struct kern_ipc_perm *ptr)
 {
        return refcount_inc_not_zero(&ptr->refcount);
 }
@@ -565,61 +564,22 @@ void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out)
 struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id)
 {
        struct kern_ipc_perm *out;
-       int lid = ipcid_to_idx(id);
-
-       if (unlikely(!ids->tables_initialized))
-               return ERR_PTR(-EINVAL);
+       int idx = ipcid_to_idx(id);
 
-       out = idr_find(&ids->ipcs_idr, lid);
+       out = idr_find(&ids->ipcs_idr, idx);
        if (!out)
                return ERR_PTR(-EINVAL);
 
        return out;
 }
 
-/**
- * ipc_lock - lock an ipc structure without rwsem held
- * @ids: ipc identifier set
- * @id: ipc id to look for
- *
- * Look for an id in the ipc ids idr and lock the associated ipc object.
- *
- * The ipc object is locked on successful exit.
- */
-struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
-{
-       struct kern_ipc_perm *out;
-
-       rcu_read_lock();
-       out = ipc_obtain_object_idr(ids, id);
-       if (IS_ERR(out))
-               goto err;
-
-       spin_lock(&out->lock);
-
-       /*
-        * ipc_rmid() may have already freed the ID while ipc_lock()
-        * was spinning: here verify that the structure is still valid.
-        * Upon races with RMID, return -EIDRM, thus indicating that
-        * the ID points to a removed identifier.
-        */
-       if (ipc_valid_object(out))
-               return out;
-
-       spin_unlock(&out->lock);
-       out = ERR_PTR(-EIDRM);
-err:
-       rcu_read_unlock();
-       return out;
-}
-
 /**
  * ipc_obtain_object_check
  * @ids: ipc identifier set
  * @id: ipc id to look for
  *
- * Similar to ipc_obtain_object_idr() but also checks
- * the ipc object reference counter.
+ * Similar to ipc_obtain_object_idr() but also checks the ipc object
+ * sequence number.
  *
  * Call inside the RCU critical section.
  * The ipc object is *not* locked on exit.
@@ -677,7 +637,7 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 }
 
 /**
- * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd
+ * ipcctl_obtain_check - retrieve an ipc object and check permissions
  * @ns:  ipc namespace
  * @ids:  the table of ids where to look for the ipc
  * @id:   the id of the ipc to retrieve
@@ -687,16 +647,16 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
  *
  * This function does some common audit and permissions check for some IPC_XXX
  * cmd and is called from semctl_down, shmctl_down and msgctl_down.
- * It must be called without any lock held and:
  *
- *   - retrieves the ipc with the given id in the given table.
+ * It:
+ *   - retrieves the ipc object with the given id in the given table.
  *   - performs some audit and permission check, depending on the given cmd
  *   - returns a pointer to the ipc object or otherwise, the corresponding
  *     error.
  *
  * Call holding the both the rwsem and the rcu read lock.
  */
-struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
                                        struct ipc_ids *ids, int id, int cmd,
                                        struct ipc64_perm *perm, int extra_perm)
 {
index 0aba3230d0070ca45285e5075154a352030b59fb..0a159f69b3bbeb82440268a263c33be8d0dc71dd 100644 (file)
@@ -18,8 +18,8 @@
 #define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
 #define SEQ_MULTIPLIER (IPCMNI)
 
-int sem_init(void);
-int msg_init(void);
+void sem_init(void);
+void msg_init(void);
 void shm_init(void);
 
 struct ipc_namespace;
@@ -34,17 +34,17 @@ static inline void mq_put_mnt(struct ipc_namespace *ns) { }
 #endif
 
 #ifdef CONFIG_SYSVIPC
-int sem_init_ns(struct ipc_namespace *ns);
-int msg_init_ns(struct ipc_namespace *ns);
-int shm_init_ns(struct ipc_namespace *ns);
+void sem_init_ns(struct ipc_namespace *ns);
+void msg_init_ns(struct ipc_namespace *ns);
+void shm_init_ns(struct ipc_namespace *ns);
 
 void sem_exit_ns(struct ipc_namespace *ns);
 void msg_exit_ns(struct ipc_namespace *ns);
 void shm_exit_ns(struct ipc_namespace *ns);
 #else
-static inline int sem_init_ns(struct ipc_namespace *ns) { return 0; }
-static inline int msg_init_ns(struct ipc_namespace *ns) { return 0; }
-static inline int shm_init_ns(struct ipc_namespace *ns) { return 0; }
+static inline void sem_init_ns(struct ipc_namespace *ns) { }
+static inline void msg_init_ns(struct ipc_namespace *ns) { }
+static inline void shm_init_ns(struct ipc_namespace *ns) { }
 
 static inline void sem_exit_ns(struct ipc_namespace *ns) { }
 static inline void msg_exit_ns(struct ipc_namespace *ns) { }
@@ -83,7 +83,7 @@ struct ipc_ops {
 struct seq_file;
 struct ipc_ids;
 
-int ipc_init_ids(struct ipc_ids *);
+void ipc_init_ids(struct ipc_ids *ids);
 #ifdef CONFIG_PROC_FS
 void __init ipc_init_proc_interface(const char *path, const char *header,
                int ids, int (*show)(struct seq_file *, void *));
@@ -113,12 +113,12 @@ void ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *);
 int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
 
 /**
- * ipc_get_maxid - get the last assigned id
+ * ipc_get_maxidx - get the highest assigned index
  * @ids: ipc identifier set
  *
  * Called with ipc_ids.rwsem held for reading.
  */
-static inline int ipc_get_maxid(struct ipc_ids *ids)
+static inline int ipc_get_maxidx(struct ipc_ids *ids)
 {
        if (ids->in_use == 0)
                return -1;
@@ -126,7 +126,7 @@ static inline int ipc_get_maxid(struct ipc_ids *ids)
        if (ids->in_use == IPCMNI)
                return IPCMNI - 1;
 
-       return ids->max_id;
+       return ids->max_idx;
 }
 
 /*
@@ -138,17 +138,16 @@ static inline int ipc_get_maxid(struct ipc_ids *ids)
  * refcount is initialized by ipc_addid(), before that point call_rcu()
  * must be used.
  */
-int ipc_rcu_getref(struct kern_ipc_perm *ptr);
+bool ipc_rcu_getref(struct kern_ipc_perm *ptr);
 void ipc_rcu_putref(struct kern_ipc_perm *ptr,
                        void (*func)(struct rcu_head *head));
 
-struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
 struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
 
 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
 int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
-struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
                                             struct ipc_ids *ids, int id, int cmd,
                                             struct ipc64_perm *perm, int extra_perm);
 
@@ -173,9 +172,9 @@ extern struct msg_msg *load_msg(const void __user *src, size_t len);
 extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
 extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);
 
-static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid)
+static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int id)
 {
-       return uid / SEQ_MULTIPLIER != ipcp->seq;
+       return ipcid_to_seqx(id) != ipcp->seq;
 }
 
 static inline void ipc_lock_object(struct kern_ipc_perm *perm)
index b66aced5e8c2e3479efe16df7cdfc73044d4e77b..933cb3e45b987df1ba52d7fa4afc312823d3d745 100644 (file)
@@ -14,8 +14,8 @@
 #include <asm/sections.h>
 
 /* vmcoreinfo stuff */
-static unsigned char *vmcoreinfo_data;
-static size_t vmcoreinfo_size;
+unsigned char *vmcoreinfo_data;
+size_t vmcoreinfo_size;
 u32 *vmcoreinfo_note;
 
 /* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
@@ -344,7 +344,7 @@ void crash_save_vmcoreinfo(void)
        if (vmcoreinfo_data_safecopy)
                vmcoreinfo_data = vmcoreinfo_data_safecopy;
 
-       vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds());
+       vmcoreinfo_append_str("CRASHTIME=%lld\n", ktime_get_real_seconds());
        update_vmcoreinfo_note();
 }
 
@@ -401,7 +401,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_SYMBOL(init_uts_ns);
        VMCOREINFO_SYMBOL(node_online_map);
 #ifdef CONFIG_MMU
-       VMCOREINFO_SYMBOL(swapper_pg_dir);
+       VMCOREINFO_SYMBOL_ARRAY(swapper_pg_dir);
 #endif
        VMCOREINFO_SYMBOL(_stext);
        VMCOREINFO_SYMBOL(vmap_area_list);
index ff5037be7771709d12cf75362feb2431a765c9d8..d896e9ca38b0cccc5de00a0564ecd22179fa2c06 100644 (file)
@@ -310,8 +310,9 @@ static struct kmem_cache *mm_cachep;
 
 struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
 {
-       struct vm_area_struct *vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+       struct vm_area_struct *vma;
 
+       vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
        if (vma)
                vma_init(vma, mm);
        return vma;
@@ -1301,6 +1302,7 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
        tsk->nvcsw = tsk->nivcsw = 0;
 #ifdef CONFIG_DETECT_HUNG_TASK
        tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw;
+       tsk->last_switch_time = 0;
 #endif
 
        tsk->mm = NULL;
@@ -1425,7 +1427,9 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
                return -ENOMEM;
 
        atomic_set(&sig->count, 1);
+       spin_lock_irq(&current->sighand->siglock);
        memcpy(sig->action, current->sighand->action, sizeof(sig->action));
+       spin_unlock_irq(&current->sighand->siglock);
        return 0;
 }
 
index 32b479468e4d50d69530ad766ba7e3897afa5cc3..b9132d1269ef1967950a804f7e21f3922cb491c8 100644 (file)
@@ -40,6 +40,11 @@ int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
  */
 unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
 
+/*
+ * Zero (default value) means use sysctl_hung_task_timeout_secs:
+ */
+unsigned long __read_mostly sysctl_hung_task_check_interval_secs;
+
 int __read_mostly sysctl_hung_task_warnings = 10;
 
 static int __read_mostly did_panic;
@@ -98,8 +103,11 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
 
        if (switch_count != t->last_switch_count) {
                t->last_switch_count = switch_count;
+               t->last_switch_time = jiffies;
                return;
        }
+       if (time_is_after_jiffies(t->last_switch_time + timeout * HZ))
+               return;
 
        trace_sched_process_hang(t);
 
@@ -245,8 +253,13 @@ static int watchdog(void *dummy)
 
        for ( ; ; ) {
                unsigned long timeout = sysctl_hung_task_timeout_secs;
-               long t = hung_timeout_jiffies(hung_last_checked, timeout);
+               unsigned long interval = sysctl_hung_task_check_interval_secs;
+               long t;
 
+               if (interval == 0)
+                       interval = timeout;
+               interval = min_t(unsigned long, interval, timeout);
+               t = hung_timeout_jiffies(hung_last_checked, interval);
                if (t <= 0) {
                        if (!atomic_xchg(&reset_hung_task, 0))
                                check_hung_uninterruptible_tasks(timeout);
index b046a32520d83aeeed519a72ae61972b4cc9870c..6746c85511fefe40f335207245df81d3e246a0c8 100644 (file)
@@ -529,12 +529,30 @@ static bool check_symbol(const struct symsearch *syms,
        return true;
 }
 
+static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
+{
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+       return (unsigned long)offset_to_ptr(&sym->value_offset);
+#else
+       return sym->value;
+#endif
+}
+
+static const char *kernel_symbol_name(const struct kernel_symbol *sym)
+{
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+       return offset_to_ptr(&sym->name_offset);
+#else
+       return sym->name;
+#endif
+}
+
 static int cmp_name(const void *va, const void *vb)
 {
        const char *a;
        const struct kernel_symbol *b;
        a = va; b = vb;
-       return strcmp(a, b->name);
+       return strcmp(a, kernel_symbol_name(b));
 }
 
 static bool find_symbol_in_section(const struct symsearch *syms,
@@ -2170,7 +2188,7 @@ void *__symbol_get(const char *symbol)
                sym = NULL;
        preempt_enable();
 
-       return sym ? (void *)sym->value : NULL;
+       return sym ? (void *)kernel_symbol_value(sym) : NULL;
 }
 EXPORT_SYMBOL_GPL(__symbol_get);
 
@@ -2200,10 +2218,12 @@ static int verify_export_symbols(struct module *mod)
 
        for (i = 0; i < ARRAY_SIZE(arr); i++) {
                for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
-                       if (find_symbol(s->name, &owner, NULL, true, false)) {
+                       if (find_symbol(kernel_symbol_name(s), &owner, NULL,
+                                       true, false)) {
                                pr_err("%s: exports duplicate symbol %s"
                                       " (owned by %s)\n",
-                                      mod->name, s->name, module_name(owner));
+                                      mod->name, kernel_symbol_name(s),
+                                      module_name(owner));
                                return -ENOEXEC;
                        }
                }
@@ -2252,7 +2272,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
                        ksym = resolve_symbol_wait(mod, info, name);
                        /* Ok if resolved.  */
                        if (ksym && !IS_ERR(ksym)) {
-                               sym[i].st_value = ksym->value;
+                               sym[i].st_value = kernel_symbol_value(ksym);
                                break;
                        }
 
@@ -2516,7 +2536,7 @@ static int is_exported(const char *name, unsigned long value,
                ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
        else
                ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
-       return ks != NULL && ks->value == value;
+       return ks != NULL && kernel_symbol_value(ks) == value;
 }
 
 /* As per nm */
index 90b6ab01db59cadbaf6e92283e982cb3ae820289..918f386b2f6ea7619878c927272a6d3920631a4e 100644 (file)
@@ -2788,7 +2788,8 @@ EXPORT_SYMBOL(unregister_console);
 void __init console_init(void)
 {
        int ret;
-       initcall_t *call;
+       initcall_t call;
+       initcall_entry_t *ce;
 
        /* Setup the default TTY line discipline. */
        n_tty_init();
@@ -2797,13 +2798,14 @@ void __init console_init(void)
         * set up the console device so that later boot sequences can
         * inform about problems etc..
         */
-       call = __con_initcall_start;
+       ce = __con_initcall_start;
        trace_initcall_level("console");
-       while (call < __con_initcall_end) {
-               trace_initcall_start((*call));
-               ret = (*call)();
-               trace_initcall_finish((*call), ret);
-               call++;
+       while (ce < __con_initcall_end) {
+               call = initcall_from_entry(ce);
+               trace_initcall_start(call);
+               ret = call();
+               trace_initcall_finish(call, ret);
+               ce++;
        }
 }
 
index 870f97b313e3891003b30982603cf333a879d4a8..5dd47f1103d18bd769cace68b753088574e02f27 100644 (file)
@@ -69,6 +69,8 @@ static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
        wait_queue_entry_t *curr, *next;
        int cnt = 0;
 
+       lockdep_assert_held(&wq_head->lock);
+
        if (bookmark && (bookmark->flags & WQ_FLAG_BOOKMARK)) {
                curr = list_next_entry(bookmark, entry);
 
index cfa9d10e731ab663c7c932f6ea9257e349101d5e..5843c541fda9c30bb8e4165facc07a3df114f57b 100644 (file)
@@ -65,14 +65,14 @@ static void __user *sig_handler(struct task_struct *t, int sig)
        return t->sighand->action[sig - 1].sa.sa_handler;
 }
 
-static int sig_handler_ignored(void __user *handler, int sig)
+static inline bool sig_handler_ignored(void __user *handler, int sig)
 {
        /* Is it explicitly or implicitly ignored? */
        return handler == SIG_IGN ||
-               (handler == SIG_DFL && sig_kernel_ignore(sig));
+              (handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_task_ignored(struct task_struct *t, int sig, bool force)
+static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
 {
        void __user *handler;
 
@@ -80,12 +80,12 @@ static int sig_task_ignored(struct task_struct *t, int sig, bool force)
 
        if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
            handler == SIG_DFL && !(force && sig_kernel_only(sig)))
-               return 1;
+               return true;
 
        return sig_handler_ignored(handler, sig);
 }
 
-static int sig_ignored(struct task_struct *t, int sig, bool force)
+static bool sig_ignored(struct task_struct *t, int sig, bool force)
 {
        /*
         * Blocked signals are never ignored, since the
@@ -93,7 +93,7 @@ static int sig_ignored(struct task_struct *t, int sig, bool force)
         * unblocked.
         */
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
-               return 0;
+               return false;
 
        /*
         * Tracers may want to know about even ignored signal unless it
@@ -101,7 +101,7 @@ static int sig_ignored(struct task_struct *t, int sig, bool force)
         * by SIGNAL_UNKILLABLE task.
         */
        if (t->ptrace && sig != SIGKILL)
-               return 0;
+               return false;
 
        return sig_task_ignored(t, sig, force);
 }
@@ -110,7 +110,7 @@ static int sig_ignored(struct task_struct *t, int sig, bool force)
  * Re-calculate pending state from the set of locally pending
  * signals, globally pending signals, and blocked signals.
  */
-static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked)
+static inline bool has_pending_signals(sigset_t *signal, sigset_t *blocked)
 {
        unsigned long ready;
        long i;
@@ -138,20 +138,21 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked)
 
 #define PENDING(p,b) has_pending_signals(&(p)->signal, (b))
 
-static int recalc_sigpending_tsk(struct task_struct *t)
+static bool recalc_sigpending_tsk(struct task_struct *t)
 {
        if ((t->jobctl & JOBCTL_PENDING_MASK) ||
            PENDING(&t->pending, &t->blocked) ||
            PENDING(&t->signal->shared_pending, &t->blocked)) {
                set_tsk_thread_flag(t, TIF_SIGPENDING);
-               return 1;
+               return true;
        }
+
        /*
         * We must never clear the flag in another thread, or in current
         * when it's possible the current syscall is returning -ERESTART*.
         * So we don't clear it here, and only callers who know they should do.
         */
-       return 0;
+       return false;
 }
 
 /*
@@ -529,13 +530,15 @@ flush_signal_handlers(struct task_struct *t, int force_default)
        }
 }
 
-int unhandled_signal(struct task_struct *tsk, int sig)
+bool unhandled_signal(struct task_struct *tsk, int sig)
 {
        void __user *handler = tsk->sighand->action[sig-1].sa.sa_handler;
        if (is_global_init(tsk))
-               return 1;
+               return true;
+
        if (handler != SIG_IGN && handler != SIG_DFL)
-               return 0;
+               return false;
+
        /* if ptraced, let the tracer determine */
        return !tsk->ptrace;
 }
@@ -709,14 +712,14 @@ void signal_wake_up_state(struct task_struct *t, unsigned int state)
  *
  * All callers must be holding the siglock.
  */
-static int flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
+static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
 {
        struct sigqueue *q, *n;
        sigset_t m;
 
        sigandsets(&m, mask, &s->signal);
        if (sigisemptyset(&m))
-               return 0;
+               return;
 
        sigandnsets(&s->signal, &s->signal, mask);
        list_for_each_entry_safe(q, n, &s->list, list) {
@@ -725,7 +728,6 @@ static int flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
                        __sigqueue_free(q);
                }
        }
-       return 1;
 }
 
 static inline int is_si_special(const struct siginfo *info)
@@ -742,21 +744,16 @@ static inline bool si_fromuser(const struct siginfo *info)
 /*
  * called with RCU read lock from check_kill_permission()
  */
-static int kill_ok_by_cred(struct task_struct *t)
+static bool kill_ok_by_cred(struct task_struct *t)
 {
        const struct cred *cred = current_cred();
        const struct cred *tcred = __task_cred(t);
 
-       if (uid_eq(cred->euid, tcred->suid) ||
-           uid_eq(cred->euid, tcred->uid)  ||
-           uid_eq(cred->uid,  tcred->suid) ||
-           uid_eq(cred->uid,  tcred->uid))
-               return 1;
-
-       if (ns_capable(tcred->user_ns, CAP_KILL))
-               return 1;
-
-       return 0;
+       return uid_eq(cred->euid, tcred->suid) ||
+              uid_eq(cred->euid, tcred->uid) ||
+              uid_eq(cred->uid, tcred->suid) ||
+              uid_eq(cred->uid, tcred->uid) ||
+              ns_capable(tcred->user_ns, CAP_KILL);
 }
 
 /*
@@ -907,16 +904,20 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force)
  * as soon as they're available, so putting the signal on the shared queue
  * will be equivalent to sending it to one such thread.
  */
-static inline int wants_signal(int sig, struct task_struct *p)
+static inline bool wants_signal(int sig, struct task_struct *p)
 {
        if (sigismember(&p->blocked, sig))
-               return 0;
+               return false;
+
        if (p->flags & PF_EXITING)
-               return 0;
+               return false;
+
        if (sig == SIGKILL)
-               return 1;
+               return true;
+
        if (task_is_stopped_or_traced(p))
-               return 0;
+               return false;
+
        return task_curr(p) || !signal_pending(p);
 }
 
@@ -996,7 +997,7 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type)
        return;
 }
 
-static inline int legacy_queue(struct sigpending *signals, int sig)
+static inline bool legacy_queue(struct sigpending *signals, int sig)
 {
        return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
@@ -1380,14 +1381,15 @@ static int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
        return error;
 }
 
-static int kill_as_cred_perm(const struct cred *cred,
-                            struct task_struct *target)
+static inline bool kill_as_cred_perm(const struct cred *cred,
+                                    struct task_struct *target)
 {
        const struct cred *pcred = __task_cred(target);
-       if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) &&
-           !uid_eq(cred->uid,  pcred->suid) && !uid_eq(cred->uid,  pcred->uid))
-               return 0;
-       return 1;
+
+       return uid_eq(cred->euid, pcred->suid) ||
+              uid_eq(cred->euid, pcred->uid) ||
+              uid_eq(cred->uid, pcred->suid) ||
+              uid_eq(cred->uid, pcred->uid);
 }
 
 /* like kill_pid_info(), but doesn't use uid/euid of "current" */
@@ -1500,8 +1502,7 @@ send_sig(int sig, struct task_struct *p, int priv)
        return send_sig_info(sig, __si_special(priv), p);
 }
 
-void
-force_sig(int sig, struct task_struct *p)
+void force_sig(int sig, struct task_struct *p)
 {
        force_sig_info(sig, SEND_SIG_PRIV, p);
 }
@@ -1512,8 +1513,7 @@ force_sig(int sig, struct task_struct *p)
  * the problem was already a SIGSEGV, we'll want to
  * make sure we don't even try to deliver the signal..
  */
-int
-force_sigsegv(int sig, struct task_struct *p)
+void force_sigsegv(int sig, struct task_struct *p)
 {
        if (sig == SIGSEGV) {
                unsigned long flags;
@@ -1522,7 +1522,6 @@ force_sigsegv(int sig, struct task_struct *p)
                spin_unlock_irqrestore(&p->sighand->siglock, flags);
        }
        force_sig(SIGSEGV, p);
-       return 0;
 }
 
 int force_sig_fault(int sig, int code, void __user *addr
@@ -1923,10 +1922,10 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
        spin_unlock_irqrestore(&sighand->siglock, flags);
 }
 
-static inline int may_ptrace_stop(void)
+static inline bool may_ptrace_stop(void)
 {
        if (!likely(current->ptrace))
-               return 0;
+               return false;
        /*
         * Are we in the middle of do_coredump?
         * If so and our tracer is also part of the coredump stopping
@@ -1942,19 +1941,19 @@ static inline int may_ptrace_stop(void)
         */
        if (unlikely(current->mm->core_state) &&
            unlikely(current->mm == current->parent->mm))
-               return 0;
+               return false;
 
-       return 1;
+       return true;
 }
 
 /*
  * Return non-zero if there is a SIGKILL that should be waking us up.
  * Called with the siglock held.
  */
-static int sigkill_pending(struct task_struct *tsk)
+static bool sigkill_pending(struct task_struct *tsk)
 {
-       return  sigismember(&tsk->pending.signal, SIGKILL) ||
-               sigismember(&tsk->signal->shared_pending.signal, SIGKILL);
+       return sigismember(&tsk->pending.signal, SIGKILL) ||
+              sigismember(&tsk->signal->shared_pending.signal, SIGKILL);
 }
 
 /*
@@ -2334,7 +2333,7 @@ static int ptrace_signal(int signr, siginfo_t *info)
        return signr;
 }
 
-int get_signal(struct ksignal *ksig)
+bool get_signal(struct ksignal *ksig)
 {
        struct sighand_struct *sighand = current->sighand;
        struct signal_struct *signal = current->signal;
@@ -2344,7 +2343,7 @@ int get_signal(struct ksignal *ksig)
                task_work_run();
 
        if (unlikely(uprobe_deny_signal()))
-               return 0;
+               return false;
 
        /*
         * Do this once, we can't return to user-mode if freezing() == T.
@@ -2801,7 +2800,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset,
 }
 #endif
 
-static int do_sigpending(sigset_t *set)
+static void do_sigpending(sigset_t *set)
 {
        spin_lock_irq(&current->sighand->siglock);
        sigorsets(set, &current->pending.signal,
@@ -2810,7 +2809,6 @@ static int do_sigpending(sigset_t *set)
 
        /* Outside the lock because only this thread touches it.  */
        sigandsets(set, &current->blocked, set);
-       return 0;
 }
 
 /**
@@ -2822,15 +2820,16 @@ static int do_sigpending(sigset_t *set)
 SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize)
 {
        sigset_t set;
-       int err;
 
        if (sigsetsize > sizeof(*uset))
                return -EINVAL;
 
-       err = do_sigpending(&set);
-       if (!err && copy_to_user(uset, &set, sigsetsize))
-               err = -EFAULT;
-       return err;
+       do_sigpending(&set);
+
+       if (copy_to_user(uset, &set, sigsetsize))
+               return -EFAULT;
+
+       return 0;
 }
 
 #ifdef CONFIG_COMPAT
@@ -2838,15 +2837,13 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
                compat_size_t, sigsetsize)
 {
        sigset_t set;
-       int err;
 
        if (sigsetsize > sizeof(*uset))
                return -EINVAL;
 
-       err = do_sigpending(&set);
-       if (!err)
-               err = put_compat_sigset(uset, &set, sigsetsize);
-       return err;
+       do_sigpending(&set);
+
+       return put_compat_sigset(uset, &set, sigsetsize);
 }
 #endif
 
@@ -3608,25 +3605,26 @@ int __compat_save_altstack(compat_stack_t __user *uss, unsigned long sp)
 SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, uset)
 {
        sigset_t set;
-       int err;
 
        if (sizeof(old_sigset_t) > sizeof(*uset))
                return -EINVAL;
 
-       err = do_sigpending(&set);
-       if (!err && copy_to_user(uset, &set, sizeof(old_sigset_t)))
-               err = -EFAULT;
-       return err;
+       do_sigpending(&set);
+
+       if (copy_to_user(uset, &set, sizeof(old_sigset_t)))
+               return -EFAULT;
+
+       return 0;
 }
 
 #ifdef CONFIG_COMPAT
 COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32)
 {
        sigset_t set;
-       int err = do_sigpending(&set);
-       if (!err)
-               err = put_user(set.sig[0], set32);
-       return err;
+
+       do_sigpending(&set);
+
+       return put_user(set.sig[0], set32);
 }
 #endif
 
@@ -3697,25 +3695,23 @@ SYSCALL_DEFINE4(rt_sigaction, int, sig,
                size_t, sigsetsize)
 {
        struct k_sigaction new_sa, old_sa;
-       int ret = -EINVAL;
+       int ret;
 
        /* XXX: Don't preclude handling different sized sigset_t's.  */
        if (sigsetsize != sizeof(sigset_t))
-               goto out;
+               return -EINVAL;
 
-       if (act) {
-               if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa)))
-                       return -EFAULT;
-       }
+       if (act && copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa)))
+               return -EFAULT;
 
        ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
+       if (ret)
+               return ret;
 
-       if (!ret && oact) {
-               if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa)))
-                       return -EFAULT;
-       }
-out:
-       return ret;
+       if (oact && copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa)))
+               return -EFAULT;
+
+       return 0;
 }
 #ifdef CONFIG_COMPAT
 COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
index f22f76b7a138ceedcc5392a24f493ec04366bc1b..71ceb6c13c1a54030ed23e86e89da1079636d223 100644 (file)
@@ -145,7 +145,10 @@ static int minolduid;
 static int ngroups_max = NGROUPS_MAX;
 static const int cap_last_cap = CAP_LAST_CAP;
 
-/*this is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs */
+/*
+ * This is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs
+ * and hung_task_check_interval_secs
+ */
 #ifdef CONFIG_DETECT_HUNG_TASK
 static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
 #endif
@@ -222,7 +225,7 @@ static int proc_dopipe_max_size(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp, loff_t *ppos);
 
 #ifdef CONFIG_MAGIC_SYSRQ
-/* Note: sysrq code uses it's own private copy */
+/* Note: sysrq code uses its own private copy */
 static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
 
 static int sysrq_sysctl_handler(struct ctl_table *table, int write,
@@ -1090,6 +1093,14 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = proc_dohung_task_timeout_secs,
                .extra2         = &hung_task_timeout_max,
        },
+       {
+               .procname       = "hung_task_check_interval_secs",
+               .data           = &sysctl_hung_task_check_interval_secs,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = proc_dohung_task_timeout_secs,
+               .extra2         = &hung_task_timeout_max,
+       },
        {
                .procname       = "hung_task_warnings",
                .data           = &sysctl_hung_task_warnings,
@@ -1965,13 +1976,13 @@ static void warn_sysctl_write(struct ctl_table *table)
 }
 
 /**
- * proc_first_pos_non_zero_ignore - check if firs position is allowed
+ * proc_first_pos_non_zero_ignore - check if first position is allowed
  * @ppos: file position
  * @table: the sysctl table
  *
  * Returns true if the first position is non-zero and the sysctl_writes_strict
  * mode indicates this is not allowed for numeric input types. String proc
- * hadlers can ignore the return value.
+ * handlers can ignore the return value.
  */
 static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
                                           struct ctl_table *table)
index 96db841bf0fc89d1bea38ee7ccfb8faf909df420..bf2c06ef9afc3d5c2a5eecb620aa9acb07a7bba5 100644 (file)
@@ -371,6 +371,27 @@ int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data)
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
 
+static void for_each_tracepoint_range(struct tracepoint * const *begin,
+               struct tracepoint * const *end,
+               void (*fct)(struct tracepoint *tp, void *priv),
+               void *priv)
+{
+       if (!begin)
+               return;
+
+       if (IS_ENABLED(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)) {
+               const int *iter;
+
+               for (iter = (const int *)begin; iter < (const int *)end; iter++)
+                       fct(offset_to_ptr(iter), priv);
+       } else {
+               struct tracepoint * const *iter;
+
+               for (iter = begin; iter < end; iter++)
+                       fct(*iter, priv);
+       }
+}
+
 #ifdef CONFIG_MODULES
 bool trace_module_has_bad_taint(struct module *mod)
 {
@@ -435,15 +456,9 @@ EXPORT_SYMBOL_GPL(unregister_tracepoint_module_notifier);
  * Ensure the tracer unregistered the module's probes before the module
  * teardown is performed. Prevents leaks of probe and data pointers.
  */
-static void tp_module_going_check_quiescent(struct tracepoint * const *begin,
-               struct tracepoint * const *end)
+static void tp_module_going_check_quiescent(struct tracepoint *tp, void *priv)
 {
-       struct tracepoint * const *iter;
-
-       if (!begin)
-               return;
-       for (iter = begin; iter < end; iter++)
-               WARN_ON_ONCE((*iter)->funcs);
+       WARN_ON_ONCE(tp->funcs);
 }
 
 static int tracepoint_module_coming(struct module *mod)
@@ -494,8 +509,9 @@ static void tracepoint_module_going(struct module *mod)
                         * Called the going notifier before checking for
                         * quiescence.
                         */
-                       tp_module_going_check_quiescent(mod->tracepoints_ptrs,
-                               mod->tracepoints_ptrs + mod->num_tracepoints);
+                       for_each_tracepoint_range(mod->tracepoints_ptrs,
+                               mod->tracepoints_ptrs + mod->num_tracepoints,
+                               tp_module_going_check_quiescent, NULL);
                        break;
                }
        }
@@ -547,19 +563,6 @@ static __init int init_tracepoints(void)
 __initcall(init_tracepoints);
 #endif /* CONFIG_MODULES */
 
-static void for_each_tracepoint_range(struct tracepoint * const *begin,
-               struct tracepoint * const *end,
-               void (*fct)(struct tracepoint *tp, void *priv),
-               void *priv)
-{
-       struct tracepoint * const *iter;
-
-       if (!begin)
-               return;
-       for (iter = begin; iter < end; iter++)
-               fct(*iter, priv);
-}
-
 /**
  * for_each_kernel_tracepoint - iteration on all kernel tracepoints
  * @fct: callback
index 36288d8406756400f5008ee0631b810301504e0d..0df9b1640b2af5d4ade21a376172fdfd6d097694 100644 (file)
@@ -96,7 +96,7 @@ static DEFINE_SPINLOCK(uidhash_lock);
 
 /* root_user.__count is 1, for init task cred */
 struct user_struct root_user = {
-       .__count        = ATOMIC_INIT(1),
+       .__count        = REFCOUNT_INIT(1),
        .processes      = ATOMIC_INIT(1),
        .sigpending     = ATOMIC_INIT(0),
        .locked_shm     = 0,
@@ -123,7 +123,7 @@ static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
 
        hlist_for_each_entry(user, hashent, uidhash_node) {
                if (uid_eq(user->uid, uid)) {
-                       atomic_inc(&user->__count);
+                       refcount_inc(&user->__count);
                        return user;
                }
        }
@@ -169,11 +169,8 @@ void free_uid(struct user_struct *up)
        if (!up)
                return;
 
-       local_irq_save(flags);
-       if (atomic_dec_and_lock(&up->__count, &uidhash_lock))
+       if (refcount_dec_and_lock_irqsave(&up->__count, &uidhash_lock, &flags))
                free_user(up, flags);
-       else
-               local_irq_restore(flags);
 }
 
 struct user_struct *alloc_uid(kuid_t uid)
@@ -191,7 +188,7 @@ struct user_struct *alloc_uid(kuid_t uid)
                        goto out_unlock;
 
                new->uid = uid;
-               atomic_set(&new->__count, 1);
+               refcount_set(&new->__count, 1);
                ratelimit_state_init(&new->ratelimit, HZ, 100);
                ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE);
 
index 09aae85418ab92218f330f3bad18e8e96cb31055..f2a39c9e54853262c8f8d566775fbae6062d4480 100644 (file)
@@ -2,5 +2,7 @@
 # Generated files
 #
 gen_crc32table
+gen_crc64table
 crc32table.h
+crc64table.h
 oid_registry_data.c
index 706836ec314d2add83b84ebe59dec8fd7e13a7ad..a3928d4438b5008c1fa01470de11245d1557bc33 100644 (file)
@@ -170,6 +170,14 @@ config CRC32_BIT
 
 endchoice
 
+config CRC64
+       tristate "CRC64 functions"
+       help
+         This option is provided for the case where no in-kernel-tree
+         modules require CRC64 functions, but a module built outside
+         the kernel tree does. Such modules that use library CRC64
+         functions require M here.
+
 config CRC4
        tristate "CRC4 functions"
        help
@@ -223,7 +231,6 @@ config AUDIT_COMPAT_GENERIC
 
 config RANDOM32_SELFTEST
        bool "PRNG perform self test on init"
-       default n
        help
          This option enables the 32 bit PRNG library functions to perform a
          self test on initialization.
index ab1b599202bca7f5ba8b690a92df177a3b8c1282..3589765141a875aa96d4b785296071e2f29aff11 100644 (file)
@@ -1220,7 +1220,6 @@ config LOCK_TORTURE_TEST
        tristate "torture tests for locking"
        depends on DEBUG_KERNEL
        select TORTURE_TEST
-       default n
        help
          This option provides a kernel module that runs torture tests
          on kernel locking primitives.  The kernel module may be built
@@ -1687,7 +1686,6 @@ config LKDTM
        tristate "Linux Kernel Dump Test Tool Module"
        depends on DEBUG_FS
        depends on BLOCK
-       default n
        help
        This module enables testing of the different dumping mechanisms by
        inducing system failures at predefined crash points.
@@ -1721,7 +1719,6 @@ config KPROBES_SANITY_TEST
        bool "Kprobes sanity tests"
        depends on DEBUG_KERNEL
        depends on KPROBES
-       default n
        help
          This option provides for testing basic kprobes functionality on
          boot. Samples of kprobe and kretprobe are inserted and
@@ -1732,7 +1729,6 @@ config KPROBES_SANITY_TEST
 config BACKTRACE_SELF_TEST
        tristate "Self test for the backtrace code"
        depends on DEBUG_KERNEL
-       default n
        help
          This option provides a kernel module that can be used to test
          the kernel stack backtrace code. This option is not useful
@@ -1802,7 +1798,6 @@ config TEST_PRINTF
 
 config TEST_BITMAP
        tristate "Test bitmap_*() family of functions at runtime"
-       default n
        help
          Enable this option to test the bitmap functions at boot.
 
@@ -1823,7 +1818,6 @@ config TEST_OVERFLOW
 
 config TEST_RHASHTABLE
        tristate "Perform selftest on resizable hash table"
-       default n
        help
          Enable this option to test the rhashtable functions at boot.
 
@@ -1831,7 +1825,6 @@ config TEST_RHASHTABLE
 
 config TEST_HASH
        tristate "Perform selftest on hash functions"
-       default n
        help
          Enable this option to test the kernel's integer (<linux/hash.h>),
          string (<linux/stringhash.h>), and siphash (<linux/siphash.h>)
@@ -1842,7 +1835,6 @@ config TEST_HASH
 
 config TEST_PARMAN
        tristate "Perform selftest on priority array manager"
-       default n
        depends on PARMAN
        help
          Enable this option to test priority array manager on boot
@@ -1852,7 +1844,6 @@ config TEST_PARMAN
 
 config TEST_LKM
        tristate "Test module loading with 'hello world' module"
-       default n
        depends on m
        help
          This builds the "test_module" module that emits "Hello, world"
@@ -1866,7 +1857,6 @@ config TEST_LKM
 
 config TEST_USER_COPY
        tristate "Test user/kernel boundary protections"
-       default n
        depends on m
        help
          This builds the "test_user_copy" module that runs sanity checks
@@ -1879,7 +1869,6 @@ config TEST_USER_COPY
 
 config TEST_BPF
        tristate "Test BPF filter functionality"
-       default n
        depends on m && NET
        help
          This builds the "test_bpf" module that runs various test vectors
@@ -1893,7 +1882,6 @@ config TEST_BPF
 
 config FIND_BIT_BENCHMARK
        tristate "Test find_bit functions"
-       default n
        help
          This builds the "test_find_bit" module that measure find_*_bit()
          functions performance.
@@ -1902,7 +1890,6 @@ config FIND_BIT_BENCHMARK
 
 config TEST_FIRMWARE
        tristate "Test firmware loading via userspace interface"
-       default n
        depends on FW_LOADER
        help
          This builds the "test_firmware" module that creates a userspace
@@ -1915,7 +1902,6 @@ config TEST_FIRMWARE
 
 config TEST_SYSCTL
        tristate "sysctl test driver"
-       default n
        depends on PROC_SYSCTL
        help
          This builds the "test_sysctl" module. This driver enables to test the
@@ -1926,7 +1912,6 @@ config TEST_SYSCTL
 
 config TEST_UDELAY
        tristate "udelay test driver"
-       default n
        help
          This builds the "udelay_test" module that helps to make sure
          that udelay() is working properly.
@@ -1935,7 +1920,6 @@ config TEST_UDELAY
 
 config TEST_STATIC_KEYS
        tristate "Test static keys"
-       default n
        depends on m
        help
          Test the static key interfaces.
@@ -1944,7 +1928,6 @@ config TEST_STATIC_KEYS
 
 config TEST_KMOD
        tristate "kmod stress tester"
-       default n
        depends on m
        depends on BLOCK && (64BIT || LBDAF)      # for XFS, BTRFS
        depends on NETDEVICES && NET_CORE && INET # for TUN
index d95bb252510169816ae0ce67c1e92a1e1ec9ce87..9baefb6cb1a11a54073e9e9fec7f06eccc876b58 100644 (file)
@@ -103,6 +103,7 @@ obj-$(CONFIG_CRC16) += crc16.o
 obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
 obj-$(CONFIG_CRC_ITU_T)        += crc-itu-t.o
 obj-$(CONFIG_CRC32)    += crc32.o
+obj-$(CONFIG_CRC64)     += crc64.o
 obj-$(CONFIG_CRC32_SELFTEST)   += crc32test.o
 obj-$(CONFIG_CRC4)     += crc4.o
 obj-$(CONFIG_CRC7)     += crc7.o
@@ -217,7 +218,9 @@ obj-$(CONFIG_FONT_SUPPORT) += fonts/
 obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o
 
 hostprogs-y    := gen_crc32table
+hostprogs-y    += gen_crc64table
 clean-files    := crc32table.h
+clean-files    += crc64table.h
 
 $(obj)/crc32.o: $(obj)/crc32table.h
 
@@ -227,6 +230,14 @@ quiet_cmd_crc32 = GEN     $@
 $(obj)/crc32table.h: $(obj)/gen_crc32table
        $(call cmd,crc32)
 
+$(obj)/crc64.o: $(obj)/crc64table.h
+
+quiet_cmd_crc64 = GEN     $@
+      cmd_crc64 = $< > $@
+
+$(obj)/crc64table.h: $(obj)/gen_crc64table
+       $(call cmd,crc64)
+
 #
 # Build a fast OID lookip registry from include/linux/oid_registry.h
 #
index 730969c681cbaf6228e5f8a78bd56e3e547b7122..2fd07f6df0b85e417f340576f530878a9d6ddcfc 100644 (file)
@@ -1152,14 +1152,10 @@ EXPORT_SYMBOL(bitmap_free);
  *     @buf: array of u32 (in host byte order), the source bitmap
  *     @nbits: number of bits in @bitmap
  */
-void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf,
-                                               unsigned int nbits)
+void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf, unsigned int nbits)
 {
        unsigned int i, halfwords;
 
-       if (!nbits)
-               return;
-
        halfwords = DIV_ROUND_UP(nbits, 32);
        for (i = 0; i < halfwords; i++) {
                bitmap[i/2] = (unsigned long) buf[i];
@@ -1183,9 +1179,6 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap, unsigned int nbits)
 {
        unsigned int i, halfwords;
 
-       if (!nbits)
-               return;
-
        halfwords = DIV_ROUND_UP(nbits, 32);
        for (i = 0; i < halfwords; i++) {
                buf[i] = (u32) (bitmap[i/2] & UINT_MAX);
diff --git a/lib/crc64.c b/lib/crc64.c
new file mode 100644 (file)
index 0000000..0ef8ae6
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Normal 64-bit CRC calculation.
+ *
+ * This is a basic crc64 implementation following ECMA-182 specification,
+ * which can be found from,
+ * http://www.ecma-international.org/publications/standards/Ecma-182.htm
+ *
+ * Dr. Ross N. Williams has a great document to introduce the idea of CRC
+ * algorithm, here the CRC64 code is also inspired by the table-driven
+ * algorithm and detail example from this paper. This paper can be found
+ * from,
+ * http://www.ross.net/crc/download/crc_v3.txt
+ *
+ * crc64table[256] is the lookup table of a table-driven 64-bit CRC
+ * calculation, which is generated by gen_crc64table.c in kernel build
+ * time. The polynomial of crc64 arithmetic is from ECMA-182 specification
+ * as well, which is defined as,
+ *
+ * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 +
+ * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 +
+ * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 +
+ * x^7 + x^4 + x + 1
+ *
+ * Copyright 2018 SUSE Linux.
+ *   Author: Coly Li <colyli@suse.de>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include "crc64table.h"
+
+MODULE_DESCRIPTION("CRC64 calculations");
+MODULE_LICENSE("GPL v2");
+
+/**
+ * crc64_be - Calculate bitwise big-endian ECMA-182 CRC64
+ * @crc: seed value for computation. 0 or (u64)~0 for a new CRC calculation,
+       or the previous crc64 value if computing incrementally.
+ * @p: pointer to buffer over which CRC64 is run
+ * @len: length of buffer @p
+ */
+u64 __pure crc64_be(u64 crc, const void *p, size_t len)
+{
+       size_t i, t;
+
+       const unsigned char *_p = p;
+
+       for (i = 0; i < len; i++) {
+               t = ((crc >> 56) ^ (*_p++)) & 0xFF;
+               crc = crc64table[t] ^ (crc << 8);
+       }
+
+       return crc;
+}
+EXPORT_SYMBOL_GPL(crc64_be);
diff --git a/lib/gen_crc64table.c b/lib/gen_crc64table.c
new file mode 100644 (file)
index 0000000..9011926
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generate lookup table for the table-driven CRC64 calculation.
+ *
+ * gen_crc64table is executed in kernel build time and generates
+ * lib/crc64table.h. This header is included by lib/crc64.c for
+ * the table-driven CRC64 calculation.
+ *
+ * See lib/crc64.c for more information about which specification
+ * and polynomial arithmetic that gen_crc64table.c follows to
+ * generate the lookup table.
+ *
+ * Copyright 2018 SUSE Linux.
+ *   Author: Coly Li <colyli@suse.de>
+ */
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <linux/swab.h>
+
+#define CRC64_ECMA182_POLY 0x42F0E1EBA9EA3693ULL
+
+static uint64_t crc64_table[256] = {0};
+
+static void generate_crc64_table(void)
+{
+       uint64_t i, j, c, crc;
+
+       for (i = 0; i < 256; i++) {
+               crc = 0;
+               c = i << 56;
+
+               for (j = 0; j < 8; j++) {
+                       if ((crc ^ c) & 0x8000000000000000ULL)
+                               crc = (crc << 1) ^ CRC64_ECMA182_POLY;
+                       else
+                               crc <<= 1;
+                       c <<= 1;
+               }
+
+               crc64_table[i] = crc;
+       }
+}
+
+static void print_crc64_table(void)
+{
+       int i;
+
+       printf("/* this file is generated - do not edit */\n\n");
+       printf("#include <linux/types.h>\n");
+       printf("#include <linux/cache.h>\n\n");
+       printf("static const u64 ____cacheline_aligned crc64table[256] = {\n");
+       for (i = 0; i < 256; i++) {
+               printf("\t0x%016" PRIx64 "ULL", crc64_table[i]);
+               if (i & 0x1)
+                       printf(",\n");
+               else
+                       printf(", ");
+       }
+       printf("};\n");
+}
+
+int main(int argc, char *argv[])
+{
+       generate_crc64_table();
+       print_crc64_table();
+       return 0;
+}
index ae4223e0f5bcb68610511b2cb7ba2e12b7f7d086..310e29b5150737eac76503b91baf551da3bc47da 100644 (file)
@@ -174,17 +174,15 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
        int i;
 
        size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
-       if (gfp != GFP_KERNEL)
-               tbl = kzalloc(size, gfp | __GFP_NOWARN | __GFP_NORETRY);
-       else
-               tbl = kvzalloc(size, gfp);
+       tbl = kvzalloc(size, gfp);
 
        size = nbuckets;
 
-       if (tbl == NULL && gfp != GFP_KERNEL) {
+       if (tbl == NULL && (gfp & ~__GFP_NOFAIL) != GFP_KERNEL) {
                tbl = nested_bucket_table_alloc(ht, nbuckets, gfp);
                nbuckets = 0;
        }
+
        if (tbl == NULL)
                return NULL;
 
@@ -450,7 +448,7 @@ static int rhashtable_insert_rehash(struct rhashtable *ht,
 
        err = -ENOMEM;
 
-       new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC);
+       new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC | __GFP_NOWARN);
        if (new_tbl == NULL)
                goto fail;
 
@@ -1060,9 +1058,16 @@ int rhashtable_init(struct rhashtable *ht,
                }
        }
 
+       /*
+        * This is api initialization and thus we need to guarantee the
+        * initial rhashtable allocation. Upon failure, retry with the
+        * smallest possible size with __GFP_NOFAIL semantics.
+        */
        tbl = bucket_table_alloc(ht, size, GFP_KERNEL);
-       if (tbl == NULL)
-               return -ENOMEM;
+       if (unlikely(tbl == NULL)) {
+               size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE);
+               tbl = bucket_table_alloc(ht, size, GFP_KERNEL | __GFP_NOFAIL);
+       }
 
        atomic_set(&ht->nelems, 0);
 
index b9cdeecc19dc303f0167433457f41f5325684f6a..d5a06addeb27180a60577dbcd04ff2582cb391db 100644 (file)
@@ -15,7 +15,7 @@ struct foo {
        unsigned int bar;
 };
 
-struct foo *foo;
+static struct foo *foo;
 
 static int __init test_debug_virtual_init(void)
 {
index 3f415d8101f3209f16ba66143ee1b31b56d4b0b1..626f580b4ff7b0c52fd3aeb7cffdf19429c3f457 100644 (file)
@@ -18,7 +18,7 @@ static const unsigned char data_b[] = {
 
 static const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C...";
 
-static const char * const test_data_1_le[] __initconst = {
+static const char * const test_data_1[] __initconst = {
        "be", "32", "db", "7b", "0a", "18", "93", "b2",
        "70", "ba", "c4", "24", "7d", "83", "34", "9b",
        "a6", "9c", "31", "ad", "9c", "0f", "ac", "e9",
@@ -32,16 +32,33 @@ static const char * const test_data_2_le[] __initconst = {
        "d14c", "9919", "b143", "0caf",
 };
 
+static const char * const test_data_2_be[] __initconst = {
+       "be32", "db7b", "0a18", "93b2",
+       "70ba", "c424", "7d83", "349b",
+       "a69c", "31ad", "9c0f", "ace9",
+       "4cd1", "1999", "43b1", "af0c",
+};
+
 static const char * const test_data_4_le[] __initconst = {
        "7bdb32be", "b293180a", "24c4ba70", "9b34837d",
        "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143",
 };
 
+static const char * const test_data_4_be[] __initconst = {
+       "be32db7b", "0a1893b2", "70bac424", "7d83349b",
+       "a69c31ad", "9c0face9", "4cd11999", "43b1af0c",
+};
+
 static const char * const test_data_8_le[] __initconst = {
        "b293180a7bdb32be", "9b34837d24c4ba70",
        "e9ac0f9cad319ca6", "0cafb1439919d14c",
 };
 
+static const char * const test_data_8_be[] __initconst = {
+       "be32db7b0a1893b2", "70bac4247d83349b",
+       "a69c31ad9c0face9", "4cd1199943b1af0c",
+};
+
 #define FILL_CHAR      '#'
 
 static unsigned total_tests __initdata;
@@ -56,6 +73,7 @@ static void __init test_hexdump_prepare_test(size_t len, int rowsize,
        size_t l = len;
        int gs = groupsize, rs = rowsize;
        unsigned int i;
+       const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
 
        if (rs != 16 && rs != 32)
                rs = 16;
@@ -67,13 +85,13 @@ static void __init test_hexdump_prepare_test(size_t len, int rowsize,
                gs = 1;
 
        if (gs == 8)
-               result = test_data_8_le;
+               result = is_be ? test_data_8_be : test_data_8_le;
        else if (gs == 4)
-               result = test_data_4_le;
+               result = is_be ? test_data_4_be : test_data_4_le;
        else if (gs == 2)
-               result = test_data_2_le;
+               result = is_be ? test_data_2_be : test_data_2_le;
        else
-               result = test_data_1_le;
+               result = test_data_1;
 
        /* hex dump */
        p = test;
index e5e606ee5f715e846a19ea9186391c47a2efddc0..9a7b8b049d04fb42ca02783eabf5e70ef9fe5495 100644 (file)
@@ -46,7 +46,8 @@ config PAGE_POISONING
          Fill the pages with poison patterns after free_pages() and verify
          the patterns before alloc_pages. The filling of the memory helps
          reduce the risk of information leaks from freed data. This does
-         have a potential performance impact.
+         have a potential performance impact if enabled with the
+         "page_poison=1" kernel boot option.
 
          Note that "poison" here is not the same thing as the "HWPoison"
          for CONFIG_MEMORY_FAILURE. This is software poisoning only.
@@ -65,7 +66,7 @@ config PAGE_POISONING_NO_SANITY
           say N.
 
 config PAGE_POISONING_ZERO
-       bool "Use zero for poisoning instead of random data"
+       bool "Use zero for poisoning instead of debugging value"
        depends on PAGE_POISONING
        ---help---
           Instead of using the existing poison value, fill the pages with
@@ -75,7 +76,6 @@ config PAGE_POISONING_ZERO
           allocation.
 
           If unsure, say N
-       bool
 
 config DEBUG_PAGE_REF
        bool "Enable tracepoint to track down page reference manipulation"
index 2e5d3df0853d928021cba0e30c70ff682afeaf68..f5981e9d6ae2e73761879023584ff378ebfcb1b8 100644 (file)
@@ -438,10 +438,10 @@ retry:
        if (new_congested) {
                /* !found and storage for new one already allocated, insert */
                congested = new_congested;
-               new_congested = NULL;
                rb_link_node(&congested->rb_node, parent, node);
                rb_insert_color(&congested->rb_node, &bdi->cgwb_congested_tree);
-               goto found;
+               spin_unlock_irqrestore(&cgwb_lock, flags);
+               return congested;
        }
 
        spin_unlock_irqrestore(&cgwb_lock, flags);
@@ -451,13 +451,13 @@ retry:
        if (!new_congested)
                return NULL;
 
-       atomic_set(&new_congested->refcnt, 0);
+       refcount_set(&new_congested->refcnt, 1);
        new_congested->__bdi = bdi;
        new_congested->blkcg_id = blkcg_id;
        goto retry;
 
 found:
-       atomic_inc(&congested->refcnt);
+       refcount_inc(&congested->refcnt);
        spin_unlock_irqrestore(&cgwb_lock, flags);
        kfree(new_congested);
        return congested;
@@ -473,11 +473,8 @@ void wb_congested_put(struct bdi_writeback_congested *congested)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
-       if (!atomic_dec_and_lock(&congested->refcnt, &cgwb_lock)) {
-               local_irq_restore(flags);
+       if (!refcount_dec_and_lock_irqsave(&congested->refcnt, &cgwb_lock, &flags))
                return;
-       }
 
        /* bdi might already have been destroyed leaving @congested unlinked */
        if (congested->__bdi) {
@@ -804,7 +801,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
        if (!bdi->wb_congested)
                return -ENOMEM;
 
-       atomic_set(&bdi->wb_congested->refcnt, 1);
+       refcount_set(&bdi->wb_congested->refcnt, 1);
 
        err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
        if (err) {
index 76e7a058b32fc2c4dfb675d262dde082dced208d..0b05545916106cad2f5bd490af19514107a6b9c5 100644 (file)
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -177,16 +177,19 @@ static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
        up_write(&hmm->mirrors_sem);
 }
 
-static void hmm_invalidate_range_start(struct mmu_notifier *mn,
+static int hmm_invalidate_range_start(struct mmu_notifier *mn,
                                       struct mm_struct *mm,
                                       unsigned long start,
-                                      unsigned long end)
+                                      unsigned long end,
+                                      bool blockable)
 {
        struct hmm *hmm = mm->hmm;
 
        VM_BUG_ON(!hmm);
 
        atomic_inc(&hmm->sequence);
+
+       return 0;
 }
 
 static void hmm_invalidate_range_end(struct mmu_notifier *mn,
index 9e3654d70289895e67f6aff18734c165ed1d0e58..dab088cb69374bd205f90ec5bd7868ae4d478f87 100644 (file)
@@ -389,18 +389,6 @@ static inline struct page *mem_map_next(struct page *iter,
        return iter + 1;
 }
 
-/*
- * FLATMEM and DISCONTIGMEM configurations use alloc_bootmem_node,
- * so all functions starting at paging_init should be marked __init
- * in those cases. SPARSEMEM, however, allows for memory hotplug,
- * and alloc_bootmem_node is not used.
- */
-#ifdef CONFIG_SPARSEMEM
-#define __paginginit __meminit
-#else
-#define __paginginit __init
-#endif
-
 /* Memory initialisation debug and verification */
 enum mminit_level {
        MMINIT_WARNING,
index 2621be57bd957caabd5df559d41f2c40e284a26d..1bd514c9e5d08778caf843045b4b873d83637550 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -703,7 +703,7 @@ again:
         * We cannot do anything with the page while its refcount is 0.
         * Usually 0 means free, or tail of a higher-order page: in which
         * case this node is no longer referenced, and should be freed;
-        * however, it might mean that the page is under page_freeze_refs().
+        * however, it might mean that the page is under page_ref_freeze().
         * The __remove_mapping() case is easy, again the node is now stale;
         * but if page is swapcache in migrate_page_move_mapping(), it might
         * still be our page, in which case it's essential to keep the node.
@@ -714,7 +714,7 @@ again:
                 * work here too.  We have chosen the !PageSwapCache test to
                 * optimize the common case, when the page is or is about to
                 * be freed: PageSwapCache is cleared (under spin_lock_irq)
-                * in the freeze_refs section of __remove_mapping(); but Anon
+                * in the ref_freeze section of __remove_mapping(); but Anon
                 * page->mapping reset to NULL later, in free_pages_prepare().
                 */
                if (!PageSwapCache(page))
index 6a921890739f7e1c0acad44d5916c5f43487a2a1..4ead5a4817de3ffbf1477cfe77b8f4f4802281c8 100644 (file)
@@ -1776,6 +1776,62 @@ cleanup:
        return true;
 }
 
+/**
+ * mem_cgroup_get_oom_group - get a memory cgroup to clean up after OOM
+ * @victim: task to be killed by the OOM killer
+ * @oom_domain: memcg in case of memcg OOM, NULL in case of system-wide OOM
+ *
+ * Returns a pointer to a memory cgroup, which has to be cleaned up
+ * by killing all belonging OOM-killable tasks.
+ *
+ * Caller has to call mem_cgroup_put() on the returned non-NULL memcg.
+ */
+struct mem_cgroup *mem_cgroup_get_oom_group(struct task_struct *victim,
+                                           struct mem_cgroup *oom_domain)
+{
+       struct mem_cgroup *oom_group = NULL;
+       struct mem_cgroup *memcg;
+
+       if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
+               return NULL;
+
+       if (!oom_domain)
+               oom_domain = root_mem_cgroup;
+
+       rcu_read_lock();
+
+       memcg = mem_cgroup_from_task(victim);
+       if (memcg == root_mem_cgroup)
+               goto out;
+
+       /*
+        * Traverse the memory cgroup hierarchy from the victim task's
+        * cgroup up to the OOMing cgroup (or root) to find the
+        * highest-level memory cgroup with oom.group set.
+        */
+       for (; memcg; memcg = parent_mem_cgroup(memcg)) {
+               if (memcg->oom_group)
+                       oom_group = memcg;
+
+               if (memcg == oom_domain)
+                       break;
+       }
+
+       if (oom_group)
+               css_get(&oom_group->css);
+out:
+       rcu_read_unlock();
+
+       return oom_group;
+}
+
+void mem_cgroup_print_oom_group(struct mem_cgroup *memcg)
+{
+       pr_info("Tasks in ");
+       pr_cont_cgroup_path(memcg->css.cgroup);
+       pr_cont(" are going to be killed due to memory.oom.group set\n");
+}
+
 /**
  * lock_page_memcg - lock a page->mem_cgroup binding
  * @page: the page
@@ -2899,29 +2955,34 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
        return retval;
 }
 
-static void tree_stat(struct mem_cgroup *memcg, unsigned long *stat)
-{
-       struct mem_cgroup *iter;
-       int i;
-
-       memset(stat, 0, sizeof(*stat) * MEMCG_NR_STAT);
-
-       for_each_mem_cgroup_tree(iter, memcg) {
-               for (i = 0; i < MEMCG_NR_STAT; i++)
-                       stat[i] += memcg_page_state(iter, i);
-       }
-}
+struct accumulated_stats {
+       unsigned long stat[MEMCG_NR_STAT];
+       unsigned long events[NR_VM_EVENT_ITEMS];
+       unsigned long lru_pages[NR_LRU_LISTS];
+       const unsigned int *stats_array;
+       const unsigned int *events_array;
+       int stats_size;
+       int events_size;
+};
 
-static void tree_events(struct mem_cgroup *memcg, unsigned long *events)
+static void accumulate_memcg_tree(struct mem_cgroup *memcg,
+                                 struct accumulated_stats *acc)
 {
-       struct mem_cgroup *iter;
+       struct mem_cgroup *mi;
        int i;
 
-       memset(events, 0, sizeof(*events) * NR_VM_EVENT_ITEMS);
+       for_each_mem_cgroup_tree(mi, memcg) {
+               for (i = 0; i < acc->stats_size; i++)
+                       acc->stat[i] += memcg_page_state(mi,
+                               acc->stats_array ? acc->stats_array[i] : i);
 
-       for_each_mem_cgroup_tree(iter, memcg) {
-               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
-                       events[i] += memcg_sum_events(iter, i);
+               for (i = 0; i < acc->events_size; i++)
+                       acc->events[i] += memcg_sum_events(mi,
+                               acc->events_array ? acc->events_array[i] : i);
+
+               for (i = 0; i < NR_LRU_LISTS; i++)
+                       acc->lru_pages[i] +=
+                               mem_cgroup_nr_lru_pages(mi, BIT(i));
        }
 }
 
@@ -3332,6 +3393,7 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        unsigned long memory, memsw;
        struct mem_cgroup *mi;
        unsigned int i;
+       struct accumulated_stats acc;
 
        BUILD_BUG_ON(ARRAY_SIZE(memcg1_stat_names) != ARRAY_SIZE(memcg1_stats));
        BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS);
@@ -3364,32 +3426,27 @@ static int memcg_stat_show(struct seq_file *m, void *v)
                seq_printf(m, "hierarchical_memsw_limit %llu\n",
                           (u64)memsw * PAGE_SIZE);
 
-       for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
-               unsigned long long val = 0;
+       memset(&acc, 0, sizeof(acc));
+       acc.stats_size = ARRAY_SIZE(memcg1_stats);
+       acc.stats_array = memcg1_stats;
+       acc.events_size = ARRAY_SIZE(memcg1_events);
+       acc.events_array = memcg1_events;
+       accumulate_memcg_tree(memcg, &acc);
 
+       for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) {
                if (memcg1_stats[i] == MEMCG_SWAP && !do_memsw_account())
                        continue;
-               for_each_mem_cgroup_tree(mi, memcg)
-                       val += memcg_page_state(mi, memcg1_stats[i]) *
-                       PAGE_SIZE;
-               seq_printf(m, "total_%s %llu\n", memcg1_stat_names[i], val);
+               seq_printf(m, "total_%s %llu\n", memcg1_stat_names[i],
+                          (u64)acc.stat[i] * PAGE_SIZE);
        }
 
-       for (i = 0; i < ARRAY_SIZE(memcg1_events); i++) {
-               unsigned long long val = 0;
-
-               for_each_mem_cgroup_tree(mi, memcg)
-                       val += memcg_sum_events(mi, memcg1_events[i]);
-               seq_printf(m, "total_%s %llu\n", memcg1_event_names[i], val);
-       }
-
-       for (i = 0; i < NR_LRU_LISTS; i++) {
-               unsigned long long val = 0;
+       for (i = 0; i < ARRAY_SIZE(memcg1_events); i++)
+               seq_printf(m, "total_%s %llu\n", memcg1_event_names[i],
+                          (u64)acc.events[i]);
 
-               for_each_mem_cgroup_tree(mi, memcg)
-                       val += mem_cgroup_nr_lru_pages(mi, BIT(i)) * PAGE_SIZE;
-               seq_printf(m, "total_%s %llu\n", mem_cgroup_lru_names[i], val);
-       }
+       for (i = 0; i < NR_LRU_LISTS; i++)
+               seq_printf(m, "total_%s %llu\n", mem_cgroup_lru_names[i],
+                          (u64)acc.lru_pages[i] * PAGE_SIZE);
 
 #ifdef CONFIG_DEBUG_VM
        {
@@ -5486,8 +5543,7 @@ static int memory_events_show(struct seq_file *m, void *v)
 static int memory_stat_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-       unsigned long stat[MEMCG_NR_STAT];
-       unsigned long events[NR_VM_EVENT_ITEMS];
+       struct accumulated_stats acc;
        int i;
 
        /*
@@ -5501,70 +5557,97 @@ static int memory_stat_show(struct seq_file *m, void *v)
         * Current memory state:
         */
 
-       tree_stat(memcg, stat);
-       tree_events(memcg, events);
+       memset(&acc, 0, sizeof(acc));
+       acc.stats_size = MEMCG_NR_STAT;
+       acc.events_size = NR_VM_EVENT_ITEMS;
+       accumulate_memcg_tree(memcg, &acc);
 
        seq_printf(m, "anon %llu\n",
-                  (u64)stat[MEMCG_RSS] * PAGE_SIZE);
+                  (u64)acc.stat[MEMCG_RSS] * PAGE_SIZE);
        seq_printf(m, "file %llu\n",
-                  (u64)stat[MEMCG_CACHE] * PAGE_SIZE);
+                  (u64)acc.stat[MEMCG_CACHE] * PAGE_SIZE);
        seq_printf(m, "kernel_stack %llu\n",
-                  (u64)stat[MEMCG_KERNEL_STACK_KB] * 1024);
+                  (u64)acc.stat[MEMCG_KERNEL_STACK_KB] * 1024);
        seq_printf(m, "slab %llu\n",
-                  (u64)(stat[NR_SLAB_RECLAIMABLE] +
-                        stat[NR_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
+                  (u64)(acc.stat[NR_SLAB_RECLAIMABLE] +
+                        acc.stat[NR_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
        seq_printf(m, "sock %llu\n",
-                  (u64)stat[MEMCG_SOCK] * PAGE_SIZE);
+                  (u64)acc.stat[MEMCG_SOCK] * PAGE_SIZE);
 
        seq_printf(m, "shmem %llu\n",
-                  (u64)stat[NR_SHMEM] * PAGE_SIZE);
+                  (u64)acc.stat[NR_SHMEM] * PAGE_SIZE);
        seq_printf(m, "file_mapped %llu\n",
-                  (u64)stat[NR_FILE_MAPPED] * PAGE_SIZE);
+                  (u64)acc.stat[NR_FILE_MAPPED] * PAGE_SIZE);
        seq_printf(m, "file_dirty %llu\n",
-                  (u64)stat[NR_FILE_DIRTY] * PAGE_SIZE);
+                  (u64)acc.stat[NR_FILE_DIRTY] * PAGE_SIZE);
        seq_printf(m, "file_writeback %llu\n",
-                  (u64)stat[NR_WRITEBACK] * PAGE_SIZE);
-
-       for (i = 0; i < NR_LRU_LISTS; i++) {
-               struct mem_cgroup *mi;
-               unsigned long val = 0;
+                  (u64)acc.stat[NR_WRITEBACK] * PAGE_SIZE);
 
-               for_each_mem_cgroup_tree(mi, memcg)
-                       val += mem_cgroup_nr_lru_pages(mi, BIT(i));
-               seq_printf(m, "%s %llu\n",
-                          mem_cgroup_lru_names[i], (u64)val * PAGE_SIZE);
-       }
+       for (i = 0; i < NR_LRU_LISTS; i++)
+               seq_printf(m, "%s %llu\n", mem_cgroup_lru_names[i],
+                          (u64)acc.lru_pages[i] * PAGE_SIZE);
 
        seq_printf(m, "slab_reclaimable %llu\n",
-                  (u64)stat[NR_SLAB_RECLAIMABLE] * PAGE_SIZE);
+                  (u64)acc.stat[NR_SLAB_RECLAIMABLE] * PAGE_SIZE);
        seq_printf(m, "slab_unreclaimable %llu\n",
-                  (u64)stat[NR_SLAB_UNRECLAIMABLE] * PAGE_SIZE);
+                  (u64)acc.stat[NR_SLAB_UNRECLAIMABLE] * PAGE_SIZE);
 
        /* Accumulated memory events */
 
-       seq_printf(m, "pgfault %lu\n", events[PGFAULT]);
-       seq_printf(m, "pgmajfault %lu\n", events[PGMAJFAULT]);
+       seq_printf(m, "pgfault %lu\n", acc.events[PGFAULT]);
+       seq_printf(m, "pgmajfault %lu\n", acc.events[PGMAJFAULT]);
 
-       seq_printf(m, "pgrefill %lu\n", events[PGREFILL]);
-       seq_printf(m, "pgscan %lu\n", events[PGSCAN_KSWAPD] +
-                  events[PGSCAN_DIRECT]);
-       seq_printf(m, "pgsteal %lu\n", events[PGSTEAL_KSWAPD] +
-                  events[PGSTEAL_DIRECT]);
-       seq_printf(m, "pgactivate %lu\n", events[PGACTIVATE]);
-       seq_printf(m, "pgdeactivate %lu\n", events[PGDEACTIVATE]);
-       seq_printf(m, "pglazyfree %lu\n", events[PGLAZYFREE]);
-       seq_printf(m, "pglazyfreed %lu\n", events[PGLAZYFREED]);
+       seq_printf(m, "pgrefill %lu\n", acc.events[PGREFILL]);
+       seq_printf(m, "pgscan %lu\n", acc.events[PGSCAN_KSWAPD] +
+                  acc.events[PGSCAN_DIRECT]);
+       seq_printf(m, "pgsteal %lu\n", acc.events[PGSTEAL_KSWAPD] +
+                  acc.events[PGSTEAL_DIRECT]);
+       seq_printf(m, "pgactivate %lu\n", acc.events[PGACTIVATE]);
+       seq_printf(m, "pgdeactivate %lu\n", acc.events[PGDEACTIVATE]);
+       seq_printf(m, "pglazyfree %lu\n", acc.events[PGLAZYFREE]);
+       seq_printf(m, "pglazyfreed %lu\n", acc.events[PGLAZYFREED]);
 
        seq_printf(m, "workingset_refault %lu\n",
-                  stat[WORKINGSET_REFAULT]);
+                  acc.stat[WORKINGSET_REFAULT]);
        seq_printf(m, "workingset_activate %lu\n",
-                  stat[WORKINGSET_ACTIVATE]);
+                  acc.stat[WORKINGSET_ACTIVATE]);
        seq_printf(m, "workingset_nodereclaim %lu\n",
-                  stat[WORKINGSET_NODERECLAIM]);
+                  acc.stat[WORKINGSET_NODERECLAIM]);
+
+       return 0;
+}
+
+static int memory_oom_group_show(struct seq_file *m, void *v)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
+
+       seq_printf(m, "%d\n", memcg->oom_group);
 
        return 0;
 }
 
+static ssize_t memory_oom_group_write(struct kernfs_open_file *of,
+                                     char *buf, size_t nbytes, loff_t off)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+       int ret, oom_group;
+
+       buf = strstrip(buf);
+       if (!buf)
+               return -EINVAL;
+
+       ret = kstrtoint(buf, 0, &oom_group);
+       if (ret)
+               return ret;
+
+       if (oom_group != 0 && oom_group != 1)
+               return -EINVAL;
+
+       memcg->oom_group = oom_group;
+
+       return nbytes;
+}
+
 static struct cftype memory_files[] = {
        {
                .name = "current",
@@ -5606,6 +5689,12 @@ static struct cftype memory_files[] = {
                .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = memory_stat_show,
        },
+       {
+               .name = "oom.group",
+               .flags = CFTYPE_NOT_ON_ROOT | CFTYPE_NS_DELEGATABLE,
+               .seq_show = memory_oom_group_show,
+               .write = memory_oom_group_write,
+       },
        { }     /* terminate */
 };
 
index 9d142b9b86dcd970d46a2b8124f065bd5eb29391..c83a1746812f53ded0f1840df45619cc6b355c00 100644 (file)
@@ -1167,7 +1167,7 @@ int memory_failure(unsigned long pfn, int flags)
         *    R/W the page; let's pray that the page has been
         *    used and will be freed some time later.
         * In fact it's dangerous to directly bump up page count from 0,
-        * that may make page_freeze_refs()/page_unfreeze_refs() mismatch.
+        * that may make page_ref_freeze()/page_ref_unfreeze() mismatch.
         */
        if (!(flags & MF_COUNT_INCREASED) && !get_hwpoison_page(p)) {
                if (is_free_buddy_page(p)) {
index 4eb6e824a80c800bddefbfb9b1a41eabf70916aa..9eea6e809a4e99fcf11125d47f28d7493af8b0ab 100644 (file)
@@ -982,8 +982,6 @@ static void reset_node_present_pages(pg_data_t *pgdat)
 static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
 {
        struct pglist_data *pgdat;
-       unsigned long zones_size[MAX_NR_ZONES] = {0};
-       unsigned long zholes_size[MAX_NR_ZONES] = {0};
        unsigned long start_pfn = PFN_DOWN(start);
 
        pgdat = NODE_DATA(nid);
@@ -1006,8 +1004,11 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
 
        /* we can use NODE_DATA(nid) from here */
 
+       pgdat->node_id = nid;
+       pgdat->node_start_pfn = start_pfn;
+
        /* init node's zones as empty zones, we don't have any present pages.*/
-       free_area_init_node(nid, zones_size, start_pfn, zholes_size);
+       free_area_init_core_hotplug(nid);
        pgdat->per_cpu_nodestats = alloc_percpu(struct per_cpu_nodestat);
 
        /*
@@ -1016,19 +1017,12 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
         */
        build_all_zonelists(pgdat);
 
-       /*
-        * zone->managed_pages is set to an approximate value in
-        * free_area_init_core(), which will cause
-        * /sys/device/system/node/nodeX/meminfo has wrong data.
-        * So reset it to 0 before any memory is onlined.
-        */
-       reset_node_managed_pages(pgdat);
-
        /*
         * When memory is hot-added, all the memory is in offline state. So
         * clear all zones' present_pages because they will be updated in
         * online_pages() and offline_pages().
         */
+       reset_node_managed_pages(pgdat);
        reset_node_present_pages(pgdat);
 
        return pgdat;
index 01f1a14facc461c4ca5490adc4060d50887aa053..da858f794eb694a934afb58da49f749343ed8c08 100644 (file)
@@ -1784,7 +1784,7 @@ unsigned int mempolicy_slab_node(void)
                zonelist = &NODE_DATA(node)->node_zonelists[ZONELIST_FALLBACK];
                z = first_zones_zonelist(zonelist, highest_zoneidx,
                                                        &policy->v.nodes);
-               return z->zone ? z->zone->node : node;
+               return z->zone ? zone_to_nid(z->zone) : node;
        }
 
        default:
@@ -2326,7 +2326,7 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
                                node_zonelist(numa_node_id(), GFP_HIGHUSER),
                                gfp_zone(GFP_HIGHUSER),
                                &pol->v.nodes);
-               polnid = z->zone->node;
+               polnid = zone_to_nid(z->zone);
                break;
 
        default:
@@ -2504,7 +2504,6 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
                        goto put_new;
 
                /* Create pseudo-vma that contains just the policy */
-               memset(&pvma, 0, sizeof(struct vm_area_struct));
                vma_init(&pvma, NULL);
                pvma.vm_end = TASK_SIZE;        /* policy covers entire file */
                mpol_set_shared_policy(sp, &pvma, new); /* adds ref */
index 44f5fa98c1e77f34ce3f56b715e3e38e9755af54..0ef8cc8d1602246a670d4e443ba7624bd2c99df0 100644 (file)
@@ -213,6 +213,7 @@ EXPORT_SYMBOL(mempool_init_node);
 
 /**
  * mempool_init - initialize a memory pool
+ * @pool:      pointer to the memory pool that should be initialized
  * @min_nr:    the minimum number of elements guaranteed to be
  *             allocated for this pool.
  * @alloc_fn:  user-defined element-allocation function.
index 5b72266b4b03362ebb792ccbbfbf9b84e30c1702..6838a530789b414bcda3a2fca71747d067760118 100644 (file)
@@ -53,13 +53,8 @@ void __init mminit_verify_zonelist(void)
                                zone->name);
 
                        /* Iterate the zonelist */
-                       for_each_zone_zonelist(zone, z, zonelist, zoneid) {
-#ifdef CONFIG_NUMA
-                               pr_cont("%d:%s ", zone->node, zone->name);
-#else
-                               pr_cont("0:%s ", zone->name);
-#endif /* CONFIG_NUMA */
-                       }
+                       for_each_zone_zonelist(zone, z, zonelist, zoneid)
+                               pr_cont("%d:%s ", zone_to_nid(zone), zone->name);
                        pr_cont("\n");
                }
        }
index 8d6449e74431155edcb21308743bd52d449bd8f2..5f2b2b184c604b203f38142d8e638db87487f5f4 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -3063,9 +3063,7 @@ void exit_mmap(struct mm_struct *mm)
                 * which clears VM_LOCKED, otherwise the oom reaper cannot
                 * reliably test it.
                 */
-               mutex_lock(&oom_lock);
-               __oom_reap_task_mm(mm);
-               mutex_unlock(&oom_lock);
+               (void)__oom_reap_task_mm(mm);
 
                set_bit(MMF_OOM_SKIP, &mm->flags);
                down_write(&mm->mmap_sem);
index eff6b88a993f2491b8fb96a2ad553196448966da..82bb1a939c0e496affc2849c1e1af795fe3d5d96 100644 (file)
@@ -174,18 +174,29 @@ void __mmu_notifier_change_pte(struct mm_struct *mm, unsigned long address,
        srcu_read_unlock(&srcu, id);
 }
 
-void __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
-                                 unsigned long start, unsigned long end)
+int __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end,
+                                 bool blockable)
 {
        struct mmu_notifier *mn;
+       int ret = 0;
        int id;
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) {
-               if (mn->ops->invalidate_range_start)
-                       mn->ops->invalidate_range_start(mn, mm, start, end);
+               if (mn->ops->invalidate_range_start) {
+                       int _ret = mn->ops->invalidate_range_start(mn, mm, start, end, blockable);
+                       if (_ret) {
+                               pr_info("%pS callback failed with %d in %sblockable context.\n",
+                                               mn->ops->invalidate_range_start, _ret,
+                                               !blockable ? "non-" : "");
+                               ret = _ret;
+                       }
+               }
        }
        srcu_read_unlock(&srcu, id);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(__mmu_notifier_invalidate_range_start);
 
index 7c74dcc2d26d668cc471ff3ec98db71d47577fa2..b5b25e4dcbbb707e5d7ad0ae588a88ca2dc49e88 100644 (file)
@@ -400,7 +400,8 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
        struct task_struct *p;
        struct task_struct *task;
 
-       pr_info("[ pid ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name\n");
+       pr_info("Tasks state (memory values in pages):\n");
+       pr_info("[  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name\n");
        rcu_read_lock();
        for_each_process(p) {
                if (oom_unkillable_task(p, memcg, nodemask))
@@ -416,7 +417,7 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
                        continue;
                }
 
-               pr_info("[%5d] %5d %5d %8lu %8lu %8ld %8lu         %5hd %s\n",
+               pr_info("[%7d] %5d %5d %8lu %8lu %8ld %8lu         %5hd %s\n",
                        task->pid, from_kuid(&init_user_ns, task_uid(task)),
                        task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
                        mm_pgtables_bytes(task->mm),
@@ -487,9 +488,10 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
 static struct task_struct *oom_reaper_list;
 static DEFINE_SPINLOCK(oom_reaper_lock);
 
-void __oom_reap_task_mm(struct mm_struct *mm)
+bool __oom_reap_task_mm(struct mm_struct *mm)
 {
        struct vm_area_struct *vma;
+       bool ret = true;
 
        /*
         * Tell all users of get_user/copy_from_user etc... that the content
@@ -519,50 +521,32 @@ void __oom_reap_task_mm(struct mm_struct *mm)
                        struct mmu_gather tlb;
 
                        tlb_gather_mmu(&tlb, mm, start, end);
-                       mmu_notifier_invalidate_range_start(mm, start, end);
+                       if (mmu_notifier_invalidate_range_start_nonblock(mm, start, end)) {
+                               ret = false;
+                               continue;
+                       }
                        unmap_page_range(&tlb, vma, start, end, NULL);
                        mmu_notifier_invalidate_range_end(mm, start, end);
                        tlb_finish_mmu(&tlb, start, end);
                }
        }
+
+       return ret;
 }
 
+/*
+ * Reaps the address space of the give task.
+ *
+ * Returns true on success and false if none or part of the address space
+ * has been reclaimed and the caller should retry later.
+ */
 static bool oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm)
 {
        bool ret = true;
 
-       /*
-        * We have to make sure to not race with the victim exit path
-        * and cause premature new oom victim selection:
-        * oom_reap_task_mm             exit_mm
-        *   mmget_not_zero
-        *                                mmput
-        *                                  atomic_dec_and_test
-        *                                exit_oom_victim
-        *                              [...]
-        *                              out_of_memory
-        *                                select_bad_process
-        *                                  # no TIF_MEMDIE task selects new victim
-        *  unmap_page_range # frees some memory
-        */
-       mutex_lock(&oom_lock);
-
        if (!down_read_trylock(&mm->mmap_sem)) {
-               ret = false;
                trace_skip_task_reaping(tsk->pid);
-               goto unlock_oom;
-       }
-
-       /*
-        * If the mm has invalidate_{start,end}() notifiers that could block,
-        * sleep to give the oom victim some more time.
-        * TODO: we really want to get rid of this ugly hack and make sure that
-        * notifiers cannot block for unbounded amount of time
-        */
-       if (mm_has_blockable_invalidate_notifiers(mm)) {
-               up_read(&mm->mmap_sem);
-               schedule_timeout_idle(HZ);
-               goto unlock_oom;
+               return false;
        }
 
        /*
@@ -572,25 +556,27 @@ static bool oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm)
         * down_write();up_write() cycle in exit_mmap().
         */
        if (test_bit(MMF_OOM_SKIP, &mm->flags)) {
-               up_read(&mm->mmap_sem);
                trace_skip_task_reaping(tsk->pid);
-               goto unlock_oom;
+               goto out_unlock;
        }
 
        trace_start_task_reaping(tsk->pid);
 
-       __oom_reap_task_mm(mm);
+       /* failed to reap part of the address space. Try again later */
+       ret = __oom_reap_task_mm(mm);
+       if (!ret)
+               goto out_finish;
 
        pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
                        task_pid_nr(tsk), tsk->comm,
                        K(get_mm_counter(mm, MM_ANONPAGES)),
                        K(get_mm_counter(mm, MM_FILEPAGES)),
                        K(get_mm_counter(mm, MM_SHMEMPAGES)));
+out_finish:
+       trace_finish_task_reaping(tsk->pid);
+out_unlock:
        up_read(&mm->mmap_sem);
 
-       trace_finish_task_reaping(tsk->pid);
-unlock_oom:
-       mutex_unlock(&oom_lock);
        return ret;
 }
 
@@ -843,68 +829,12 @@ static bool task_will_free_mem(struct task_struct *task)
        return ret;
 }
 
-static void oom_kill_process(struct oom_control *oc, const char *message)
+static void __oom_kill_process(struct task_struct *victim)
 {
-       struct task_struct *p = oc->chosen;
-       unsigned int points = oc->chosen_points;
-       struct task_struct *victim = p;
-       struct task_struct *child;
-       struct task_struct *t;
+       struct task_struct *p;
        struct mm_struct *mm;
-       unsigned int victim_points = 0;
-       static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
-                                             DEFAULT_RATELIMIT_BURST);
        bool can_oom_reap = true;
 
-       /*
-        * If the task is already exiting, don't alarm the sysadmin or kill
-        * its children or threads, just give it access to memory reserves
-        * so it can die quickly
-        */
-       task_lock(p);
-       if (task_will_free_mem(p)) {
-               mark_oom_victim(p);
-               wake_oom_reaper(p);
-               task_unlock(p);
-               put_task_struct(p);
-               return;
-       }
-       task_unlock(p);
-
-       if (__ratelimit(&oom_rs))
-               dump_header(oc, p);
-
-       pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
-               message, task_pid_nr(p), p->comm, points);
-
-       /*
-        * If any of p's children has a different mm and is eligible for kill,
-        * the one with the highest oom_badness() score is sacrificed for its
-        * parent.  This attempts to lose the minimal amount of work done while
-        * still freeing memory.
-        */
-       read_lock(&tasklist_lock);
-       for_each_thread(p, t) {
-               list_for_each_entry(child, &t->children, sibling) {
-                       unsigned int child_points;
-
-                       if (process_shares_mm(child, p->mm))
-                               continue;
-                       /*
-                        * oom_badness() returns 0 if the thread is unkillable
-                        */
-                       child_points = oom_badness(child,
-                               oc->memcg, oc->nodemask, oc->totalpages);
-                       if (child_points > victim_points) {
-                               put_task_struct(victim);
-                               victim = child;
-                               victim_points = child_points;
-                               get_task_struct(victim);
-                       }
-               }
-       }
-       read_unlock(&tasklist_lock);
-
        p = find_lock_task_mm(victim);
        if (!p) {
                put_task_struct(victim);
@@ -978,6 +908,99 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
 }
 #undef K
 
+/*
+ * Kill provided task unless it's secured by setting
+ * oom_score_adj to OOM_SCORE_ADJ_MIN.
+ */
+static int oom_kill_memcg_member(struct task_struct *task, void *unused)
+{
+       if (task->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
+               get_task_struct(task);
+               __oom_kill_process(task);
+       }
+       return 0;
+}
+
+static void oom_kill_process(struct oom_control *oc, const char *message)
+{
+       struct task_struct *p = oc->chosen;
+       unsigned int points = oc->chosen_points;
+       struct task_struct *victim = p;
+       struct task_struct *child;
+       struct task_struct *t;
+       struct mem_cgroup *oom_group;
+       unsigned int victim_points = 0;
+       static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
+                                             DEFAULT_RATELIMIT_BURST);
+
+       /*
+        * If the task is already exiting, don't alarm the sysadmin or kill
+        * its children or threads, just give it access to memory reserves
+        * so it can die quickly
+        */
+       task_lock(p);
+       if (task_will_free_mem(p)) {
+               mark_oom_victim(p);
+               wake_oom_reaper(p);
+               task_unlock(p);
+               put_task_struct(p);
+               return;
+       }
+       task_unlock(p);
+
+       if (__ratelimit(&oom_rs))
+               dump_header(oc, p);
+
+       pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
+               message, task_pid_nr(p), p->comm, points);
+
+       /*
+        * If any of p's children has a different mm and is eligible for kill,
+        * the one with the highest oom_badness() score is sacrificed for its
+        * parent.  This attempts to lose the minimal amount of work done while
+        * still freeing memory.
+        */
+       read_lock(&tasklist_lock);
+       for_each_thread(p, t) {
+               list_for_each_entry(child, &t->children, sibling) {
+                       unsigned int child_points;
+
+                       if (process_shares_mm(child, p->mm))
+                               continue;
+                       /*
+                        * oom_badness() returns 0 if the thread is unkillable
+                        */
+                       child_points = oom_badness(child,
+                               oc->memcg, oc->nodemask, oc->totalpages);
+                       if (child_points > victim_points) {
+                               put_task_struct(victim);
+                               victim = child;
+                               victim_points = child_points;
+                               get_task_struct(victim);
+                       }
+               }
+       }
+       read_unlock(&tasklist_lock);
+
+       /*
+        * Do we need to kill the entire memory cgroup?
+        * Or even one of the ancestor memory cgroups?
+        * Check this out before killing the victim task.
+        */
+       oom_group = mem_cgroup_get_oom_group(victim, oc->memcg);
+
+       __oom_kill_process(victim);
+
+       /*
+        * If necessary, kill all tasks in the selected memory cgroup.
+        */
+       if (oom_group) {
+               mem_cgroup_print_oom_group(oom_group);
+               mem_cgroup_scan_tasks(oom_group, oom_kill_memcg_member, NULL);
+               mem_cgroup_put(oom_group);
+       }
+}
+
 /*
  * Determines whether the kernel must panic because of the panic_on_oom sysctl.
  */
index 15ea511fb41c56bc16ae9b48e3b49d4b5e937717..c677c1506d73da040784c913a7035f725265e4b4 100644 (file)
@@ -2909,10 +2909,10 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)
        if (!static_branch_likely(&vm_numa_stat_key))
                return;
 
-       if (z->node != numa_node_id())
+       if (zone_to_nid(z) != numa_node_id())
                local_stat = NUMA_OTHER;
 
-       if (z->node == preferred_zone->node)
+       if (zone_to_nid(z) == zone_to_nid(preferred_zone))
                __inc_numa_state(z, NUMA_HIT);
        else {
                __inc_numa_state(z, NUMA_MISS);
@@ -5278,7 +5278,7 @@ int local_memory_node(int node)
        z = first_zones_zonelist(node_zonelist(node, GFP_KERNEL),
                                   gfp_zone(GFP_KERNEL),
                                   NULL);
-       return z->zone->node;
+       return zone_to_nid(z->zone);
 }
 #endif
 
@@ -6120,7 +6120,7 @@ static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned l
        return usemapsize / 8;
 }
 
-static void __init setup_usemap(struct pglist_data *pgdat,
+static void __ref setup_usemap(struct pglist_data *pgdat,
                                struct zone *zone,
                                unsigned long zone_start_pfn,
                                unsigned long zonesize)
@@ -6140,7 +6140,7 @@ static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone,
 #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
 
 /* Initialise the number of pages represented by NR_PAGEBLOCK_BITS */
-void __paginginit set_pageblock_order(void)
+void __init set_pageblock_order(void)
 {
        unsigned int order;
 
@@ -6168,14 +6168,14 @@ void __paginginit set_pageblock_order(void)
  * include/linux/pageblock-flags.h for the values of pageblock_order based on
  * the kernel config
  */
-void __paginginit set_pageblock_order(void)
+void __init set_pageblock_order(void)
 {
 }
 
 #endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */
 
-static unsigned long __paginginit calc_memmap_size(unsigned long spanned_pages,
-                                                  unsigned long present_pages)
+static unsigned long __init calc_memmap_size(unsigned long spanned_pages,
+                                               unsigned long present_pages)
 {
        unsigned long pages = spanned_pages;
 
@@ -6194,39 +6194,99 @@ static unsigned long __paginginit calc_memmap_size(unsigned long spanned_pages,
        return PAGE_ALIGN(pages * sizeof(struct page)) >> PAGE_SHIFT;
 }
 
-/*
- * Set up the zone data structures:
- *   - mark all pages reserved
- *   - mark all memory queues empty
- *   - clear the memory bitmaps
- *
- * NOTE: pgdat should get zeroed by caller.
- */
-static void __paginginit free_area_init_core(struct pglist_data *pgdat)
-{
-       enum zone_type j;
-       int nid = pgdat->node_id;
-
-       pgdat_resize_init(pgdat);
 #ifdef CONFIG_NUMA_BALANCING
+static void pgdat_init_numabalancing(struct pglist_data *pgdat)
+{
        spin_lock_init(&pgdat->numabalancing_migrate_lock);
        pgdat->numabalancing_migrate_nr_pages = 0;
        pgdat->numabalancing_migrate_next_window = jiffies;
+}
+#else
+static void pgdat_init_numabalancing(struct pglist_data *pgdat) {}
 #endif
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static void pgdat_init_split_queue(struct pglist_data *pgdat)
+{
        spin_lock_init(&pgdat->split_queue_lock);
        INIT_LIST_HEAD(&pgdat->split_queue);
        pgdat->split_queue_len = 0;
+}
+#else
+static void pgdat_init_split_queue(struct pglist_data *pgdat) {}
 #endif
-       init_waitqueue_head(&pgdat->kswapd_wait);
-       init_waitqueue_head(&pgdat->pfmemalloc_wait);
+
 #ifdef CONFIG_COMPACTION
+static void pgdat_init_kcompactd(struct pglist_data *pgdat)
+{
        init_waitqueue_head(&pgdat->kcompactd_wait);
+}
+#else
+static void pgdat_init_kcompactd(struct pglist_data *pgdat) {}
 #endif
+
+static void __meminit pgdat_init_internals(struct pglist_data *pgdat)
+{
+       pgdat_resize_init(pgdat);
+
+       pgdat_init_numabalancing(pgdat);
+       pgdat_init_split_queue(pgdat);
+       pgdat_init_kcompactd(pgdat);
+
+       init_waitqueue_head(&pgdat->kswapd_wait);
+       init_waitqueue_head(&pgdat->pfmemalloc_wait);
+
        pgdat_page_ext_init(pgdat);
        spin_lock_init(&pgdat->lru_lock);
        lruvec_init(node_lruvec(pgdat));
+}
+
+static void __meminit zone_init_internals(struct zone *zone, enum zone_type idx, int nid,
+                                                       unsigned long remaining_pages)
+{
+       zone->managed_pages = remaining_pages;
+       zone_set_nid(zone, nid);
+       zone->name = zone_names[idx];
+       zone->zone_pgdat = NODE_DATA(nid);
+       spin_lock_init(&zone->lock);
+       zone_seqlock_init(zone);
+       zone_pcp_init(zone);
+}
+
+/*
+ * Set up the zone data structures
+ * - init pgdat internals
+ * - init all zones belonging to this node
+ *
+ * NOTE: this function is only called during memory hotplug
+ */
+#ifdef CONFIG_MEMORY_HOTPLUG
+void __ref free_area_init_core_hotplug(int nid)
+{
+       enum zone_type z;
+       pg_data_t *pgdat = NODE_DATA(nid);
 
+       pgdat_init_internals(pgdat);
+       for (z = 0; z < MAX_NR_ZONES; z++)
+               zone_init_internals(&pgdat->node_zones[z], z, nid, 0);
+}
+#endif
+
+/*
+ * Set up the zone data structures:
+ *   - mark all pages reserved
+ *   - mark all memory queues empty
+ *   - clear the memory bitmaps
+ *
+ * NOTE: pgdat should get zeroed by caller.
+ * NOTE: this function is only called during early init.
+ */
+static void __init free_area_init_core(struct pglist_data *pgdat)
+{
+       enum zone_type j;
+       int nid = pgdat->node_id;
+
+       pgdat_init_internals(pgdat);
        pgdat->per_cpu_nodestats = &boot_nodestats;
 
        for (j = 0; j < MAX_NR_ZONES; j++) {
@@ -6274,15 +6334,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                 * when the bootmem allocator frees pages into the buddy system.
                 * And all highmem pages will be managed by the buddy system.
                 */
-               zone->managed_pages = freesize;
-#ifdef CONFIG_NUMA
-               zone->node = nid;
-#endif
-               zone->name = zone_names[j];
-               zone->zone_pgdat = pgdat;
-               spin_lock_init(&zone->lock);
-               zone_seqlock_init(zone);
-               zone_pcp_init(zone);
+               zone_init_internals(zone, j, nid, freesize);
 
                if (!size)
                        continue;
@@ -6342,8 +6394,24 @@ static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
 static void __ref alloc_node_mem_map(struct pglist_data *pgdat) { }
 #endif /* CONFIG_FLAT_NODE_MEM_MAP */
 
-void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
-               unsigned long node_start_pfn, unsigned long *zholes_size)
+#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+static inline void pgdat_set_deferred_range(pg_data_t *pgdat)
+{
+       /*
+        * We start only with one section of pages, more pages are added as
+        * needed until the rest of deferred pages are initialized.
+        */
+       pgdat->static_init_pgcnt = min_t(unsigned long, PAGES_PER_SECTION,
+                                               pgdat->node_spanned_pages);
+       pgdat->first_deferred_pfn = ULONG_MAX;
+}
+#else
+static inline void pgdat_set_deferred_range(pg_data_t *pgdat) {}
+#endif
+
+void __init free_area_init_node(int nid, unsigned long *zones_size,
+                                  unsigned long node_start_pfn,
+                                  unsigned long *zholes_size)
 {
        pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long start_pfn = 0;
@@ -6367,16 +6435,8 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
                                  zones_size, zholes_size);
 
        alloc_node_mem_map(pgdat);
+       pgdat_set_deferred_range(pgdat);
 
-#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
-       /*
-        * We start only with one section of pages, more pages are added as
-        * needed until the rest of deferred pages are initialized.
-        */
-       pgdat->static_init_pgcnt = min_t(unsigned long, PAGES_PER_SECTION,
-                                        pgdat->node_spanned_pages);
-       pgdat->first_deferred_pfn = ULONG_MAX;
-#endif
        free_area_init_core(pgdat);
 }
 
@@ -6388,7 +6448,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
  * may be accessed (for example page_to_pfn() on some configuration accesses
  * flags). We must explicitly zero those struct pages.
  */
-void __paginginit zero_resv_unavail(void)
+void __init zero_resv_unavail(void)
 {
        phys_addr_t start, end;
        unsigned long pfn;
index 0b6480979ac78147d4a3fe33d8aded2d5e9a1a75..a749d4d96e3ec72baa7da9c325230855243e0bfa 100644 (file)
@@ -169,6 +169,14 @@ static LIST_HEAD(pcpu_map_extend_chunks);
  */
 int pcpu_nr_empty_pop_pages;
 
+/*
+ * The number of populated pages in use by the allocator, protected by
+ * pcpu_lock.  This number is kept per a unit per chunk (i.e. when a page gets
+ * allocated/deallocated, it is allocated/deallocated in all units of a chunk
+ * and increments/decrements this count by 1).
+ */
+static unsigned long pcpu_nr_populated;
+
 /*
  * Balance work is used to populate or destroy chunks asynchronously.  We
  * try to keep the number of populated free pages between
@@ -1232,6 +1240,7 @@ static void pcpu_chunk_populated(struct pcpu_chunk *chunk, int page_start,
 
        bitmap_set(chunk->populated, page_start, nr);
        chunk->nr_populated += nr;
+       pcpu_nr_populated += nr;
 
        if (!for_alloc) {
                chunk->nr_empty_pop_pages += nr;
@@ -1260,6 +1269,7 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk,
        chunk->nr_populated -= nr;
        chunk->nr_empty_pop_pages -= nr;
        pcpu_nr_empty_pop_pages -= nr;
+       pcpu_nr_populated -= nr;
 }
 
 /*
@@ -2176,6 +2186,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
        pcpu_nr_empty_pop_pages = pcpu_first_chunk->nr_empty_pop_pages;
        pcpu_chunk_relocate(pcpu_first_chunk, -1);
 
+       /* include all regions of the first chunk */
+       pcpu_nr_populated += PFN_DOWN(size_sum);
+
        pcpu_stats_chunk_alloc();
        trace_percpu_create_chunk(base_addr);
 
@@ -2745,6 +2758,22 @@ void __init setup_per_cpu_areas(void)
 
 #endif /* CONFIG_SMP */
 
+/*
+ * pcpu_nr_pages - calculate total number of populated backing pages
+ *
+ * This reflects the number of pages populated to back chunks.  Metadata is
+ * excluded in the number exposed in meminfo as the number of backing pages
+ * scales with the number of cpus and can quickly outweigh the memory used for
+ * metadata.  It also keeps this calculation nice and simple.
+ *
+ * RETURNS:
+ * Total number of populated backing pages in use by the allocator.
+ */
+unsigned long pcpu_nr_pages(void)
+{
+       return pcpu_nr_populated * pcpu_nr_units;
+}
+
 /*
  * Percpu allocator is initialized early during boot when neither slab or
  * workqueue is available.  Plug async management until everything is up
index c48c79018a7c0c7bad72ac3fda1584280267b210..fb04baacc9fa2814924b2367c854055f4c2de723 100644 (file)
@@ -1421,7 +1421,6 @@ static void shmem_pseudo_vma_init(struct vm_area_struct *vma,
                struct shmem_inode_info *info, pgoff_t index)
 {
        /* Create a pseudo vma that just contains the policy */
-       memset(vma, 0, sizeof(*vma));
        vma_init(vma, NULL);
        /* Bias interleave by inode number to distribute better across nodes */
        vma->vm_pgoff = index + info->vfs_inode.i_ino;
index 008ccb22fee6c3057fffa1fd3f0713767614cbfb..63a7b4563a57ee3367b8963b1219323a4d3b28c9 100644 (file)
@@ -269,8 +269,8 @@ static int refill_swap_slots_cache(struct swap_slots_cache *cache)
 
        cache->cur = 0;
        if (swap_slot_cache_active)
-               cache->nr = get_swap_pages(SWAP_SLOTS_CACHE_SIZE, false,
-                                          cache->slots);
+               cache->nr = get_swap_pages(SWAP_SLOTS_CACHE_SIZE,
+                                          cache->slots, 1);
 
        return cache->nr;
 }
@@ -316,7 +316,7 @@ swp_entry_t get_swap_page(struct page *page)
 
        if (PageTransHuge(page)) {
                if (IS_ENABLED(CONFIG_THP_SWAP))
-                       get_swap_pages(1, true, &entry);
+                       get_swap_pages(1, &entry, HPAGE_PMD_NR);
                goto out;
        }
 
@@ -350,7 +350,7 @@ repeat:
                        goto out;
        }
 
-       get_swap_pages(1, false, &entry);
+       get_swap_pages(1, &entry, 1);
 out:
        if (mem_cgroup_try_charge_swap(page, entry)) {
                put_swap_page(page, entry);
index 8837b22c848d069262653318a69a542b6ddf34dd..d954b71c4f9c2e842e142713e1a921addb6a4c9d 100644 (file)
@@ -204,8 +204,16 @@ static void discard_swap_cluster(struct swap_info_struct *si,
 
 #ifdef CONFIG_THP_SWAP
 #define SWAPFILE_CLUSTER       HPAGE_PMD_NR
+
+#define swap_entry_size(size)  (size)
 #else
 #define SWAPFILE_CLUSTER       256
+
+/*
+ * Define swap_entry_size() as constant to let compiler to optimize
+ * out some code if !CONFIG_THP_SWAP
+ */
+#define swap_entry_size(size)  1
 #endif
 #define LATENCY_LIMIT          256
 
@@ -269,7 +277,9 @@ static inline void cluster_set_null(struct swap_cluster_info *info)
 
 static inline bool cluster_is_huge(struct swap_cluster_info *info)
 {
-       return info->flags & CLUSTER_FLAG_HUGE;
+       if (IS_ENABLED(CONFIG_THP_SWAP))
+               return info->flags & CLUSTER_FLAG_HUGE;
+       return false;
 }
 
 static inline void cluster_clear_huge(struct swap_cluster_info *info)
@@ -296,13 +306,18 @@ static inline void unlock_cluster(struct swap_cluster_info *ci)
                spin_unlock(&ci->lock);
 }
 
+/*
+ * Determine the locking method in use for this device.  Return
+ * swap_cluster_info if SSD-style cluster-based locking is in place.
+ */
 static inline struct swap_cluster_info *lock_cluster_or_swap_info(
-       struct swap_info_struct *si,
-       unsigned long offset)
+               struct swap_info_struct *si, unsigned long offset)
 {
        struct swap_cluster_info *ci;
 
+       /* Try to use fine-grained SSD-style locking if available: */
        ci = lock_cluster(si, offset);
+       /* Otherwise, fall back to traditional, coarse locking: */
        if (!ci)
                spin_lock(&si->lock);
 
@@ -863,7 +878,6 @@ no_page:
        return n_ret;
 }
 
-#ifdef CONFIG_THP_SWAP
 static int swap_alloc_cluster(struct swap_info_struct *si, swp_entry_t *slot)
 {
        unsigned long idx;
@@ -871,6 +885,15 @@ static int swap_alloc_cluster(struct swap_info_struct *si, swp_entry_t *slot)
        unsigned long offset, i;
        unsigned char *map;
 
+       /*
+        * Should not even be attempting cluster allocations when huge
+        * page swap is disabled.  Warn and fail the allocation.
+        */
+       if (!IS_ENABLED(CONFIG_THP_SWAP)) {
+               VM_WARN_ON_ONCE(1);
+               return 0;
+       }
+
        if (cluster_list_empty(&si->free_clusters))
                return 0;
 
@@ -901,13 +924,6 @@ static void swap_free_cluster(struct swap_info_struct *si, unsigned long idx)
        unlock_cluster(ci);
        swap_range_free(si, offset, SWAPFILE_CLUSTER);
 }
-#else
-static int swap_alloc_cluster(struct swap_info_struct *si, swp_entry_t *slot)
-{
-       VM_WARN_ON_ONCE(1);
-       return 0;
-}
-#endif /* CONFIG_THP_SWAP */
 
 static unsigned long scan_swap_map(struct swap_info_struct *si,
                                   unsigned char usage)
@@ -924,18 +940,18 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
 
 }
 
-int get_swap_pages(int n_goal, bool cluster, swp_entry_t swp_entries[])
+int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_size)
 {
-       unsigned long nr_pages = cluster ? SWAPFILE_CLUSTER : 1;
+       unsigned long size = swap_entry_size(entry_size);
        struct swap_info_struct *si, *next;
        long avail_pgs;
        int n_ret = 0;
        int node;
 
        /* Only single cluster request supported */
-       WARN_ON_ONCE(n_goal > 1 && cluster);
+       WARN_ON_ONCE(n_goal > 1 && size == SWAPFILE_CLUSTER);
 
-       avail_pgs = atomic_long_read(&nr_swap_pages) / nr_pages;
+       avail_pgs = atomic_long_read(&nr_swap_pages) / size;
        if (avail_pgs <= 0)
                goto noswap;
 
@@ -945,7 +961,7 @@ int get_swap_pages(int n_goal, bool cluster, swp_entry_t swp_entries[])
        if (n_goal > avail_pgs)
                n_goal = avail_pgs;
 
-       atomic_long_sub(n_goal * nr_pages, &nr_swap_pages);
+       atomic_long_sub(n_goal * size, &nr_swap_pages);
 
        spin_lock(&swap_avail_lock);
 
@@ -972,14 +988,14 @@ start_over:
                        spin_unlock(&si->lock);
                        goto nextsi;
                }
-               if (cluster) {
+               if (size == SWAPFILE_CLUSTER) {
                        if (!(si->flags & SWP_FILE))
                                n_ret = swap_alloc_cluster(si, swp_entries);
                } else
                        n_ret = scan_swap_map_slots(si, SWAP_HAS_CACHE,
                                                    n_goal, swp_entries);
                spin_unlock(&si->lock);
-               if (n_ret || cluster)
+               if (n_ret || size == SWAPFILE_CLUSTER)
                        goto check_out;
                pr_debug("scan_swap_map of si %d failed to find offset\n",
                        si->type);
@@ -1005,7 +1021,7 @@ nextsi:
 
 check_out:
        if (n_ret < n_goal)
-               atomic_long_add((long)(n_goal - n_ret) * nr_pages,
+               atomic_long_add((long)(n_goal - n_ret) * size,
                                &nr_swap_pages);
 noswap:
        return n_ret;
@@ -1107,16 +1123,13 @@ static struct swap_info_struct *swap_info_get_cont(swp_entry_t entry,
        return p;
 }
 
-static unsigned char __swap_entry_free(struct swap_info_struct *p,
-                                      swp_entry_t entry, unsigned char usage)
+static unsigned char __swap_entry_free_locked(struct swap_info_struct *p,
+                                             unsigned long offset,
+                                             unsigned char usage)
 {
-       struct swap_cluster_info *ci;
-       unsigned long offset = swp_offset(entry);
        unsigned char count;
        unsigned char has_cache;
 
-       ci = lock_cluster_or_swap_info(p, offset);
-
        count = p->swap_map[offset];
 
        has_cache = count & SWAP_HAS_CACHE;
@@ -1144,6 +1157,17 @@ static unsigned char __swap_entry_free(struct swap_info_struct *p,
        usage = count | has_cache;
        p->swap_map[offset] = usage ? : SWAP_HAS_CACHE;
 
+       return usage;
+}
+
+static unsigned char __swap_entry_free(struct swap_info_struct *p,
+                                      swp_entry_t entry, unsigned char usage)
+{
+       struct swap_cluster_info *ci;
+       unsigned long offset = swp_offset(entry);
+
+       ci = lock_cluster_or_swap_info(p, offset);
+       usage = __swap_entry_free_locked(p, offset, usage);
        unlock_cluster_or_swap_info(p, ci);
 
        return usage;
@@ -1184,19 +1208,7 @@ void swap_free(swp_entry_t entry)
 /*
  * Called after dropping swapcache to decrease refcnt to swap entries.
  */
-static void swapcache_free(swp_entry_t entry)
-{
-       struct swap_info_struct *p;
-
-       p = _swap_info_get(entry);
-       if (p) {
-               if (!__swap_entry_free(p, entry, SWAP_HAS_CACHE))
-                       free_swap_slot(entry);
-       }
-}
-
-#ifdef CONFIG_THP_SWAP
-static void swapcache_free_cluster(swp_entry_t entry)
+void put_swap_page(struct page *page, swp_entry_t entry)
 {
        unsigned long offset = swp_offset(entry);
        unsigned long idx = offset / SWAPFILE_CLUSTER;
@@ -1205,42 +1217,48 @@ static void swapcache_free_cluster(swp_entry_t entry)
        unsigned char *map;
        unsigned int i, free_entries = 0;
        unsigned char val;
+       int size = swap_entry_size(hpage_nr_pages(page));
 
        si = _swap_info_get(entry);
        if (!si)
                return;
 
-       ci = lock_cluster(si, offset);
-       VM_BUG_ON(!cluster_is_huge(ci));
-       map = si->swap_map + offset;
-       for (i = 0; i < SWAPFILE_CLUSTER; i++) {
-               val = map[i];
-               VM_BUG_ON(!(val & SWAP_HAS_CACHE));
-               if (val == SWAP_HAS_CACHE)
-                       free_entries++;
-       }
-       if (!free_entries) {
-               for (i = 0; i < SWAPFILE_CLUSTER; i++)
-                       map[i] &= ~SWAP_HAS_CACHE;
+       ci = lock_cluster_or_swap_info(si, offset);
+       if (size == SWAPFILE_CLUSTER) {
+               VM_BUG_ON(!cluster_is_huge(ci));
+               map = si->swap_map + offset;
+               for (i = 0; i < SWAPFILE_CLUSTER; i++) {
+                       val = map[i];
+                       VM_BUG_ON(!(val & SWAP_HAS_CACHE));
+                       if (val == SWAP_HAS_CACHE)
+                               free_entries++;
+               }
+               cluster_clear_huge(ci);
+               if (free_entries == SWAPFILE_CLUSTER) {
+                       unlock_cluster_or_swap_info(si, ci);
+                       spin_lock(&si->lock);
+                       ci = lock_cluster(si, offset);
+                       memset(map, 0, SWAPFILE_CLUSTER);
+                       unlock_cluster(ci);
+                       mem_cgroup_uncharge_swap(entry, SWAPFILE_CLUSTER);
+                       swap_free_cluster(si, idx);
+                       spin_unlock(&si->lock);
+                       return;
+               }
        }
-       cluster_clear_huge(ci);
-       unlock_cluster(ci);
-       if (free_entries == SWAPFILE_CLUSTER) {
-               spin_lock(&si->lock);
-               ci = lock_cluster(si, offset);
-               memset(map, 0, SWAPFILE_CLUSTER);
-               unlock_cluster(ci);
-               mem_cgroup_uncharge_swap(entry, SWAPFILE_CLUSTER);
-               swap_free_cluster(si, idx);
-               spin_unlock(&si->lock);
-       } else if (free_entries) {
-               for (i = 0; i < SWAPFILE_CLUSTER; i++, entry.val++) {
-                       if (!__swap_entry_free(si, entry, SWAP_HAS_CACHE))
-                               free_swap_slot(entry);
+       for (i = 0; i < size; i++, entry.val++) {
+               if (!__swap_entry_free_locked(si, offset + i, SWAP_HAS_CACHE)) {
+                       unlock_cluster_or_swap_info(si, ci);
+                       free_swap_slot(entry);
+                       if (i == size - 1)
+                               return;
+                       lock_cluster_or_swap_info(si, offset);
                }
        }
+       unlock_cluster_or_swap_info(si, ci);
 }
 
+#ifdef CONFIG_THP_SWAP
 int split_swap_cluster(swp_entry_t entry)
 {
        struct swap_info_struct *si;
@@ -1255,19 +1273,7 @@ int split_swap_cluster(swp_entry_t entry)
        unlock_cluster(ci);
        return 0;
 }
-#else
-static inline void swapcache_free_cluster(swp_entry_t entry)
-{
-}
-#endif /* CONFIG_THP_SWAP */
-
-void put_swap_page(struct page *page, swp_entry_t entry)
-{
-       if (!PageTransHuge(page))
-               swapcache_free(entry);
-       else
-               swapcache_free_cluster(entry);
-}
+#endif
 
 static int swp_entry_cmp(const void *ent1, const void *ent2)
 {
@@ -1409,7 +1415,6 @@ out:
        return count;
 }
 
-#ifdef CONFIG_THP_SWAP
 static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
                                         swp_entry_t entry)
 {
@@ -1422,12 +1427,12 @@ static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
 
        ci = lock_cluster_or_swap_info(si, offset);
        if (!ci || !cluster_is_huge(ci)) {
-               if (map[roffset] != SWAP_HAS_CACHE)
+               if (swap_count(map[roffset]))
                        ret = true;
                goto unlock_out;
        }
        for (i = 0; i < SWAPFILE_CLUSTER; i++) {
-               if (map[offset + i] != SWAP_HAS_CACHE) {
+               if (swap_count(map[offset + i])) {
                        ret = true;
                        break;
                }
@@ -1442,7 +1447,7 @@ static bool page_swapped(struct page *page)
        swp_entry_t entry;
        struct swap_info_struct *si;
 
-       if (likely(!PageTransCompound(page)))
+       if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!PageTransCompound(page)))
                return page_swapcount(page) != 0;
 
        page = compound_head(page);
@@ -1466,10 +1471,8 @@ static int page_trans_huge_map_swapcount(struct page *page, int *total_mapcount,
        /* hugetlbfs shouldn't call it */
        VM_BUG_ON_PAGE(PageHuge(page), page);
 
-       if (likely(!PageTransCompound(page))) {
-               mapcount = atomic_read(&page->_mapcount) + 1;
-               if (total_mapcount)
-                       *total_mapcount = mapcount;
+       if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!PageTransCompound(page))) {
+               mapcount = page_trans_huge_mapcount(page, total_mapcount);
                if (PageSwapCache(page))
                        swapcount = page_swapcount(page);
                if (total_swapcount)
@@ -1516,26 +1519,6 @@ static int page_trans_huge_map_swapcount(struct page *page, int *total_mapcount,
 
        return map_swapcount;
 }
-#else
-#define swap_page_trans_huge_swapped(si, entry)        swap_swapcount(si, entry)
-#define page_swapped(page)                     (page_swapcount(page) != 0)
-
-static int page_trans_huge_map_swapcount(struct page *page, int *total_mapcount,
-                                        int *total_swapcount)
-{
-       int mapcount, swapcount = 0;
-
-       /* hugetlbfs shouldn't call it */
-       VM_BUG_ON_PAGE(PageHuge(page), page);
-
-       mapcount = page_trans_huge_mapcount(page, total_mapcount);
-       if (PageSwapCache(page))
-               swapcount = page_swapcount(page);
-       if (total_swapcount)
-               *total_swapcount = swapcount;
-       return mapcount + swapcount;
-}
-#endif
 
 /*
  * We can write to an anon page without COW if there are no other references
index 4375b1e9bd56142b0f0d0b94fbe63d4c067ed7f4..7e7d25504651d5b666f1706ff9a0743b3c62079f 100644 (file)
@@ -408,7 +408,8 @@ void register_shrinker_prepared(struct shrinker *shrinker)
        down_write(&shrinker_rwsem);
        list_add_tail(&shrinker->list, &shrinker_list);
 #ifdef CONFIG_MEMCG_KMEM
-       idr_replace(&shrinker_idr, shrinker, shrinker->id);
+       if (shrinker->flags & SHRINKER_MEMCG_AWARE)
+               idr_replace(&shrinker_idr, shrinker, shrinker->id);
 #endif
        up_write(&shrinker_rwsem);
 }
@@ -902,7 +903,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
                refcount = 2;
        if (!page_ref_freeze(page, refcount))
                goto cannot_free;
-       /* note: atomic_cmpxchg in page_freeze_refs provides the smp_rmb */
+       /* note: atomic_cmpxchg in page_ref_freeze provides the smp_rmb */
        if (unlikely(PageDirty(page))) {
                page_ref_unfreeze(page, refcount);
                goto cannot_free;
index 447857ffaf6be157841f8b0283d8ac67cb37dc5e..5219280bf7ff351a742db19e6a35748f77efbeb8 100755 (executable)
@@ -13,6 +13,7 @@ use POSIX;
 use File::Basename;
 use Cwd 'abs_path';
 use Term::ANSIColor qw(:constants);
+use Encode qw(decode encode);
 
 my $P = $0;
 my $D = dirname(abs_path($P));
@@ -240,11 +241,11 @@ $check_orig = $check;
 
 my $exit = 0;
 
+my $perl_version_ok = 1;
 if ($^V && $^V lt $minimum_perl_version) {
+       $perl_version_ok = 0;
        printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
-       if (!$ignore_perl_version) {
-               exit(1);
-       }
+       exit(1) if (!$ignore_perl_version);
 }
 
 #if no filenames are given, push '-' to read patch from stdin
@@ -346,9 +347,10 @@ our $Sparse        = qr{
                        __force|
                        __iomem|
                        __must_check|
-                       __init_refok|
                        __kprobes|
                        __ref|
+                       __refconst|
+                       __refdata|
                        __rcu|
                        __private
                }x;
@@ -847,6 +849,17 @@ sub is_maintained_obsolete {
        return $status =~ /obsolete/i;
 }
 
+sub is_SPDX_License_valid {
+       my ($license) = @_;
+
+       return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git"));
+
+       my $root_path = abs_path($root);
+       my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
+       return 0 if ($status ne "");
+       return 1;
+}
+
 my $camelcase_seeded = 0;
 sub seed_camelcase_includes {
        return if ($camelcase_seeded);
@@ -1026,11 +1039,11 @@ if (!$quiet) {
        hash_show_words(\%use_type, "Used");
        hash_show_words(\%ignore_type, "Ignored");
 
-       if ($^V lt 5.10.0) {
+       if (!$perl_version_ok) {
                print << "EOM"
 
 NOTE: perl $^V is not modern enough to detect all possible issues.
-      An upgrade to at least perl v5.10.0 is suggested.
+      An upgrade to at least perl $minimum_perl_version is suggested.
 EOM
        }
        if ($exit) {
@@ -2235,10 +2248,14 @@ sub process {
 
        our $clean = 1;
        my $signoff = 0;
+       my $author = '';
+       my $authorsignoff = 0;
        my $is_patch = 0;
+       my $is_binding_patch = -1;
        my $in_header_lines = $file ? 0 : 1;
        my $in_commit_log = 0;          #Scanning lines before patch
        my $has_commit_log = 0;         #Encountered lines before patch
+       my $commit_log_lines = 0;       #Number of commit log lines
        my $commit_log_possible_stack_dump = 0;
        my $commit_log_long_line = 0;
        my $commit_log_has_diff = 0;
@@ -2485,6 +2502,19 @@ sub process {
                                $check = $check_orig;
                        }
                        $checklicenseline = 1;
+
+                       if ($realfile !~ /^MAINTAINERS/) {
+                               my $last_binding_patch = $is_binding_patch;
+
+                               $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@;
+
+                               if (($last_binding_patch != -1) &&
+                                   ($last_binding_patch ^ $is_binding_patch)) {
+                                       WARN("DT_SPLIT_BINDING_PATCH",
+                                            "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.txt\n");
+                               }
+                       }
+
                        next;
                }
 
@@ -2496,6 +2526,18 @@ sub process {
 
                $cnt_lines++ if ($realcnt != 0);
 
+# Verify the existence of a commit log if appropriate
+# 2 is used because a $signature is counted in $commit_log_lines
+               if ($in_commit_log) {
+                       if ($line !~ /^\s*$/) {
+                               $commit_log_lines++;    #could be a $signature
+                       }
+               } elsif ($has_commit_log && $commit_log_lines < 2) {
+                       WARN("COMMIT_MESSAGE",
+                            "Missing commit description - Add an appropriate one\n");
+                       $commit_log_lines = 2;  #warn only once
+               }
+
 # Check if the commit log has what seems like a diff which can confuse patch
                if ($in_commit_log && !$commit_log_has_diff &&
                    (($line =~ m@^\s+diff\b.*a/[\w/]+@ &&
@@ -2517,10 +2559,24 @@ sub process {
                        }
                }
 
+# Check the patch for a From:
+               if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) {
+                       $author = $1;
+                       $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i);
+                       $author =~ s/"//g;
+               }
+
 # Check the patch for a signoff:
                if ($line =~ /^\s*signed-off-by:/i) {
                        $signoff++;
                        $in_commit_log = 0;
+                       if ($author ne '') {
+                               my $l = $line;
+                               $l =~ s/"//g;
+                               if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) {
+                                   $authorsignoff = 1;
+                               }
+                       }
                }
 
 # Check if MAINTAINERS is being updated.  If so, there's probably no need to
@@ -2960,8 +3016,14 @@ sub process {
 
                                if ($comment !~ /^$/ &&
                                    $rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) {
-                                       WARN("SPDX_LICENSE_TAG",
-                                            "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr);
+                                        WARN("SPDX_LICENSE_TAG",
+                                             "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr);
+                               } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) {
+                                        my $spdx_license = $1;
+                                        if (!is_SPDX_License_valid($spdx_license)) {
+                                                 WARN("SPDX_LICENSE_TAG",
+                                                      "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);
+                                        }
                                }
                        }
                }
@@ -3079,7 +3141,7 @@ sub process {
                }
 
 # check indentation starts on a tab stop
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) {
                        my $indent = length($1);
                        if ($indent % 8) {
@@ -3092,7 +3154,7 @@ sub process {
                }
 
 # check multi-line statement indentation matches previous line
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
                        $prevline =~ /^\+(\t*)(.*)$/;
                        my $oldindent = $1;
@@ -3781,6 +3843,26 @@ sub process {
                             "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr);
                }
 
+# check for unnecessary <signed> int declarations of short/long/long long
+               while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) {
+                       my $type = trim($1);
+                       next if ($type !~ /\bint\b/);
+                       next if ($type !~ /\b(?:short|long\s+long|long)\b/);
+                       my $new_type = $type;
+                       $new_type =~ s/\b\s*int\s*\b/ /;
+                       $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /;
+                       $new_type =~ s/^const\s+//;
+                       $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/);
+                       $new_type = "const $new_type" if ($type =~ /^const\b/);
+                       $new_type =~ s/\s+/ /g;
+                       $new_type = trim($new_type);
+                       if (WARN("UNNECESSARY_INT",
+                                "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/;
+                       }
+               }
+
 # check for static const char * arrays.
                if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
                        WARN("STATIC_CONST_CHAR_ARRAY",
@@ -3967,7 +4049,7 @@ sub process {
 
 # function brace can't be on same line, except for #defines of do while,
 # or if closed on same line
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ &&
                    $sline !~ /\#\s*define\b.*do\s*\{/ &&
                    $sline !~ /}/) {
@@ -4483,11 +4565,11 @@ sub process {
 
 #need space before brace following if, while, etc
                if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
-                   $line =~ /do\{/) {
+                   $line =~ /\b(?:else|do)\{/) {
                        if (ERROR("SPACING",
                                  "space required before the open brace '{'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/;
+                               $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/;
                        }
                }
 
@@ -4578,7 +4660,7 @@ sub process {
 # check for unnecessary parentheses around comparisons in if uses
 # when !drivers/staging or command-line uses --strict
                if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) &&
-                   $^V && $^V ge 5.10.0 && defined($stat) &&
+                   $perl_version_ok && defined($stat) &&
                    $stat =~ /(^.\s*if\s*($balanced_parens))/) {
                        my $if_stat = $1;
                        my $test = substr($2, 1, -1);
@@ -4615,7 +4697,7 @@ sub process {
 # return is not a function
                if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
                        my $spacing = $1;
-                       if ($^V && $^V ge 5.10.0 &&
+                       if ($perl_version_ok &&
                            $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) {
                                my $value = $1;
                                $value = deparenthesize($value);
@@ -4642,7 +4724,7 @@ sub process {
                }
 
 # if statements using unnecessary parentheses - ie: if ((foo == bar))
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\bif\s*((?:\(\s*){2,})/) {
                        my $openparens = $1;
                        my $count = $openparens =~ tr@\(@\(@;
@@ -4659,7 +4741,7 @@ sub process {
 #      avoid cases like "foo + BAR < baz"
 #      only fix matches surrounded by parentheses to avoid incorrect
 #      conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5"
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) {
                        my $lead = $1;
                        my $const = $2;
@@ -4949,6 +5031,7 @@ sub process {
                        if (defined $define_args && $define_args ne "") {
                                $define_args = substr($define_args, 1, length($define_args) - 2);
                                $define_args =~ s/\s*//g;
+                               $define_args =~ s/\\\+?//g;
                                @def_args = split(",", $define_args);
                        }
 
@@ -5084,7 +5167,7 @@ sub process {
 # do {} while (0) macro tests:
 # single-statement macros do not need to be enclosed in do while (0) loop,
 # macro should not end with a semicolon
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $realfile !~ m@/vmlinux.lds.h$@ &&
                    $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) {
                        my $ln = $linenr;
@@ -5330,15 +5413,28 @@ sub process {
                }
 
 # concatenated string without spaces between elements
-               if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) {
-                       CHK("CONCATENATED_STRING",
-                           "Concatenated strings should use spaces between elements\n" . $herecurr);
+               if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) {
+                       if (CHK("CONCATENATED_STRING",
+                               "Concatenated strings should use spaces between elements\n" . $herecurr) &&
+                           $fix) {
+                               while ($line =~ /($String)/g) {
+                                       my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+                                       $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/;
+                                       $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/;
+                               }
+                       }
                }
 
 # uncoalesced string fragments
                if ($line =~ /$String\s*"/) {
-                       WARN("STRING_FRAGMENTS",
-                            "Consecutive strings are generally better as a single string\n" . $herecurr);
+                       if (WARN("STRING_FRAGMENTS",
+                                "Consecutive strings are generally better as a single string\n" . $herecurr) &&
+                           $fix) {
+                               while ($line =~ /($String)(?=\s*")/g) {
+                                       my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]);
+                                       $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e;
+                               }
+                       }
                }
 
 # check for non-standard and hex prefixed decimal printf formats
@@ -5374,9 +5470,14 @@ sub process {
 
 # warn about #if 0
                if ($line =~ /^.\s*\#\s*if\s+0\b/) {
-                       CHK("REDUNDANT_CODE",
-                           "if this code is redundant consider removing it\n" .
-                               $herecurr);
+                       WARN("IF_0",
+                            "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr);
+               }
+
+# warn about #if 1
+               if ($line =~ /^.\s*\#\s*if\s+1\b/) {
+                       WARN("IF_1",
+                            "Consider removing the #if 1 and its #endif\n" . $herecurr);
                }
 
 # check for needless "if (<foo>) fn(<foo>)" uses
@@ -5447,7 +5548,7 @@ sub process {
                }
 
 # check for mask then right shift without a parentheses
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
                    $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so
                        WARN("MASK_THEN_SHIFT",
@@ -5455,7 +5556,7 @@ sub process {
                }
 
 # check for pointer comparisons to NULL
-               if ($^V && $^V ge 5.10.0) {
+               if ($perl_version_ok) {
                        while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) {
                                my $val = $1;
                                my $equal = "!";
@@ -5727,7 +5828,7 @@ sub process {
                }
 
 # Check for __attribute__ weak, or __weak declarations (may have link issues)
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ &&
                    ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ ||
                     $line =~ /\b__weak\b/)) {
@@ -5809,7 +5910,7 @@ sub process {
                }
 
 # check for vsprintf extension %p<foo> misuses
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
                    $1 !~ /^_*volatile_*$/) {
@@ -5856,7 +5957,7 @@ sub process {
                }
 
 # Check for misused memsets
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) {
 
@@ -5874,7 +5975,7 @@ sub process {
                }
 
 # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar)
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #                      if (WARN("PREFER_ETHER_ADDR_COPY",
@@ -5885,7 +5986,7 @@ sub process {
 #              }
 
 # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar)
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #                      WARN("PREFER_ETHER_ADDR_EQUAL",
@@ -5894,7 +5995,7 @@ sub process {
 
 # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr
 # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr
-#              if ($^V && $^V ge 5.10.0 &&
+#              if ($perl_version_ok &&
 #                  defined $stat &&
 #                  $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) {
 #
@@ -5916,7 +6017,7 @@ sub process {
 #              }
 
 # typecasts on min/max could be min_t/max_t
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
                        if (defined $2 || defined $7) {
@@ -5940,7 +6041,7 @@ sub process {
                }
 
 # check usleep_range arguments
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
                        my $min = $1;
@@ -5956,7 +6057,7 @@ sub process {
                }
 
 # check for naked sscanf
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /\bsscanf\b/ &&
                    ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ &&
@@ -5970,7 +6071,7 @@ sub process {
                }
 
 # check for simple sscanf that should be kstrto<foo>
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /\bsscanf\b/) {
                        my $lc = $stat =~ tr@\n@@;
@@ -6042,7 +6143,7 @@ sub process {
                }
 
 # check for function definitions
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) {
                        $context_function = $1;
@@ -6082,14 +6183,14 @@ sub process {
 
 # alloc style
 # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
                        CHK("ALLOC_SIZEOF_STRUCT",
                            "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
                }
 
 # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
                        my $oldfunc = $3;
@@ -6118,8 +6219,9 @@ sub process {
                }
 
 # check for krealloc arg reuse
-               if ($^V && $^V ge 5.10.0 &&
-                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
+               if ($perl_version_ok &&
+                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ &&
+                   $1 eq $3) {
                        WARN("KREALLOC_ARG_REUSE",
                             "Reusing the krealloc arg is almost always a bug\n" . $herecurr);
                }
@@ -6187,7 +6289,7 @@ sub process {
                }
 
 # check for switch/default statements without a break;
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
                        my $cnt = statement_rawlines($stat);
@@ -6251,6 +6353,13 @@ sub process {
                             "Avoid using bool as bitfield.  Prefer bool bitfields as unsigned int or u<8|16|32>\n" . $herecurr);
                }
 
+# check for bool use in .h files
+               if ($realfile =~ /\.h$/ &&
+                   $sline =~ /^.\s+bool\s*$Ident\s*(?::\s*d+\s*)?;/) {
+                       CHK("BOOL_MEMBER",
+                           "Avoid using bool structure members because of possible alignment issues - see: https://lkml.org/lkml/2017/11/21/384\n" . $herecurr);
+               }
+
 # check for semaphores initialized locked
                if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
                        WARN("CONSIDER_COMPLETION",
@@ -6297,7 +6406,7 @@ sub process {
                }
 
 # likely/unlikely comparisons similar to "(likely(foo) > 0)"
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) {
                        WARN("LIKELY_MISUSE",
                             "Using $1 should generally have parentheses around the comparison\n" . $herecurr);
@@ -6340,7 +6449,7 @@ sub process {
 # check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO>
 # and whether or not function naming is typical and if
 # DEVICE_ATTR permissions uses are unusual too
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) {
                        my $var = $1;
@@ -6400,7 +6509,7 @@ sub process {
 #   specific definition of not visible in sysfs.
 # o Ignore proc_create*(...) uses with a decimal 0 permission as that means
 #   use the default permissions
-               if ($^V && $^V ge 5.10.0 &&
+               if ($perl_version_ok &&
                    defined $stat &&
                    $line =~ /$mode_perms_search/) {
                        foreach my $entry (@mode_permission_funcs) {
@@ -6486,9 +6595,14 @@ sub process {
                ERROR("NOT_UNIFIED_DIFF",
                      "Does not appear to be a unified-diff format patch\n");
        }
-       if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
-               ERROR("MISSING_SIGN_OFF",
-                     "Missing Signed-off-by: line(s)\n");
+       if ($is_patch && $has_commit_log && $chk_signoff) {
+               if ($signoff == 0) {
+                       ERROR("MISSING_SIGN_OFF",
+                             "Missing Signed-off-by: line(s)\n");
+               } elsif (!$authorsignoff) {
+                       WARN("NO_AUTHOR_SIGN_OFF",
+                            "Missing Signed-off-by: line by nominal patch author '$author'\n");
+               }
        }
 
        print report_dump();
index c87fa734e3e195c70ee284da73e17b7b9d70193e..c1c088ef1420e68aa6a56bf041dd019aa82e64ee 100755 (executable)
@@ -48,6 +48,7 @@ my $output_roles = 0;
 my $output_rolestats = 1;
 my $output_section_maxlen = 50;
 my $scm = 0;
+my $tree = 1;
 my $web = 0;
 my $subsystem = 0;
 my $status = 0;
@@ -61,7 +62,7 @@ my $self_test = undef;
 my $version = 0;
 my $help = 0;
 my $find_maintainer_files = 0;
-
+my $maintainer_path;
 my $vcs_used = 0;
 
 my $exit = 0;
@@ -255,6 +256,7 @@ if (!GetOptions(
                'subsystem!' => \$subsystem,
                'status!' => \$status,
                'scm!' => \$scm,
+               'tree!' => \$tree,
                'web!' => \$web,
                'letters=s' => \$letters,
                'pattern-depth=i' => \$pattern_depth,
@@ -263,6 +265,7 @@ if (!GetOptions(
                'fe|file-emails!' => \$file_emails,
                'f|file' => \$from_filename,
                'find-maintainer-files' => \$find_maintainer_files,
+               'mpath|maintainer-path=s' => \$maintainer_path,
                'self-test:s' => \$self_test,
                'v|version' => \$version,
                'h|help|usage' => \$help,
@@ -319,7 +322,7 @@ if ($email &&
     die "$P: Please select at least 1 email option\n";
 }
 
-if (!top_of_kernel_tree($lk_path)) {
+if ($tree && !top_of_kernel_tree($lk_path)) {
     die "$P: The current directory does not appear to be "
        . "a linux kernel source tree.\n";
 }
@@ -384,26 +387,36 @@ sub find_ignore_git {
 read_all_maintainer_files();
 
 sub read_all_maintainer_files {
-    if (-d "${lk_path}MAINTAINERS") {
-        opendir(DIR, "${lk_path}MAINTAINERS") or die $!;
-        my @files = readdir(DIR);
-        closedir(DIR);
-        foreach my $file (@files) {
-            push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./);
-        }
-    }
-
-    if ($find_maintainer_files) {
-        find( { wanted => \&find_is_maintainer_file,
-                preprocess => \&find_ignore_git,
-                no_chdir => 1,
-        }, "${lk_path}");
+    my $path = "${lk_path}MAINTAINERS";
+    if (defined $maintainer_path) {
+       $path = $maintainer_path;
+       # Perl Cookbook tilde expansion if necessary
+       $path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex;
+    }
+
+    if (-d $path) {
+       $path .= '/' if ($path !~ m@/$@);
+       if ($find_maintainer_files) {
+           find( { wanted => \&find_is_maintainer_file,
+                   preprocess => \&find_ignore_git,
+                   no_chdir => 1,
+               }, "$path");
+       } else {
+           opendir(DIR, "$path") or die $!;
+           my @files = readdir(DIR);
+           closedir(DIR);
+           foreach my $file (@files) {
+               push(@mfiles, "$path$file") if ($file !~ /^\./);
+           }
+       }
+    } elsif (-f "$path") {
+       push(@mfiles, "$path");
     } else {
-        push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS";
+       die "$P: MAINTAINER file not found '$path'\n";
     }
-
+    die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0);
     foreach my $file (@mfiles) {
-        read_maintainer_file("$file");
+       read_maintainer_file("$file");
     }
 }
 
@@ -1031,13 +1044,14 @@ Other options:
   --sections => print all of the subsystem sections with pattern matches
   --letters => print all matching 'letter' types from all matching sections
   --mailmap => use .mailmap file (default: $email_use_mailmap)
+  --no-tree => run without a kernel tree
   --self-test => show potential issues with MAINTAINERS file content
   --version => show version
   --help => show this help information
 
 Default options:
-  [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0
-   --remove-duplicates --rolestats]
+  [--email --tree --nogit --git-fallback --m --r --n --l --multiline
+   --pattern-depth=0 --remove-duplicates --rolestats]
 
 Notes:
   Using "-f directory" may give unexpected results:
index 9a058cff49d4a1d8fec6c6151cedffffc03d8232..d2688d55c34b364f4bf277f6fdca82527f1c18e0 100644 (file)
@@ -10,6 +10,8 @@
 abandonning||abandoning
 abigious||ambiguous
 abitrate||arbitrate
+abord||abort
+aboslute||absolute
 abov||above
 abreviated||abbreviated
 absense||absence
@@ -25,6 +27,7 @@ accessable||accessible
 accesss||access
 accidentaly||accidentally
 accidentually||accidentally
+acclerated||accelerated
 accoding||according
 accomodate||accommodate
 accomodates||accommodates
@@ -58,12 +61,15 @@ addres||address
 adddress||address
 addreses||addresses
 addresss||address
+addrress||address
 aditional||additional
 aditionally||additionally
 aditionaly||additionally
 adminstrative||administrative
 adress||address
 adresses||addresses
+adrresses||addresses
+advertisment||advertisement
 adviced||advised
 afecting||affecting
 againt||against
@@ -100,6 +106,7 @@ alue||value
 ambigious||ambiguous
 amoung||among
 amout||amount
+amplifer||amplifier
 an union||a union
 an user||a user
 an userspace||a userspace
@@ -145,11 +152,15 @@ assistent||assistant
 assocation||association
 associcated||associated
 assotiated||associated
+asssert||assert
 assum||assume
 assumtpion||assumption
 asuming||assuming
 asycronous||asynchronous
 asynchnous||asynchronous
+asynchromous||asynchronous
+asymetric||asymmetric
+asymmeric||asymmetric
 atomatically||automatically
 atomicly||atomically
 atempt||attempt
@@ -172,6 +183,7 @@ avaible||available
 availabe||available
 availabled||available
 availablity||availability
+availaible||available
 availale||available
 availavility||availability
 availble||available
@@ -206,8 +218,11 @@ borad||board
 boundry||boundary
 brievely||briefly
 broadcat||broadcast
+bufufer||buffer
 cacluated||calculated
+caculate||calculate
 caculation||calculation
+cadidate||candidate
 calender||calendar
 calescing||coalescing
 calle||called
@@ -221,12 +236,14 @@ capabilty||capability
 capabitilies||capabilities
 capatibilities||capabilities
 capapbilities||capabilities
+caputure||capture
 carefuly||carefully
 cariage||carriage
 catagory||category
 cehck||check
 challange||challenge
 challanges||challenges
+chache||cache
 chanell||channel
 changable||changeable
 chanined||chained
@@ -240,6 +257,7 @@ charaters||characters
 charcter||character
 chcek||check
 chck||check
+checksumed||checksummed
 checksuming||checksumming
 childern||children
 childs||children
@@ -292,8 +310,10 @@ comunication||communication
 conbination||combination
 conditionaly||conditionally
 conected||connected
+conector||connector
 connecetd||connected
 configuartion||configuration
+configuation||configuration
 configuratoin||configuration
 configuraton||configuration
 configuretion||configuration
@@ -315,6 +335,7 @@ continous||continuous
 continously||continuously
 continueing||continuing
 contraints||constraints
+contruct||construct
 contol||control
 contoller||controller
 controled||controlled
@@ -343,6 +364,7 @@ dafault||default
 deafult||default
 deamon||daemon
 decompres||decompress
+decsribed||described
 decription||description
 dectected||detected
 defailt||default
@@ -379,6 +401,7 @@ desctiptor||descriptor
 desriptor||descriptor
 desriptors||descriptors
 destionation||destination
+destoried||destroyed
 destory||destroy
 destoryed||destroyed
 destorys||destroys
@@ -404,18 +427,25 @@ diffrentiate||differentiate
 difinition||definition
 dimesions||dimensions
 diplay||display
+directon||direction
 direectly||directly
+diregard||disregard
 disassocation||disassociation
 disapear||disappear
 disapeared||disappeared
 disappared||disappeared
+disbale||disable
+disbaled||disabled
 disble||disable
 disbled||disabled
 disconnet||disconnect
 discontinous||discontinuous
+disharge||discharge
 dispertion||dispersion
 dissapears||disappears
 distiction||distinction
+divisable||divisible
+divsiors||divisors
 docuentation||documentation
 documantation||documentation
 documentaion||documentation
@@ -427,6 +457,7 @@ downlad||download
 downlads||downloads
 druing||during
 dynmaic||dynamic
+eanable||enable
 easilly||easily
 ecspecially||especially
 edditable||editable
@@ -484,9 +515,12 @@ exprimental||experimental
 extened||extended
 extensability||extensibility
 extention||extension
+extenstion||extension
 extracter||extractor
+faield||failed
 falied||failed
 faild||failed
+failer||failure
 faill||fail
 failied||failed
 faillure||failure
@@ -520,6 +554,7 @@ forseeable||foreseeable
 forse||force
 fortan||fortran
 forwardig||forwarding
+frambuffer||framebuffer
 framming||framing
 framwork||framework
 frequncy||frequency
@@ -527,6 +562,7 @@ frome||from
 fucntion||function
 fuction||function
 fuctions||functions
+funcation||function
 funcion||function
 functionallity||functionality
 functionaly||functionally
@@ -540,6 +576,7 @@ futrue||future
 gaurenteed||guaranteed
 generiously||generously
 genereate||generate
+genereted||generated
 genric||generic
 globel||global
 grabing||grabbing
@@ -553,6 +590,7 @@ guarentee||guarantee
 halfs||halves
 hander||handler
 handfull||handful
+hanlde||handle
 hanled||handled
 happend||happened
 harware||hardware
@@ -561,6 +599,7 @@ helpfull||helpful
 hybernate||hibernate
 hierachy||hierarchy
 hierarchie||hierarchy
+homogenous||homogeneous
 howver||however
 hsould||should
 hypervior||hypervisor
@@ -568,6 +607,8 @@ hypter||hyper
 identidier||identifier
 iligal||illegal
 illigal||illegal
+illgal||illegal
+iomaped||iomapped
 imblance||imbalance
 immeadiately||immediately
 immedaite||immediate
@@ -618,10 +659,12 @@ initation||initiation
 initators||initiators
 initialiazation||initialization
 initializiation||initialization
+initialze||initialize
 initialzed||initialized
 initilization||initialization
 initilize||initialize
 inofficial||unofficial
+inrerface||interface
 insititute||institute
 instal||install
 instanciated||instantiated
@@ -657,6 +700,7 @@ intregral||integral
 intrrupt||interrupt
 intterrupt||interrupt
 intuative||intuitive
+inavlid||invalid
 invaid||invalid
 invald||invalid
 invalde||invalid
@@ -683,6 +727,7 @@ langauge||language
 langugage||language
 lauch||launch
 layed||laid
+legnth||length
 leightweight||lightweight
 lengh||length
 lenght||length
@@ -696,6 +741,7 @@ licenceing||licencing
 loggging||logging
 loggin||login
 logile||logfile
+loobpack||loopback
 loosing||losing
 losted||lost
 machinary||machinery
@@ -703,6 +749,7 @@ maintainance||maintenance
 maintainence||maintenance
 maintan||maintain
 makeing||making
+mailformed||malformed
 malplaced||misplaced
 malplace||misplace
 managable||manageable
@@ -710,6 +757,7 @@ managment||management
 mangement||management
 manoeuvering||maneuvering
 mappping||mapping
+matchs||matches
 mathimatical||mathematical
 mathimatic||mathematic
 mathimatics||mathematics
@@ -725,6 +773,7 @@ messsage||message
 messsages||messages
 micropone||microphone
 microprocesspr||microprocessor
+migrateable||migratable
 milliseonds||milliseconds
 minium||minimum
 minimam||minimum
@@ -741,6 +790,7 @@ missmatch||mismatch
 miximum||maximum
 mmnemonic||mnemonic
 mnay||many
+modfiy||modify
 modulues||modules
 momery||memory
 memomry||memory
@@ -777,6 +827,7 @@ notifed||notified
 numebr||number
 numner||number
 obtaion||obtain
+obusing||abusing
 occassionally||occasionally
 occationally||occasionally
 occurance||occurrence
@@ -787,6 +838,7 @@ occure||occurred
 occured||occurred
 occuring||occurring
 offet||offset
+offloded||offloaded
 omited||omitted
 omiting||omitting
 omitt||omit
@@ -829,6 +881,7 @@ parametes||parameters
 parametised||parametrised
 paramter||parameter
 paramters||parameters
+parmaters||parameters
 particuarly||particularly
 particularily||particularly
 partiton||partition
@@ -837,6 +890,7 @@ passin||passing
 pathes||paths
 pecularities||peculiarities
 peformance||performance
+peforming||performing
 peice||piece
 pendantic||pedantic
 peprocessor||preprocessor
@@ -846,6 +900,7 @@ peroid||period
 persistance||persistence
 persistant||persistent
 plalform||platform
+platfoem||platform
 platfrom||platform
 plattform||platform
 pleaes||please
@@ -858,6 +913,7 @@ posible||possible
 positon||position
 possibilites||possibilities
 powerfull||powerful
+preamle||preamble
 preample||preamble
 preapre||prepare
 preceeded||preceded
@@ -870,6 +926,7 @@ prefered||preferred
 prefferably||preferably
 premption||preemption
 prepaired||prepared
+preperation||preparation
 pressre||pressure
 primative||primitive
 princliple||principle
@@ -935,6 +992,7 @@ recommanded||recommended
 recyle||recycle
 redircet||redirect
 redirectrion||redirection
+redundacy||redundancy
 reename||rename
 refcounf||refcount
 refence||reference
@@ -945,6 +1003,7 @@ refernces||references
 refernnce||reference
 refrence||reference
 registerd||registered
+registeration||registration
 registeresd||registered
 registerred||registered
 registes||registers
@@ -973,7 +1032,9 @@ requirment||requirement
 requred||required
 requried||required
 requst||request
+reregisteration||reregistration
 reseting||resetting
+reseverd||reserved
 resizeable||resizable
 resouce||resource
 resouces||resources
@@ -982,6 +1043,7 @@ responce||response
 ressizes||resizes
 ressource||resource
 ressources||resources
+restesting||retesting
 retransmited||retransmitted
 retreived||retrieved
 retreive||retrieve
@@ -1006,6 +1068,7 @@ sacrifying||sacrificing
 safly||safely
 safty||safety
 savable||saveable
+scaleing||scaling
 scaned||scanned
 scaning||scanning
 scarch||search
@@ -1014,6 +1077,8 @@ searchs||searches
 secquence||sequence
 secund||second
 segement||segment
+semaphone||semaphore
+senario||scenario
 senarios||scenarios
 sentivite||sensitive
 separatly||separately
@@ -1025,9 +1090,13 @@ seperate||separate
 seperatly||separately
 seperator||separator
 sepperate||separate
+seqeunce||sequence
+seqeuncer||sequencer
+seqeuencer||sequencer
 sequece||sequence
 sequencial||sequential
 serveral||several
+servive||service
 setts||sets
 settting||setting
 shotdown||shutdown
@@ -1073,6 +1142,7 @@ standartization||standardization
 standart||standard
 staticly||statically
 stoped||stopped
+stoping||stopping
 stoppped||stopped
 straming||streaming
 struc||struct
@@ -1085,6 +1155,7 @@ subdirectoires||subdirectories
 suble||subtle
 substract||subtract
 submition||submission
+suceed||succeed
 succesfully||successfully
 succesful||successful
 successed||succeeded
@@ -1108,6 +1179,7 @@ surpressed||suppressed
 surpresses||suppresses
 susbsystem||subsystem
 suspeneded||suspended
+suspsend||suspend
 suspicously||suspiciously
 swaping||swapping
 switchs||switches
@@ -1122,6 +1194,7 @@ swtich||switch
 symetric||symmetric
 synax||syntax
 synchonized||synchronized
+synchronuously||synchronously
 syncronize||synchronize
 syncronized||synchronized
 syncronizing||synchronizing
@@ -1130,11 +1203,14 @@ syste||system
 sytem||system
 sythesis||synthesis
 taht||that
+tansmit||transmit
 targetted||targeted
 targetting||targeting
+taskelt||tasklet
 teh||the
 temorary||temporary
 temproarily||temporarily
+thead||thread
 therfore||therefore
 thier||their
 threds||threads
@@ -1143,11 +1219,14 @@ thresold||threshold
 throught||through
 troughput||throughput
 thses||these
+tiggers||triggers
 tiggered||triggered
 tipically||typically
+timeing||timing
 timout||timeout
 tmis||this
 torerable||tolerable
+traking||tracking
 tramsmitted||transmitted
 tramsmit||transmit
 tranasction||transaction
@@ -1162,6 +1241,7 @@ transormed||transformed
 trasfer||transfer
 trasmission||transmission
 treshold||threshold
+trigerred||triggered
 trigerring||triggering
 trun||turn
 tunning||tuning
@@ -1169,6 +1249,8 @@ ture||true
 tyep||type
 udpate||update
 uesd||used
+uknown||unknown
+usupported||unsupported
 uncommited||uncommitted
 unconditionaly||unconditionally
 underun||underrun
@@ -1181,11 +1263,14 @@ unexpeted||unexpected
 unexpexted||unexpected
 unfortunatelly||unfortunately
 unifiy||unify
+uniterrupted||uninterrupted
 unintialized||uninitialized
 unkmown||unknown
 unknonw||unknown
 unknow||unknown
 unkown||unknown
+unamed||unnamed
+uneeded||unneeded
 unneded||unneeded
 unneccecary||unnecessary
 unneccesary||unnecessary
@@ -1210,6 +1295,7 @@ usefull||useful
 usege||usage
 usera||users
 usualy||usually
+usupported||unsupported
 utilites||utilities
 utillities||utilities
 utilties||utilities
@@ -1233,7 +1319,9 @@ virtaul||virtual
 virtiual||virtual
 visiters||visitors
 vitual||virtual
+vunerable||vulnerable
 wakeus||wakeups
+wathdog||watchdog
 wating||waiting
 wiat||wait
 wether||whether
index 47cfff01d7ec01c522620aeef60643781577e5ed..736e78da1ab9d09271b2f34ace7a247c91fd5778 100644 (file)
@@ -48,14 +48,17 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
 static void __init do_security_initcalls(void)
 {
        int ret;
-       initcall_t *call;
-       call = __security_initcall_start;
+       initcall_t call;
+       initcall_entry_t *ce;
+
+       ce = __security_initcall_start;
        trace_initcall_level("security");
-       while (call < __security_initcall_end) {
-               trace_initcall_start((*call));
-               ret = (*call) ();
-               trace_initcall_finish((*call), ret);
-               call++;
+       while (ce < __security_initcall_end) {
+               call = initcall_from_entry(ce);
+               trace_initcall_start(call);
+               ret = call();
+               trace_initcall_finish(call, ret);
+               ce++;
        }
 }
 
index 74e5912e9f2efc771c3d3983d80318c666f542d7..82121a81681f7720a16709d659c6e7c53e6a3fa3 100644 (file)
@@ -9,3 +9,5 @@
 /proc-uptime-001
 /proc-uptime-002
 /read
+/self
+/thread-self
index db310eedc26874f76b43ab3034424b07adf24318..1c12c34cf85d801b09c6adbfe1fb1067c55283e8 100644 (file)
@@ -1,4 +1,5 @@
 CFLAGS += -Wall -O2 -Wno-unused-function
+CFLAGS += -D_GNU_SOURCE
 
 TEST_GEN_PROGS :=
 TEST_GEN_PROGS += fd-001-lookup
@@ -12,5 +13,7 @@ TEST_GEN_PROGS += proc-self-wchan
 TEST_GEN_PROGS += proc-uptime-001
 TEST_GEN_PROGS += proc-uptime-002
 TEST_GEN_PROGS += read
+TEST_GEN_PROGS += self
+TEST_GEN_PROGS += thread-self
 
 include ../lib.mk
index 4e178166fd84607d03ef81c67475d24eea018000..b7d57ea402376774b48715a84993acfe36165fff 100644 (file)
@@ -6,6 +6,18 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+static inline pid_t sys_getpid(void)
+{
+       return syscall(SYS_getpid);
+}
+
+static inline pid_t sys_gettid(void)
+{
+       return syscall(SYS_gettid);
+}
 
 static inline bool streq(const char *s1, const char *s2)
 {
diff --git a/tools/testing/selftests/proc/self.c b/tools/testing/selftests/proc/self.c
new file mode 100644 (file)
index 0000000..21c15a1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+// Test that /proc/self gives correct TGID.
+#undef NDEBUG
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "proc.h"
+
+int main(void)
+{
+       char buf1[64], buf2[64];
+       pid_t pid;
+       ssize_t rv;
+
+       pid = sys_getpid();
+       snprintf(buf1, sizeof(buf1), "%u", pid);
+
+       rv = readlink("/proc/self", buf2, sizeof(buf2));
+       assert(rv == strlen(buf1));
+       buf2[rv] = '\0';
+       assert(streq(buf1, buf2));
+
+       return 0;
+}
diff --git a/tools/testing/selftests/proc/thread-self.c b/tools/testing/selftests/proc/thread-self.c
new file mode 100644 (file)
index 0000000..4b23b39
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+// Test that /proc/thread-self gives correct TGID/PID.
+#undef NDEBUG
+#include <assert.h>
+#include <sched.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#include "proc.h"
+
+int f(void *arg)
+{
+       char buf1[64], buf2[64];
+       pid_t pid, tid;
+       ssize_t rv;
+
+       pid = sys_getpid();
+       tid = sys_gettid();
+       snprintf(buf1, sizeof(buf1), "%u/task/%u", pid, tid);
+
+       rv = readlink("/proc/thread-self", buf2, sizeof(buf2));
+       assert(rv == strlen(buf1));
+       buf2[rv] = '\0';
+       assert(streq(buf1, buf2));
+
+       if (arg)
+               exit(0);
+       return 0;
+}
+
+int main(void)
+{
+       const int PAGE_SIZE = sysconf(_SC_PAGESIZE);
+       pid_t pid;
+       void *stack;
+
+       /* main thread */
+       f((void *)0);
+
+       stack = mmap(NULL, 2 * PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+       assert(stack != MAP_FAILED);
+       /* side thread */
+       pid = clone(f, stack + PAGE_SIZE, CLONE_THREAD|CLONE_SIGHAND|CLONE_VM, (void *)1);
+       assert(pid > 0);
+       pause();
+
+       return 0;
+}
index 342c7bc9dc8c5d29441e27da5131d5312ea4bca8..af5ff83f6d7f85788de81f02eff7fa18d157bcf2 100644 (file)
@@ -1,6 +1,7 @@
 hugepage-mmap
 hugepage-shm
 map_hugetlb
+map_populate
 thuge-gen
 compaction_test
 mlock2-tests
index fdefa2295ddcd2255d794e620926fa3909dc770c..9881876d2aa0b065f0367a87ab184d41139360a3 100644 (file)
@@ -12,6 +12,7 @@ TEST_GEN_FILES += gup_benchmark
 TEST_GEN_FILES += hugepage-mmap
 TEST_GEN_FILES += hugepage-shm
 TEST_GEN_FILES += map_hugetlb
+TEST_GEN_FILES += map_populate
 TEST_GEN_FILES += mlock-random-test
 TEST_GEN_FILES += mlock2-tests
 TEST_GEN_FILES += on-fault-limit
diff --git a/tools/testing/selftests/vm/map_populate.c b/tools/testing/selftests/vm/map_populate.c
new file mode 100644 (file)
index 0000000..6b8aeaa
--- /dev/null
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Dmitry Safonov, Arista Networks
+ *
+ * MAP_POPULATE | MAP_PRIVATE should COW VMA pages.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef MMAP_SZ
+#define MMAP_SZ                4096
+#endif
+
+#define BUG_ON(condition, description)                                 \
+       do {                                                            \
+               if (condition) {                                        \
+                       fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \
+                               __LINE__, (description), strerror(errno)); \
+                       exit(1);                                        \
+               }                                                       \
+       } while (0)
+
+static int parent_f(int sock, unsigned long *smap, int child)
+{
+       int status, ret;
+
+       ret = read(sock, &status, sizeof(int));
+       BUG_ON(ret <= 0, "read(sock)");
+
+       *smap = 0x22222BAD;
+       ret = msync(smap, MMAP_SZ, MS_SYNC);
+       BUG_ON(ret, "msync()");
+
+       ret = write(sock, &status, sizeof(int));
+       BUG_ON(ret <= 0, "write(sock)");
+
+       waitpid(child, &status, 0);
+       BUG_ON(!WIFEXITED(status), "child in unexpected state");
+
+       return WEXITSTATUS(status);
+}
+
+static int child_f(int sock, unsigned long *smap, int fd)
+{
+       int ret, buf = 0;
+
+       smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_POPULATE, fd, 0);
+       BUG_ON(smap == MAP_FAILED, "mmap()");
+
+       BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file");
+
+       ret = write(sock, &buf, sizeof(int));
+       BUG_ON(ret <= 0, "write(sock)");
+
+       ret = read(sock, &buf, sizeof(int));
+       BUG_ON(ret <= 0, "read(sock)");
+
+       BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page");
+       BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted");
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int sock[2], child, ret;
+       FILE *ftmp;
+       unsigned long *smap;
+
+       ftmp = tmpfile();
+       BUG_ON(ftmp == 0, "tmpfile()");
+
+       ret = ftruncate(fileno(ftmp), MMAP_SZ);
+       BUG_ON(ret, "ftruncate()");
+
+       smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE,
+                       MAP_SHARED, fileno(ftmp), 0);
+       BUG_ON(smap == MAP_FAILED, "mmap()");
+
+       *smap = 0xdeadbabe;
+       /* Probably unnecessary, but let it be. */
+       ret = msync(smap, MMAP_SZ, MS_SYNC);
+       BUG_ON(ret, "msync()");
+
+       ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock);
+       BUG_ON(ret, "socketpair()");
+
+       child = fork();
+       BUG_ON(child == -1, "fork()");
+
+       if (child) {
+               ret = close(sock[0]);
+               BUG_ON(ret, "close()");
+
+               return parent_f(sock[1], smap, child);
+       }
+
+       ret = close(sock[1]);
+       BUG_ON(ret, "close()");
+
+       return child_f(sock[0], smap, fileno(ftmp));
+}
index 88cbe5575f0cf9e0d8f165ecbe27002a3c5ed8a1..584a91ae4a8f85e3c4dcf0baad7058abd8b3afea 100755 (executable)
@@ -167,6 +167,17 @@ else
        echo "[PASS]"
 fi
 
+echo "--------------------"
+echo "running map_populate"
+echo "--------------------"
+./map_populate
+if [ $? -ne 0 ]; then
+       echo "[FAIL]"
+       exitcode=1
+else
+       echo "[PASS]"
+fi
+
 echo "--------------------"
 echo "running mlock2-tests"
 echo "--------------------"
index 0df592c4f09f2da37ffbce22c24c9228f5a7f3bd..f986e31fa68cceaf8b16385e9869dc5e2bf55e4a 100644 (file)
@@ -140,9 +140,10 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm);
 static unsigned long long kvm_createvm_count;
 static unsigned long long kvm_active_vms;
 
-__weak void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
-               unsigned long start, unsigned long end)
+__weak int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+               unsigned long start, unsigned long end, bool blockable)
 {
+       return 0;
 }
 
 bool kvm_is_reserved_pfn(kvm_pfn_t pfn)
@@ -360,13 +361,15 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
        srcu_read_unlock(&kvm->srcu, idx);
 }
 
-static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
+static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
                                                    struct mm_struct *mm,
                                                    unsigned long start,
-                                                   unsigned long end)
+                                                   unsigned long end,
+                                                   bool blockable)
 {
        struct kvm *kvm = mmu_notifier_to_kvm(mn);
        int need_tlb_flush = 0, idx;
+       int ret;
 
        idx = srcu_read_lock(&kvm->srcu);
        spin_lock(&kvm->mmu_lock);
@@ -384,9 +387,11 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
 
        spin_unlock(&kvm->mmu_lock);
 
-       kvm_arch_mmu_notifier_invalidate_range(kvm, start, end);
+       ret = kvm_arch_mmu_notifier_invalidate_range(kvm, start, end, blockable);
 
        srcu_read_unlock(&kvm->srcu, idx);
+
+       return ret;
 }
 
 static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,