Merge branch 'akpm' (patches from Andrew)

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
  ...
This commit is contained in:
Linus Torvalds 2018-08-22 12:34:08 -07:00
commit cd9b44f907
182 changed files with 3198 additions and 2276 deletions

View 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

View file

@ -3041,8 +3041,9 @@
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>

View 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.
..............................................................................

View 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.
==============================================================

View 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.
==============================================================

View 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"

View 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);

View 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

View 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

View 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

View file

@ -23,11 +23,8 @@
* _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"

View 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

View file

@ -1,5 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef CONFIG_64BIT
#define KSYM_ALIGN 16
#endif
#include <asm-generic/export.h>

View 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)

View 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)) {

View 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

View 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;
}
/**

View 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 = {

View 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 = {

View 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;

View 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;
}
/*

View 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));

View 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.

View 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;
}

View 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 */

View 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,

View 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,

View 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);
}
}

View file

@ -1006,7 +1006,6 @@ static int rio_mport_transfer_ioctl(struct file *filp, void __user *arg)
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;

View 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,

View 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;

View 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 */

View file

@ -10,11 +10,9 @@
#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 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
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 @@ struct dentry *autofs_expire_direct(struct super_block *sb,
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);
}

View 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"

View 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);

View file

@ -50,10 +50,10 @@
*
* 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 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
* 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 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *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 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *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 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *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

View 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) {

View file

@ -1130,7 +1130,7 @@ static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used,
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);

View 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);

View 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 @@ int fat_count_free_clusters(struct super_block *sb)
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;
}

View 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 */
}

View 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 @@ static int __fat_write_inode(struct inode *inode, int wait)
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);

View 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);

View 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;

View 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 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name,
}
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;

View 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

View 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

View file

@ -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 */

View 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 = {

View 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);

View 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)

View 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 = {

View file

@ -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;
}

View 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) {

View 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;

View 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
};

View 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

View 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,

View 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;

View 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;

View 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 =

View 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

View 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

View 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;

View 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)

View 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;

View 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,65 +80,29 @@ 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;
*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;
}
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);
}
}
/*
* 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
/*
* If no highmem, we can assume [0...max_low_pfn) continuous range of memory
* 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 @@ kclist_add_private(unsigned long pfn, unsigned long nr_pages, void *arg)
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)
static int kcore_update_ram(void)
{
int sz;
LIST_HEAD(list);
LIST_HEAD(garbage);
int nphdr;
size_t phdrs_len, notes_len, data_offset;
struct kcore_list *tmp, *pos;
int ret = 0;
sz = sizeof(struct elf_note);
sz += roundup((strlen(en->name) + 1), 4);
sz += roundup(en->datasz, 4);
down_write(&kclist_lock);
if (!xchg(&kcore_need_update, 0))
goto out;
return sz;
} /* end notesize() */
/*****************************************************************************/
/*
* store a note in the header buffer
*/
static char *storenote(struct memelfnote *men, char *bufp)
{
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() */
/*
* 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;
/* 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;
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 process status */
notes[0].name = CORE_STR;
notes[0].type = NT_PRSTATUS;
notes[0].datasz = sizeof(struct elf_prstatus);
notes[0].data = &prstatus;
proc_root_kcore->size = get_kcore_size(&nphdr, &phdrs_len, &notes_len,
&data_offset);
memset(&prstatus, 0, sizeof(struct elf_prstatus));
out:
up_write(&kclist_lock);
list_for_each_entry_safe(pos, tmp, &garbage, list) {
list_del(&pos->list);
kfree(pos);
}
return ret;
}
nhdr->p_filesz = notesize(&notes[0]);
bufp = storenote(&notes[0], bufp);
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];
/* 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;
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);
}
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);
/* 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;
nhdr->p_filesz += notesize(&notes[2]);
bufp = storenote(&notes[2], bufp);
} /* end elf_kcore_store_hdr() */
/*****************************************************************************/
/*
* 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);
if (buflen == 0 || *fpos >= size) {
read_unlock(&kclist_lock);
return 0;
}
get_kcore_size(&nphdr, &phdrs_len, &notes_len, &data_offset);
phdrs_offset = sizeof(struct elfhdr);
notes_offset = phdrs_offset + phdrs_len;
/* trim buflen to not go beyond EOF */
if (buflen > size - *fpos)
buflen = size - *fpos;
/* 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,
};
/* 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;
tsz = min_t(size_t, buflen, sizeof(struct elfhdr) - *fpos);
if (copy_to_user(buffer, (char *)&ehdr + *fpos, tsz)) {
ret = -EFAULT;
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;
}
kfree(elf_buf);
buffer += tsz;
buflen -= tsz;
*fpos += tsz;
buffer += tsz;
acc += tsz;
}
/* leave now if filled buffer already */
if (buflen == 0)
return acc;
} else
read_unlock(&kclist_lock);
/* 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;
}
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++;
}
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;
}
/* 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);
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;
}

View 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",

View 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;

View 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 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
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;
}
#define SEQ_PUT_DEC(str, val) \
seq_put_decimal_ull_width(m, str, (val) >> 10, 8)
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");
}
/* 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");
}
static int show_smap(struct seq_file *m, void *v)
{
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);
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 0;
}
static int show_smaps_rollup(struct seq_file *m, void *v)
{
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 int show_pid_smap(struct seq_file *m, void *v)
{
return show_smap(m, v, 1);
}
static int show_tid_smap(struct seq_file *m, void *v)
{
return show_smap(m, v, 0);
}
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 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
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 */

View 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,
};

View 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",

View 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;

View 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));
}
}

View 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 @@ static int journal_read(struct super_block *sb)
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 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
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 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
}
/* 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;

View 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),

View 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;

View 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;
}

View 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);
}

View file

@ -910,7 +910,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
*/
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);
}

View 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)

View 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
@ -19,6 +17,16 @@
#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.

View 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

View 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);
}

View 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);

View 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(); \

View 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,

11
include/linux/crc64.h Normal file
View file

@ -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 */

View file

@ -18,12 +18,6 @@
#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(__KSYM_DEPS__)
#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)
#elif defined(__KSYM_DEPS__)
/*
* For fine grained build dependencies, we want to tell the build system

View file

@ -116,8 +116,24 @@
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;

View 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

View 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)

View file

@ -85,7 +85,23 @@
* 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))
/**
@ -110,13 +126,30 @@
# 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); \

View 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);

View 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)
{

View 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);

View 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);

View 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)
{

View 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,

View 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,

Some files were not shown because too many files have changed in this diff Show more