* [tip:core/documentation] Documentation/features/core: Add feature description and arch support status file for 'BPF-JIT'
From: tip-bot for Ingo Molnar @ 2015-06-03 11:20 UTC (permalink / raw)
To: linux-tip-commits
Cc: tglx, linux-api, corbet, torvalds, linux-kernel, josh, akpm,
mingo, linux-arch, hpa, peterz
Commit-ID: b07b6ecc01fa435d1c5d3fc50ee675ed36dd89d5
Gitweb: http://git.kernel.org/tip/b07b6ecc01fa435d1c5d3fc50ee675ed36dd89d5
Author: Ingo Molnar <mingo@kernel.org>
AuthorDate: Wed, 3 Jun 2015 12:37:44 +0200
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 3 Jun 2015 12:51:43 +0200
Documentation/features/core: Add feature description and arch support status file for 'BPF-JIT'
Cc: <linux-api@vger.kernel.org>
Cc: <linux-arch@vger.kernel.org>
Cc: <linux-kernel@vger.kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
.../features/core/{jump-labels => BPF-JIT}/arch-support.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/BPF-JIT/arch-support.txt
similarity index 85%
copy from Documentation/features/core/jump-labels/arch-support.txt
copy to Documentation/features/core/BPF-JIT/arch-support.txt
index 136868b..c1b4f91 100644
--- a/Documentation/features/core/jump-labels/arch-support.txt
+++ b/Documentation/features/core/BPF-JIT/arch-support.txt
@@ -1,7 +1,7 @@
#
-# Feature name: jump-labels
-# Kconfig: HAVE_ARCH_JUMP_LABEL
-# description: arch supports live patched, high efficiency branches
+# Feature name: BPF-JIT
+# Kconfig: HAVE_BPF_JIT
+# description: arch supports BPF JIT optimizations
#
-----------------------
| arch |status|
^ permalink raw reply related
* [tip:core/documentation] Documentation/features: Explain kernel feature descriptions and add visualization script
From: tip-bot for Ingo Molnar @ 2015-06-03 11:20 UTC (permalink / raw)
To: linux-tip-commits
Cc: peterz, linux-kernel, corbet, linux-arch, tglx, josh, torvalds,
hpa, mingo, akpm, linux-api
Commit-ID: 669f6f96c680a741257ada44a28b580df2e1fc25
Gitweb: http://git.kernel.org/tip/669f6f96c680a741257ada44a28b580df2e1fc25
Author: Ingo Molnar <mingo@kernel.org>
AuthorDate: Wed, 3 Jun 2015 12:39:26 +0200
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 3 Jun 2015 12:59:38 +0200
Documentation/features: Explain kernel feature descriptions and add visualization script
The previous patches added arch support matrices for more than 40 generic kernel features
that need per architecture support.
The structure of the feature descriptions is the following:
Each feature has its own directory under Documentation/features/subsystem_name/feature_name/,
and the arch-support.txt file shows its current arch porting status.
For example, lockdep support is shown the following way:
triton:~/tip> cat Documentation/features/locking/lockdep/arch-support.txt
#
# Feature name: lockdep
# Kconfig: LOCKDEP_SUPPORT
# description: arch supports the runtime locking correctness debug facility
#
-----------------------
| arch |status|
-----------------------
| alpha: | TODO |
| arc: | ok |
| arm: | ok |
| arm64: | ok |
| avr32: | ok |
| blackfin: | ok |
| c6x: | TODO |
| cris: | TODO |
| frv: | TODO |
| h8300: | TODO |
| hexagon: | ok |
| ia64: | TODO |
| m32r: | TODO |
| m68k: | TODO |
| metag: | ok |
| microblaze: | ok |
| mips: | ok |
| mn10300: | TODO |
| nios2: | TODO |
| openrisc: | TODO |
| parisc: | TODO |
| powerpc: | ok |
| s390: | ok |
| score: | ok |
| sh: | ok |
| sparc: | ok |
| tile: | ok |
| um: | ok |
| unicore32: | ok |
| x86: | ok |
| xtensa: | ok |
-----------------------
For generic kernel features that need architecture support, the
arch-support.txt file in each feature directory shows the arch
support matrix, for all upstream Linux architectures.
The meaning of entries in the tables is:
| ok | # feature supported by the architecture
|TODO| # feature not yet supported by the architecture
| .. | # feature cannot be supported by the hardware
This directory structure can be used in the future to add other
files - such as porting guides, testing description, etc.
The Documentation/features/ hierarchy may also include generic
kernel features that works on every architecture, in that case
the arch-support.txt file will list every architecture as
supported.
To list an architecture's unsupported features, just do something
like:
triton:~/tip> git grep -lE 'x86.*TODO' Documentation/features/*/*/arch-support.txt
Documentation/features/lib/strncasecmp/arch-support.txt
Documentation/features/time/arch-tick-broadcast/arch-support.txt
which will print the list of not yet supported features.
The Documentation/features/list-arch.sh script will print the current
support matrix of one architecture:
triton:~/tip> Documentation/features/list-arch.sh
#
# Kernel feature support matrix of the 'x86' architecture:
#
core/ BPF-JIT : ok | HAVE_BPF_JIT # arch supports BPF JIT optimizations
core/ generic-idle-thread : ok | GENERIC_SMP_IDLE_THREAD # arch makes use of the generic SMP idle thread facility
core/ jump-labels : ok | HAVE_ARCH_JUMP_LABEL # arch supports live patched, high efficiency branches
core/ tracehook : ok | HAVE_ARCH_TRACEHOOK # arch supports tracehook (ptrace) register handling APIs
debug/ gcov-profile-all : ok | ARCH_HAS_GCOV_PROFILE_ALL # arch supports whole-kernel GCOV code coverage profiling
debug/ KASAN : ok | HAVE_ARCH_KASAN # arch supports the KASAN runtime memory checker
debug/ kgdb : ok | HAVE_ARCH_KGDB # arch supports the kGDB kernel debugger
debug/ kprobes : ok | HAVE_KPROBES # arch supports live patched kernel probe
debug/ kprobes-on-ftrace : ok | HAVE_KPROBES_ON_FTRACE # arch supports combined kprobes and ftrace live patching
debug/ kretprobes : ok | HAVE_KRETPROBES # arch supports kernel function-return probes
debug/ optprobes : ok | HAVE_OPTPROBES # arch supports live patched optprobes
debug/ stackprotector : ok | HAVE_CC_STACKPROTECTOR # arch supports compiler driven stack overflow protection
debug/ uprobes : ok | ARCH_SUPPORTS_UPROBES # arch supports live patched user probes
debug/ user-ret-profiler : ok | HAVE_USER_RETURN_NOTIFIER # arch supports user-space return from system call profiler
io/ dma-api-debug : ok | HAVE_DMA_API_DEBUG # arch supports DMA debug facilities
io/ dma-contiguous : ok | HAVE_DMA_CONTIGUOUS # arch supports the DMA CMA (continuous memory allocator)
io/ dma_map_attrs : ok | HAVE_DMA_ATTRS # arch provides dma_*map*_attrs() APIs
io/ sg-chain : ok | ARCH_HAS_SG_CHAIN # arch supports chained scatter-gather lists
lib/ strncasecmp : TODO | __HAVE_ARCH_STRNCASECMP # arch provides an optimized strncasecmp() function
locking/ cmpxchg-local : ok | HAVE_CMPXCHG_LOCAL # arch supports the this_cpu_cmpxchg() API
locking/ lockdep : ok | LOCKDEP_SUPPORT # arch supports the runtime locking correctness debug facility
locking/ queued-rwlocks : ok | ARCH_USE_QUEUED_RWLOCKS # arch supports queued rwlocks
locking/ queued-spinlocks : ok | ARCH_USE_QUEUED_SPINLOCKS # arch supports queued spinlocks
locking/ rwsem-optimized : ok | Optimized asm/rwsem.h # arch provides optimized rwsem APIs
perf/ kprobes-event : ok | HAVE_REGS_AND_STACK_ACCESS_API # arch supports kprobes with perf events
perf/ perf-regs : ok | HAVE_PERF_REGS # arch supports perf events register access
perf/ perf-stackdump : ok | HAVE_PERF_USER_STACK_DUMP # arch supports perf events stack dumps
sched/ numa-balancing : ok | ARCH_SUPPORTS_NUMA_BALANCING # arch supports NUMA balancing
seccomp/ seccomp-filter : ok | HAVE_ARCH_SECCOMP_FILTER # arch supports seccomp filters
time/ arch-tick-broadcast : TODO | ARCH_HAS_TICK_BROADCAST # arch provides tick_broadcast()
time/ clockevents : ok | GENERIC_CLOCKEVENTS # arch support generic clock events
time/ context-tracking : ok | HAVE_CONTEXT_TRACKING # arch supports context tracking for NO_HZ_FULL
time/ irq-time-acct : ok | HAVE_IRQ_TIME_ACCOUNTING # arch supports precise IRQ time accounting
time/ modern-timekeeping : ok | !ARCH_USES_GETTIMEOFFSET # arch does not use arch_gettimeoffset() anymore
time/ virt-cpuacct : ok | HAVE_VIRT_CPU_ACCOUNTING # arch supports precise virtual CPU time accounting
vm/ ELF-ASLR : ok | ARCH_HAS_ELF_RANDOMIZE # arch randomizes the stack, heap and binary images of ELF binaries
vm/ huge-vmap : ok | HAVE_ARCH_HUGE_VMAP # arch supports the ioremap_pud_enabled() and ioremap_pmd_enabled() VM APIs
vm/ ioremap_prot : ok | HAVE_IOREMAP_PROT # arch has ioremap_prot()
vm/ numa-memblock : ok | HAVE_MEMBLOCK_NODE_MAP # arch supports NUMA aware memblocks
vm/ PG_uncached : ok | ARCH_USES_PG_UNCACHED # arch supports the PG_uncached page flag
vm/ pmdp_splitting_flush : ok | __HAVE_ARCH_PMDP_SPLITTING_FLUSH # arch supports the pmdp_splitting_flush() VM API
vm/ pte_special : ok | __HAVE_ARCH_PTE_SPECIAL # arch supports the pte_special()/pte_mkspecial() VM APIs
vm/ THP : ok | HAVE_ARCH_TRANSPARENT_HUGEPAGE # arch supports transparent hugepages
Cc: <linux-api@vger.kernel.org>
Cc: <linux-arch@vger.kernel.org>
Cc: <linux-kernel@vger.kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
Documentation/features/arch-support.txt | 11 +++++++++++
Documentation/features/list-arch.sh | 24 ++++++++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/Documentation/features/arch-support.txt b/Documentation/features/arch-support.txt
new file mode 100644
index 0000000..d22a109
--- /dev/null
+++ b/Documentation/features/arch-support.txt
@@ -0,0 +1,11 @@
+
+For generic kernel features that need architecture support, the
+arch-support.txt file in each feature directory shows the arch
+support matrix, for all upstream Linux architectures.
+
+The meaning of entries in the tables is:
+
+ | ok | # feature supported by the architecture
+ |TODO| # feature not yet supported by the architecture
+ | .. | # feature cannot be supported by the hardware
+
diff --git a/Documentation/features/list-arch.sh b/Documentation/features/list-arch.sh
new file mode 100755
index 0000000..6065124
--- /dev/null
+++ b/Documentation/features/list-arch.sh
@@ -0,0 +1,24 @@
+#
+# Small script that visualizes the kernel feature support status
+# of an architecture.
+#
+# (If no arguments are given then it will print the host architecture's status.)
+#
+
+ARCH=${1:-$(arch | sed 's/x86_64/x86/' | sed 's/i386/x86/')}
+
+cd $(dirname $0)
+echo "#"
+echo "# Kernel feature support matrix of the '$ARCH' architecture:"
+echo "#"
+
+for F in */*/arch-support.txt; do
+ SUBSYS=$(echo $F | cut -d/ -f1)
+ N=$(grep -h "^# Feature name:" $F | cut -c25-)
+ C=$(grep -h "^# Kconfig:" $F | cut -c25-)
+ D=$(grep -h "^# description:" $F | cut -c25-)
+ S=$(grep -hw $ARCH $F | cut -d\| -f3)
+
+ printf "%10s/%-22s:%s| %35s # %s\n" "$SUBSYS" "$N" "$S" "$C" "$D"
+done
+
^ permalink raw reply related
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 14:43 UTC (permalink / raw)
To: Oleg Nesterov
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150602182829.GA23449-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Tue, Jun 02, 2015 at 08:28:29PM +0200, Oleg Nesterov wrote:
> On 06/01, Tycho Andersen wrote:
> >
> > --- a/include/linux/seccomp.h
> > +++ b/include/linux/seccomp.h
> > @@ -25,6 +25,9 @@ struct seccomp_filter;
> > struct seccomp {
> > int mode;
> > struct seccomp_filter *filter;
> > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > + bool suspended;
> > +#endif
>
> Then afaics you need to change copy_seccomp() to clear ->suspended.
> At least if the child is not traced.
Yes, thank you.
> > @@ -691,6 +697,11 @@ u32 seccomp_phase1(struct seccomp_data *sd)
> > int this_syscall = sd ? sd->nr :
> > syscall_get_nr(current, task_pt_regs(current));
> >
> > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > + if (unlikely(current->seccomp.suspended))
> > + return SECCOMP_PHASE1_OK;
> > +#endif
> > +
>
> I am wondering if PTRACE_SUSPEND_SECCOMP can just clear/set TIF_SECCOMP.
> Of course, it is not that resume_seccomp() can simply do set_tsk_thread_flag,
> it should be more careful. And prctl_set_seccomp() paths will need some
> changes. Probably not, this would be more complex.
>
> So perhaps it would be better to add PTRACE_O_SUSPEND_SECCOMP? This also
> solves the problem with the killed tracer. Except TIF_NOTSC...
>
> But why do we bother to play with TIF_NOTSC, could you explain?
The procedure for restoring is to call seccomp suspend, restore the
seccomp filters (and potentially other stuff), and then resume them at
the end. If the other stuff happens to use RDTSC, the process gets
killed because TIF_NOTSC has been set. It seems to me that since
seccomp is the one setting TIF_NOTSC, suspending seccomp should unset
it.
We can work around this in criu by doing the seccomp restore as the
very last thing before the final sigreturn, but that seems like the
seccomp suspend API is incomplete, IMO. However, since both you and
Andy complained, perhaps I should remove it :)
> > +int suspend_seccomp(struct task_struct *task)
> > +{
> > + int ret = -EACCES;
> > +
> > + spin_lock_irq(&task->sighand->siglock);
> > +
> > + if (!capable(CAP_SYS_ADMIN))
> > + goto out;
>
> I am puzzled ;) Why do we need ->siglock? And even if we need it, why
> we can't check CAP_SYS_ADMIN lockless?
I'm not sure, other pieces of the seccomp code
(seccomp_set_mode_strict() and friends) take the lock when
manipulating the seccomp mode, so I just followed suit here. You're
right that we can do the capability check lockless, I'll make that
change.
> And I am not sure I understand why do we need the additional security
> check, but I leave this to you and Andy.
Yes, it is required to prevent the case Pavel mentions (although there
are other ways to get around seccomp with ptrace, the goal here is to
not depend on that behavior so that when it is eventually fixed this
doesn't break).
> If you have the rights to trace this task, then you can do anything
> the tracee could do without the filtering.
>
> > +
> > + task->seccomp.suspended = true;
> > +
> > +#ifdef TIF_NOTSC
> > + if (task->seccomp.mode == SECCOMP_MODE_STRICT)
> > + clear_tsk_thread_flag(task, TIF_NOTSC);
> > +#endif
> > +
> > + ret = 0;
> > +out:
> > + spin_unlock_irq(&task->sighand->siglock);
> > +
> > + return ret;
> > +}
> > +
> > +int resume_seccomp(struct task_struct *task)
> > +{
> > + int ret = -EACCES;
> > +
> > + spin_lock_irq(&task->sighand->siglock);
> > +
> > + if (!capable(CAP_SYS_ADMIN))
> > + goto out;
> > +
> > + task->seccomp.suspended = false;
> > +
> > +#ifdef TIF_NOTSC
> > + if (task->seccomp.mode == SECCOMP_MODE_STRICT)
> > + set_tsk_thread_flag(task, TIF_NOTSC);
> > +#endif
> > +
> > + ret = 0;
> > +out:
> > + spin_unlock_irq(&task->sighand->siglock);
> > +
> > + return ret;
> > +}
> > +#endif /* CONFIG_CHECKPOINT_RESTORE */
>
> Well, I do not think we need 2 helpers, just one which takes a boolean
> will look better, imo.
Ok, this has changed slightly with the "always resume on
detach/unlink" change Pavel suggested, but I'll see if I can find a
nice way to merge them.
Thanks for taking a look.
Tycho
> Oleg.
>
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 14:45 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Pavel Emelyanov, Oleg Nesterov,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux API,
Kees Cook, Will Drewry, Roland McGrath, Serge E. Hallyn
In-Reply-To: <CALCETrVYHYfogj3nTY-3ui87+tVi3mG3D4=Xdk-_MpisG8BczA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Tue, Jun 02, 2015 at 12:27:42PM -0700, Andy Lutomirski wrote:
>
> It might be worth changing the check to verify that the task trying to
> suspect seccomp isn't itself subject to seccomp. That should get most
> of the safety.
Sounds good, I'll make the change.
Tycho
^ permalink raw reply
* Re: [PATCH v5 02/21] libnvdimm, nfit: initial libnvdimm infrastructure and NFIT support
From: Christoph Hellwig @ 2015-06-03 14:57 UTC (permalink / raw)
To: Dan Williams
Cc: linux-nvdimm, axboe, sfr, rafael, neilb, gregkh, linux-kernel,
mingo, linux-acpi, jmoyer, linux-api, akpm, hch
In-Reply-To: <20150602001419.4506.41953.stgit@dwillia2-desk3.amr.corp.intel.com>
On Mon, Jun 01, 2015 at 08:14:19PM -0400, Dan Williams wrote:
> A libnvdimm bus is the anchor device for registering nvdimm resources and
> interfaces, for example, a character control device, nvdimm devices,
> and I/O region devices. The ACPI NFIT (NVDIMM Firmware Interface Table)
> is one possible platform description for such non-volatile memory
> resources in a system. The nfit.ko driver attaches to the "ACPI0012"
> device that indicates the presence of the NFIT and parses the table to
> register a libnvdimm bus instance.
Havin lib in a name of a bus seems odd. Why not simply the nvdimm bus?
Also this seems to both have the generic nvdimm infrastructure as well
as the acpi wiring. Might make sense to split this into two patches?
> +config ACPI_NFIT
> + tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
> + depends on PHYS_ADDR_T_64BIT
> + depends on BLK_DEV
> + select NVDIMM_DEVICES
> + select LIBNVDIMM
Is this the right way for the user to chose it? It seems like enabling
the NVMDIMM subsystem would be the obvious choice, and ACPI would
simply enable the table parsing in that case.
> +static u8 nfit_uuid[NFIT_UUID_MAX][16];
Should this use the uuid_le type?
> +static const char *spa_type_name(u16 type)
> +{
> + switch (type) {
> + case NFIT_SPA_VOLATILE: return "volatile";
> + case NFIT_SPA_PM: return "pmem";
> + case NFIT_SPA_DCR: return "dimm-control-region";
> + case NFIT_SPA_BDW: return "block-data-window";
> + default: return "unknown";
Please never put code on the same line as a switch (or goto) label.
> +static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, const void *end)
> +{
> + struct device *dev = acpi_desc->dev;
> + struct acpi_nfit_header *hdr;
> + void *err = ERR_PTR(-ENOMEM);
> +
> + if (table >= end)
> + return NULL;
> +
> + hdr = (struct acpi_nfit_header *) table;
No need to case from void * to another pointer type.
> + switch (hdr->type) {
> + case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: {
> + struct nfit_spa *nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa),
> + GFP_KERNEL);
> + struct acpi_nfit_system_address *spa = table;
> +
> + if (!nfit_spa)
> + return err;
> + INIT_LIST_HEAD(&nfit_spa->list);
> + nfit_spa->spa = spa;
> + list_add_tail(&nfit_spa->list, &acpi_desc->spas);
> + dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
> + spa->range_index,
> + spa_type_name(nfit_spa_type(spa)));
If you need local variables inside a switch statement you probably
want to split each case into a separate helper function.
> +static inline struct acpi_nfit_memory_map *__to_nfit_memdev(struct nfit_mem *nfit_mem)
This line is over 80 characters.
Also why the odd __-prefix?
> new file mode 100644
> index 000000000000..24b51dbc8215
> --- /dev/null
> +++ b/drivers/nvdimm/Kconfig
> @@ -0,0 +1,20 @@
> +menuconfig NVDIMM_DEVICES
> + bool "NVDIMM (Non-Volatile Memory Device) Support"
> + help
> + Generic support for non-volatile memory devices including
> + ACPI-6-NFIT defined resources. On platforms that define an
> + NFIT, or otherwise can discover NVDIMM resources, a libnvdimm
> + bus is registered to advertise PMEM (persistent memory)
> + namespaces (/dev/pmemX) and BLK (sliding mmio window(s))
> + namespaces (/dev/ndX). A PMEM namespace refers to a memory
> + resource that may span multiple DIMMs and support DAX (see
> + CONFIG_DAX). A BLK namespace refers to an NVDIMM control
> + region which exposes an mmio register set for windowed
> + access mode to non-volatile memory.
> +
> +if NVDIMM_DEVICES
> +
> +config LIBNVDIMM
> + tristate
> +
> +endif
What different meanings will CONFIG_NVDIMM_DEVICES and CONFIG_LIBNVDIMM
have?
> diff --git a/drivers/nvdimm/nd-private.h b/drivers/nvdimm/nd-private.h
> new file mode 100644
> index 000000000000..e7c4e99a22a4
> --- /dev/null
> +++ b/drivers/nvdimm/nd-private.h
No need for -private if you're already under drivers/nvdimm..
> +#ifndef __ND_PRIVATE_H__
> +#define __ND_PRIVATE_H__
> +#include <linux/libnvdimm.h>
> +#include <linux/device.h>
> +
> +struct nvdimm_bus {
> + struct nvdimm_bus_descriptor *nd_desc;
> + struct device dev;
> + int id;
> +};
> +#endif /* __ND_PRIVATE_H__ */
At least so far this header doesn't need libnvdimm.h
> +#ifndef __LIBNVDIMM_H__
> +#define __LIBNVDIMM_H__
> +struct nvdimm;
> +struct nvdimm_bus_descriptor;
> +typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
> + struct nvdimm *nvdimm, unsigned int cmd, void *buf,
> + unsigned int buf_len);
> +
> +struct nvdimm_bus_descriptor {
> + unsigned long dsm_mask;
> + char *provider_name;
> + ndctl_fn ndctl;
> +};
Please provide proper methods that do one thing properly instead of
ioctl-like multiplexers.
^ permalink raw reply
* [PATCH v3 0/5] support "cpu_isolated" mode for nohz_full
From: Chris Metcalf @ 2015-06-03 15:29 UTC (permalink / raw)
To: Gilad Ben Yossef, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
Andrew Morton, Rik van Riel, Tejun Heo, Frederic Weisbecker,
Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
Viresh Kumar, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Chris Metcalf
In-Reply-To: <1431725178-20876-1-git-send-email-cmetcalf-d5a29ZRxExrQT0dZR+AlfA@public.gmane.org>
The existing nohz_full mode does a nice job of suppressing extraneous
kernel interrupts for cores that desire it. However, there is a need
for a more deterministic mode that rigorously disallows kernel
interrupts, even at a higher cost in user/kernel transition time:
for example, high-speed networking applications running userspace
drivers that will drop packets if they are ever interrupted.
These changes attempt to provide an initial draft of such a framework;
the changes do not add any overhead to the usual non-nohz_full mode,
and only very small overhead to the typical nohz_full mode. A prctl()
option (PR_SET_CPU_ISOLATED) is added to control whether processes have
requested this stricter semantics, and within that prctl() option we
provide a number of different bits for more precise control.
Additionally, we add a new command-line boot argument to facilitate
debugging where unexpected interrupts are being delivered from.
Code that is conceptually similar has been in use in Tilera's
Multicore Development Environment since 2008, known as Zero-Overhead
Linux, and has seen wide adoption by a range of customers. This patch
series represents the first serious attempt to upstream that
functionality. Although the current state of the kernel isn't quite
ready to run with absolutely no kernel interrupts (for example,
workqueues on cpu_isolated cores still remain to be dealt with), this
patch series provides a way to make dynamic tradeoffs between avoiding
kernel interrupts on the one hand, and making voluntary calls in and
out of the kernel more expensive, for tasks that want it.
The series (based currently on my arch/tile master tree for 4.2,
in turn based on 4.1-rc1) is available at:
git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git dataplane
v3:
remove dependency on cpu_idle subsystem (Thomas Gleixner)
use READ_ONCE instead of ACCESS_ONCE in tick_nohz_cpu_isolated_enter
use seconds for console messages instead of jiffies (Thomas Gleixner)
updated commit description for patch 5/5
v2:
rename "dataplane" to "cpu_isolated"
drop ksoftirqd suppression changes (believed no longer needed)
merge previous "QUIESCE" functionality into baseline functionality
explicitly track syscalls and exceptions for "STRICT" functionality
allow configuring a signal to be delivered for STRICT mode failures
move debug tracking to irq_enter(), not irq_exit()
Note: I have not removed the commit to disable the 1Hz timer tick
fallback that was nack'ed by PeterZ, pending a decision on that thread
as to what to do (https://lkml.org/lkml/2015/5/8/555); also since if
we remove the 1Hz tick, cpu_isolated threads will never re-enter
userspace since a tick will always be pending.
Chris Metcalf (5):
nohz_full: add support for "cpu_isolated" mode
nohz: support PR_CPU_ISOLATED_STRICT mode
nohz: cpu_isolated strict mode configurable signal
nohz: add cpu_isolated_debug boot flag
nohz: cpu_isolated: allow tick to be fully disabled
Documentation/kernel-parameters.txt | 6 +++
arch/tile/kernel/process.c | 9 ++++
arch/tile/kernel/ptrace.c | 6 ++-
arch/tile/mm/homecache.c | 5 +-
arch/x86/kernel/ptrace.c | 2 +
include/linux/context_tracking.h | 11 ++--
include/linux/sched.h | 3 ++
include/linux/tick.h | 28 ++++++++++
include/uapi/linux/prctl.h | 8 +++
kernel/context_tracking.c | 12 +++--
kernel/irq_work.c | 4 +-
kernel/sched/core.c | 18 +++++++
kernel/signal.c | 5 ++
kernel/smp.c | 4 ++
kernel/softirq.c | 6 +++
kernel/sys.c | 8 +++
kernel/time/tick-sched.c | 104 +++++++++++++++++++++++++++++++++++-
17 files changed, 229 insertions(+), 10 deletions(-)
--
2.1.2
^ permalink raw reply
* [PATCH v3 1/5] nohz_full: add support for "cpu_isolated" mode
From: Chris Metcalf @ 2015-06-03 15:29 UTC (permalink / raw)
To: Gilad Ben Yossef, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
Andrew Morton, Rik van Riel, Tejun Heo, Frederic Weisbecker,
Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
Viresh Kumar, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Chris Metcalf
In-Reply-To: <1433345365-29506-1-git-send-email-cmetcalf-d5a29ZRxExrQT0dZR+AlfA@public.gmane.org>
The existing nohz_full mode makes tradeoffs to minimize userspace
interruptions while still attempting to avoid overheads in the
kernel entry/exit path, to provide 100% kernel semantics, etc.
However, some applications require a stronger commitment from the
kernel to avoid interruptions, in particular userspace device
driver style applications, such as high-speed networking code.
This change introduces a framework to allow applications to elect
to have the stronger semantics as needed, specifying
prctl(PR_SET_CPU_ISOLATED, PR_CPU_ISOLATED_ENABLE) to do so.
Subsequent commits will add additional flags and additional
semantics.
The "cpu_isolated" state is indicated by setting a new task struct
field, cpu_isolated_flags, to the value passed by prctl(). When the
_ENABLE bit is set for a task, and it is returning to userspace
on a nohz_full core, it calls the new tick_nohz_cpu_isolated_enter()
routine to take additional actions to help the task avoid being
interrupted in the future.
Initially, there are only two actions taken. First, the task
calls lru_add_drain() to prevent being interrupted by a subsequent
lru_add_drain_all() call on another core. Then, the code checks for
pending timer interrupts and quiesces until they are no longer pending.
As a result, sys calls (and page faults, etc.) can be inordinately slow.
However, this quiescing guarantees that no unexpected interrupts will
occur, even if the application intentionally calls into the kernel.
Signed-off-by: Chris Metcalf <cmetcalf-d5a29ZRxExrQT0dZR+AlfA@public.gmane.org>
---
arch/tile/kernel/process.c | 9 ++++++++
include/linux/sched.h | 3 +++
include/linux/tick.h | 10 ++++++++
include/uapi/linux/prctl.h | 5 ++++
kernel/context_tracking.c | 3 +++
kernel/sys.c | 8 +++++++
kernel/time/tick-sched.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 95 insertions(+)
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index e036c0aa9792..e20c3f4a6a82 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -70,6 +70,15 @@ void arch_cpu_idle(void)
_cpu_idle();
}
+#ifdef CONFIG_NO_HZ_FULL
+void tick_nohz_cpu_isolated_wait()
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+ _cpu_idle();
+ set_current_state(TASK_RUNNING);
+}
+#endif
+
/*
* Release a thread_info structure
*/
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 8222ae40ecb0..fb4ba400d7e1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1732,6 +1732,9 @@ struct task_struct {
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
unsigned long task_state_change;
#endif
+#ifdef CONFIG_NO_HZ_FULL
+ unsigned int cpu_isolated_flags;
+#endif
};
/* Future-safe accessor for struct task_struct's cpus_allowed. */
diff --git a/include/linux/tick.h b/include/linux/tick.h
index f8492da57ad3..ec1953474a65 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -10,6 +10,7 @@
#include <linux/context_tracking_state.h>
#include <linux/cpumask.h>
#include <linux/sched.h>
+#include <linux/prctl.h>
#ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void __init tick_init(void);
@@ -134,11 +135,18 @@ static inline bool tick_nohz_full_cpu(int cpu)
return cpumask_test_cpu(cpu, tick_nohz_full_mask);
}
+static inline bool tick_nohz_is_cpu_isolated(void)
+{
+ return tick_nohz_full_cpu(smp_processor_id()) &&
+ (current->cpu_isolated_flags & PR_CPU_ISOLATED_ENABLE);
+}
+
extern void __tick_nohz_full_check(void);
extern void tick_nohz_full_kick(void);
extern void tick_nohz_full_kick_cpu(int cpu);
extern void tick_nohz_full_kick_all(void);
extern void __tick_nohz_task_switch(struct task_struct *tsk);
+extern void tick_nohz_cpu_isolated_enter(void);
#else
static inline bool tick_nohz_full_enabled(void) { return false; }
static inline bool tick_nohz_full_cpu(int cpu) { return false; }
@@ -147,6 +155,8 @@ static inline void tick_nohz_full_kick_cpu(int cpu) { }
static inline void tick_nohz_full_kick(void) { }
static inline void tick_nohz_full_kick_all(void) { }
static inline void __tick_nohz_task_switch(struct task_struct *tsk) { }
+static inline bool tick_nohz_is_cpu_isolated(void) { return false; }
+static inline void tick_nohz_cpu_isolated_enter(void) { }
#endif
static inline bool is_housekeeping_cpu(int cpu)
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 31891d9535e2..edb40b6b84db 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -190,4 +190,9 @@ struct prctl_mm_map {
# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
+/* Enable/disable or query cpu_isolated mode for NO_HZ_FULL kernels. */
+#define PR_SET_CPU_ISOLATED 47
+#define PR_GET_CPU_ISOLATED 48
+# define PR_CPU_ISOLATED_ENABLE (1 << 0)
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 72d59a1a6eb6..66739d7c1350 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -20,6 +20,7 @@
#include <linux/hardirq.h>
#include <linux/export.h>
#include <linux/kprobes.h>
+#include <linux/tick.h>
#define CREATE_TRACE_POINTS
#include <trace/events/context_tracking.h>
@@ -85,6 +86,8 @@ void context_tracking_enter(enum ctx_state state)
* on the tick.
*/
if (state == CONTEXT_USER) {
+ if (tick_nohz_is_cpu_isolated())
+ tick_nohz_cpu_isolated_enter();
trace_user_enter(0);
vtime_user_enter(current);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index a4e372b798a5..3fd9e47f8fc8 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2243,6 +2243,14 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_GET_FP_MODE:
error = GET_FP_MODE(me);
break;
+#ifdef CONFIG_NO_HZ_FULL
+ case PR_SET_CPU_ISOLATED:
+ me->cpu_isolated_flags = arg2;
+ break;
+ case PR_GET_CPU_ISOLATED:
+ error = me->cpu_isolated_flags;
+ break;
+#endif
default:
error = -EINVAL;
break;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 914259128145..f6236b66788f 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -24,6 +24,7 @@
#include <linux/posix-timers.h>
#include <linux/perf_event.h>
#include <linux/context_tracking.h>
+#include <linux/swap.h>
#include <asm/irq_regs.h>
@@ -389,6 +390,62 @@ void __init tick_nohz_init(void)
pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",
cpumask_pr_args(tick_nohz_full_mask));
}
+
+/*
+ * Rather than continuously polling for the next_event in the
+ * tick_cpu_device, architectures can provide a method to save power
+ * by sleeping until an interrupt arrives.
+ */
+void __weak tick_nohz_cpu_isolated_wait()
+{
+ cpu_relax();
+}
+
+/*
+ * We normally return immediately to userspace.
+ *
+ * In "cpu_isolated" mode we wait until no more interrupts are
+ * pending. Otherwise we nap with interrupts enabled and wait for the
+ * next interrupt to fire, then loop back and retry.
+ *
+ * Note that if you schedule two "cpu_isolated" processes on the same
+ * core, neither will ever leave the kernel, and one will have to be
+ * killed manually. Otherwise in situations where another process is
+ * in the runqueue on this cpu, this task will just wait for that
+ * other task to go idle before returning to user space.
+ */
+void tick_nohz_cpu_isolated_enter(void)
+{
+ struct clock_event_device *dev =
+ __this_cpu_read(tick_cpu_device.evtdev);
+ struct task_struct *task = current;
+ unsigned long start = jiffies;
+ bool warned = false;
+
+ /* Drain the pagevecs to avoid unnecessary IPI flushes later. */
+ lru_add_drain();
+
+ while (READ_ONCE(dev->next_event.tv64) != KTIME_MAX) {
+ if (!warned && (jiffies - start) >= (5 * HZ)) {
+ pr_warn("%s/%d: cpu %d: cpu_isolated task blocked for %ld seconds\n",
+ task->comm, task->pid, smp_processor_id(),
+ (jiffies - start) / HZ);
+ warned = true;
+ }
+ if (should_resched())
+ schedule();
+ if (test_thread_flag(TIF_SIGPENDING))
+ break;
+ tick_nohz_cpu_isolated_wait();
+ }
+ if (warned) {
+ pr_warn("%s/%d: cpu %d: cpu_isolated task unblocked after %ld seconds\n",
+ task->comm, task->pid, smp_processor_id(),
+ (jiffies - start) / HZ);
+ dump_stack();
+ }
+}
+
#endif
/*
--
2.1.2
^ permalink raw reply related
* [PATCH v3 2/5] nohz: support PR_CPU_ISOLATED_STRICT mode
From: Chris Metcalf @ 2015-06-03 15:29 UTC (permalink / raw)
To: Gilad Ben Yossef, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
Andrew Morton, Rik van Riel, Tejun Heo, Frederic Weisbecker,
Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
Viresh Kumar, linux-doc, linux-api, linux-kernel
Cc: Chris Metcalf
In-Reply-To: <1433345365-29506-1-git-send-email-cmetcalf@ezchip.com>
With cpu_isolated mode, the task is in principle guaranteed not to be
interrupted by the kernel, but only if it behaves. In particular, if it
enters the kernel via system call, page fault, or any of a number of other
synchronous traps, it may be unexpectedly exposed to long latencies.
Add a simple flag that puts the process into a state where any such
kernel entry is fatal.
To allow the state to be entered and exited, we add an internal bit to
current->cpu_isolated_flags that is set when prctl() sets the flags.
We check the bit on syscall entry as well as on any exception_enter().
The prctl() syscall is ignored to allow clearing the bit again later,
and exit/exit_group are ignored to allow exiting the task without
a pointless signal killing you as you try to do so.
This change adds the syscall-detection hooks only for x86 and tile;
I am happy to try to add more for additional platforms in the final
version.
The signature of context_tracking_exit() changes to report whether
we, in fact, are exiting back to user space, so that we can track
user exceptions properly separately from other kernel entries.
Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
---
arch/tile/kernel/ptrace.c | 6 +++++-
arch/x86/kernel/ptrace.c | 2 ++
include/linux/context_tracking.h | 11 ++++++++---
include/linux/tick.h | 16 ++++++++++++++++
include/uapi/linux/prctl.h | 1 +
kernel/context_tracking.c | 9 ++++++---
kernel/time/tick-sched.c | 38 ++++++++++++++++++++++++++++++++++++++
7 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index f84eed8243da..d4e43a13bab1 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -259,8 +259,12 @@ int do_syscall_trace_enter(struct pt_regs *regs)
* If TIF_NOHZ is set, we are required to call user_exit() before
* doing anything that could touch RCU.
*/
- if (work & _TIF_NOHZ)
+ if (work & _TIF_NOHZ) {
user_exit();
+ if (tick_nohz_cpu_isolated_strict())
+ tick_nohz_cpu_isolated_syscall(
+ regs->regs[TREG_SYSCALL_NR]);
+ }
if (work & _TIF_SYSCALL_TRACE) {
if (tracehook_report_syscall_entry(regs))
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index a7bc79480719..7f784054ddea 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1479,6 +1479,8 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
if (work & _TIF_NOHZ) {
user_exit();
work &= ~_TIF_NOHZ;
+ if (tick_nohz_cpu_isolated_strict())
+ tick_nohz_cpu_isolated_syscall(regs->orig_ax);
}
#ifdef CONFIG_SECCOMP
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h
index 2821838256b4..d042f4cda39d 100644
--- a/include/linux/context_tracking.h
+++ b/include/linux/context_tracking.h
@@ -3,6 +3,7 @@
#include <linux/sched.h>
#include <linux/vtime.h>
+#include <linux/tick.h>
#include <linux/context_tracking_state.h>
#include <asm/ptrace.h>
@@ -11,7 +12,7 @@
extern void context_tracking_cpu_set(int cpu);
extern void context_tracking_enter(enum ctx_state state);
-extern void context_tracking_exit(enum ctx_state state);
+extern bool context_tracking_exit(enum ctx_state state);
extern void context_tracking_user_enter(void);
extern void context_tracking_user_exit(void);
extern void __context_tracking_task_switch(struct task_struct *prev,
@@ -37,8 +38,12 @@ static inline enum ctx_state exception_enter(void)
return 0;
prev_ctx = this_cpu_read(context_tracking.state);
- if (prev_ctx != CONTEXT_KERNEL)
- context_tracking_exit(prev_ctx);
+ if (prev_ctx != CONTEXT_KERNEL) {
+ if (context_tracking_exit(prev_ctx)) {
+ if (tick_nohz_cpu_isolated_strict())
+ tick_nohz_cpu_isolated_exception();
+ }
+ }
return prev_ctx;
}
diff --git a/include/linux/tick.h b/include/linux/tick.h
index ec1953474a65..b7ffb10337ba 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -147,6 +147,8 @@ extern void tick_nohz_full_kick_cpu(int cpu);
extern void tick_nohz_full_kick_all(void);
extern void __tick_nohz_task_switch(struct task_struct *tsk);
extern void tick_nohz_cpu_isolated_enter(void);
+extern void tick_nohz_cpu_isolated_syscall(int nr);
+extern void tick_nohz_cpu_isolated_exception(void);
#else
static inline bool tick_nohz_full_enabled(void) { return false; }
static inline bool tick_nohz_full_cpu(int cpu) { return false; }
@@ -157,6 +159,8 @@ static inline void tick_nohz_full_kick_all(void) { }
static inline void __tick_nohz_task_switch(struct task_struct *tsk) { }
static inline bool tick_nohz_is_cpu_isolated(void) { return false; }
static inline void tick_nohz_cpu_isolated_enter(void) { }
+static inline void tick_nohz_cpu_isolated_syscall(int nr) { }
+static inline void tick_nohz_cpu_isolated_exception(void) { }
#endif
static inline bool is_housekeeping_cpu(int cpu)
@@ -189,4 +193,16 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk)
__tick_nohz_task_switch(tsk);
}
+static inline bool tick_nohz_cpu_isolated_strict(void)
+{
+#ifdef CONFIG_NO_HZ_FULL
+ if (tick_nohz_full_cpu(smp_processor_id()) &&
+ (current->cpu_isolated_flags &
+ (PR_CPU_ISOLATED_ENABLE | PR_CPU_ISOLATED_STRICT)) ==
+ (PR_CPU_ISOLATED_ENABLE | PR_CPU_ISOLATED_STRICT))
+ return true;
+#endif
+ return false;
+}
+
#endif
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index edb40b6b84db..0c11238a84fb 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -194,5 +194,6 @@ struct prctl_mm_map {
#define PR_SET_CPU_ISOLATED 47
#define PR_GET_CPU_ISOLATED 48
# define PR_CPU_ISOLATED_ENABLE (1 << 0)
+# define PR_CPU_ISOLATED_STRICT (1 << 1)
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 66739d7c1350..c82509caa42e 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -131,15 +131,16 @@ NOKPROBE_SYMBOL(context_tracking_user_enter);
* This call supports re-entrancy. This way it can be called from any exception
* handler without needing to know if we came from userspace or not.
*/
-void context_tracking_exit(enum ctx_state state)
+bool context_tracking_exit(enum ctx_state state)
{
unsigned long flags;
+ bool from_user = false;
if (!context_tracking_is_enabled())
- return;
+ return false;
if (in_interrupt())
- return;
+ return false;
local_irq_save(flags);
if (__this_cpu_read(context_tracking.state) == state) {
@@ -150,6 +151,7 @@ void context_tracking_exit(enum ctx_state state)
*/
rcu_user_exit();
if (state == CONTEXT_USER) {
+ from_user = true;
vtime_user_exit(current);
trace_user_exit(0);
}
@@ -157,6 +159,7 @@ void context_tracking_exit(enum ctx_state state)
__this_cpu_write(context_tracking.state, CONTEXT_KERNEL);
}
local_irq_restore(flags);
+ return from_user;
}
NOKPROBE_SYMBOL(context_tracking_exit);
EXPORT_SYMBOL_GPL(context_tracking_exit);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index f6236b66788f..ce3bcf29a0f6 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -27,6 +27,7 @@
#include <linux/swap.h>
#include <asm/irq_regs.h>
+#include <asm/unistd.h>
#include "tick-internal.h"
@@ -446,6 +447,43 @@ void tick_nohz_cpu_isolated_enter(void)
}
}
+static void kill_cpu_isolated_strict_task(void)
+{
+ dump_stack();
+ current->cpu_isolated_flags &= ~PR_CPU_ISOLATED_ENABLE;
+ send_sig(SIGKILL, current, 1);
+}
+
+/*
+ * This routine is called from syscall entry (with the syscall number
+ * passed in) if the _STRICT flag is set.
+ */
+void tick_nohz_cpu_isolated_syscall(int syscall)
+{
+ /* Ignore prctl() syscalls or any task exit. */
+ switch (syscall) {
+ case __NR_prctl:
+ case __NR_exit:
+ case __NR_exit_group:
+ return;
+ }
+
+ pr_warn("%s/%d: cpu_isolated strict mode violated by syscall %d\n",
+ current->comm, current->pid, syscall);
+ kill_cpu_isolated_strict_task();
+}
+
+/*
+ * This routine is called from any userspace exception if the _STRICT
+ * flag is set.
+ */
+void tick_nohz_cpu_isolated_exception(void)
+{
+ pr_warn("%s/%d: cpu_isolated strict mode violated by exception\n",
+ current->comm, current->pid);
+ kill_cpu_isolated_strict_task();
+}
+
#endif
/*
--
2.1.2
^ permalink raw reply related
* [PATCH v3 3/5] nohz: cpu_isolated strict mode configurable signal
From: Chris Metcalf @ 2015-06-03 15:29 UTC (permalink / raw)
To: Gilad Ben Yossef, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
Andrew Morton, Rik van Riel, Tejun Heo, Frederic Weisbecker,
Thomas Gleixner, Paul E. McKenney, Christoph Lameter,
Viresh Kumar, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Chris Metcalf
In-Reply-To: <1433345365-29506-1-git-send-email-cmetcalf-d5a29ZRxExrQT0dZR+AlfA@public.gmane.org>
Allow userspace to override the default SIGKILL delivered
when a cpu_isolated process in STRICT mode does a syscall
or otherwise synchronously enters the kernel.
In addition to being able to set the signal, we now also
pass whether or not the interruption was from a syscall in
the si_code field of the siginfo.
Signed-off-by: Chris Metcalf <cmetcalf-d5a29ZRxExrQT0dZR+AlfA@public.gmane.org>
---
include/uapi/linux/prctl.h | 2 ++
kernel/time/tick-sched.c | 15 +++++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 0c11238a84fb..ab45bd3d5799 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -195,5 +195,7 @@ struct prctl_mm_map {
#define PR_GET_CPU_ISOLATED 48
# define PR_CPU_ISOLATED_ENABLE (1 << 0)
# define PR_CPU_ISOLATED_STRICT (1 << 1)
+# define PR_CPU_ISOLATED_SET_SIG(sig) (((sig) & 0x7f) << 8)
+# define PR_CPU_ISOLATED_GET_SIG(bits) (((bits) >> 8) & 0x7f)
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index ce3bcf29a0f6..f09c003da22f 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -447,11 +447,18 @@ void tick_nohz_cpu_isolated_enter(void)
}
}
-static void kill_cpu_isolated_strict_task(void)
+static void kill_cpu_isolated_strict_task(int is_syscall)
{
+ siginfo_t info = {};
+ int sig;
+
dump_stack();
current->cpu_isolated_flags &= ~PR_CPU_ISOLATED_ENABLE;
- send_sig(SIGKILL, current, 1);
+
+ sig = PR_CPU_ISOLATED_GET_SIG(current->cpu_isolated_flags) ?: SIGKILL;
+ info.si_signo = sig;
+ info.si_code = is_syscall;
+ send_sig_info(sig, &info, current);
}
/*
@@ -470,7 +477,7 @@ void tick_nohz_cpu_isolated_syscall(int syscall)
pr_warn("%s/%d: cpu_isolated strict mode violated by syscall %d\n",
current->comm, current->pid, syscall);
- kill_cpu_isolated_strict_task();
+ kill_cpu_isolated_strict_task(1);
}
/*
@@ -481,7 +488,7 @@ void tick_nohz_cpu_isolated_exception(void)
{
pr_warn("%s/%d: cpu_isolated strict mode violated by exception\n",
current->comm, current->pid);
- kill_cpu_isolated_strict_task();
+ kill_cpu_isolated_strict_task(0);
}
#endif
--
2.1.2
^ permalink raw reply related
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 16:13 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrey Wagin, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook,
Andy Lutomirski, Will Drewry, Roland McGrath, Pavel Emelyanov,
Serge E. Hallyn
In-Reply-To: <20150602184848.GA24907-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Tue, Jun 02, 2015 at 08:48:48PM +0200, Oleg Nesterov wrote:
> On 06/02, Tycho Andersen wrote:
> >
> > > Do we need to re-enable seccomp if a tracer detaches unexpectedly.
> > > CRIU can be killed and we should try to not affect the task state even
> > > in this case.
> >
> > Yes, I think Pavel's suggestion on the CRIU list of simply
> > automatically re-enabling seccomp on ptrace detach
>
> But note that you can't enable tsc if the tracer dies, in this case
> the tracee can be running.
Yes, this does complicate things. I think I'll get rid of the TSC
manipulation, since it's not clear to me how to resolve this. (I do
think it makes the API slightly incomplete, though, so suggestions how
to resolve it would be welcome.)
> Otherwise, if we use PTRACE_O_ instead, it goes away automatically if
> the tracer dies or does PTRACE_DETACH.
IIRC the flag goes away, but we still have to do something in
__ptrace_unlink to clear the seccomp suspended, so I'm not sure if the
automatic-ness helps us.
Tycho
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Oleg Nesterov @ 2015-06-03 16:41 UTC (permalink / raw)
To: Tycho Andersen
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150603144303.GC3160@smitten>
On 06/03, Tycho Andersen wrote:
>
> On Tue, Jun 02, 2015 at 08:28:29PM +0200, Oleg Nesterov wrote:
> > On 06/01, Tycho Andersen wrote:
> > >
> > > --- a/include/linux/seccomp.h
> > > +++ b/include/linux/seccomp.h
> > > @@ -25,6 +25,9 @@ struct seccomp_filter;
> > > struct seccomp {
> > > int mode;
> > > struct seccomp_filter *filter;
> > > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > > + bool suspended;
> > > +#endif
> >
> > Then afaics you need to change copy_seccomp() to clear ->suspended.
> > At least if the child is not traced.
>
> Yes, thank you.
And if we really need to play with TIF_NOTSC, then copy_seccomp() should
set it too if SUSPEND has cleared in parent's flags.
> > But why do we bother to play with TIF_NOTSC, could you explain?
>
> The procedure for restoring is to call seccomp suspend, restore the
> seccomp filters (and potentially other stuff), and then resume them at
> the end. If the other stuff happens to use RDTSC, the process gets
> killed because TIF_NOTSC has been set.
This is clear, just I thought that CRIU doesn't use rdtsc on behalf of
the traced task...
> We can work around this in criu by doing the seccomp restore as the
> very last thing before the final sigreturn,
Not sure I understand... You need to suspend at "dump" time too afaics,
otherwise, say, syscall_seized() can fail because this syscall is nacked
by seccomp?
> but that seems like the
> seccomp suspend API is incomplete, IMO. However, since both you and
> Andy complained, perhaps I should remove it :)
Well, this is up to you ;)
But. Note that a process can also disable TSC via PR_SET_TSC. So if
dump or restore can't work without enabling TSC you probably want to
handle this case too.
And this makes me think that this needs a separate interface. I dunno.
> > And I am not sure I understand why do we need the additional security
> > check, but I leave this to you and Andy.
>
> Yes, it is required to prevent the case Pavel mentions (although there
> are other ways to get around seccomp with ptrace, the goal here is to
> not depend on that behavior so that when it is eventually fixed this
> doesn't break).
I still do not think it makes any sense. again, if you can trace this
process then you can disable the filtering anyway. Lets assume that
seccomp_run_filters() acks, say, sys_getpid(). Or fork() in the case
Pavel mentioned, this doesn't matter. Now you can force the tracee to
call this syscall, then change syscall_nr.
But as I said I won't argue, please forget.
> Ok, this has changed slightly with the "always resume on
> detach/unlink" change Pavel suggested,
To remind, it is not easy to restore TIF_NOTSC if the tracer dies.
PTRACE_DETACH can do this because the tracee can't be woken up. But
personally I'd prefer the expicit RESUME request rather than "rely
on PTRACE_DETACH".
If we avoid the TSC games, then, again, please consider
PTRACE_O_SECCOMP_DISABLE. This will solve the problems with
fork/detach/tracer-death automatically.
Oleg.
^ permalink raw reply
* Re: [PATCH 10/98] via_drm.h: hide struct via_file_private in userspace
From: Emil Velikov @ 2015-06-03 16:50 UTC (permalink / raw)
To: Mikko Rapeli
Cc: Linux-Kernel@Vger. Kernel. Org, ML dri-devel,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1433000370-19509-11-git-send-email-mikko.rapeli-X3B1VOXEql0@public.gmane.org>
Hi Mikko,
On 30 May 2015 at 16:38, Mikko Rapeli <mikko.rapeli-X3B1VOXEql0@public.gmane.org> wrote:
> Fixes compiler error since list_head is not exported to userspace headers.
>
> Signed-off-by: Mikko Rapeli <mikko.rapeli-X3B1VOXEql0@public.gmane.org>
> ---
> include/uapi/drm/via_drm.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/uapi/drm/via_drm.h b/include/uapi/drm/via_drm.h
> index 791531e..34ce658 100644
> --- a/include/uapi/drm/via_drm.h
> +++ b/include/uapi/drm/via_drm.h
> @@ -272,8 +272,10 @@ typedef struct drm_via_dmablit {
> drm_via_blitsync_t sync;
> } drm_via_dmablit_t;
>
> +#ifdef __KERNEL__
> struct via_file_private {
> struct list_head obj_list;
> };
> +#endif
>
We might want to follow the example of other drivers (i915) and move
it to drivers/gpu/drm/via_drv.h, There are two users of this struct
(via_drv.c and via_mm.c), and each one explicitly includes the header.
How does that sound ?
Same suggestion goes for the equivalent sis patch.
Cheers
Emil
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Oleg Nesterov @ 2015-06-03 16:54 UTC (permalink / raw)
To: Tycho Andersen
Cc: Andrey Wagin, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook,
Andy Lutomirski, Will Drewry, Roland McGrath, Pavel Emelyanov,
Serge E. Hallyn
In-Reply-To: <20150603161321.GD3337@hopstrocity>
On 06/03, Tycho Andersen wrote:
>
> On Tue, Jun 02, 2015 at 08:48:48PM +0200, Oleg Nesterov wrote:
>
> > Otherwise, if we use PTRACE_O_ instead, it goes away automatically if
> > the tracer dies or does PTRACE_DETACH.
>
> IIRC the flag goes away, but we still have to do something in
> __ptrace_unlink to clear the seccomp suspended, so I'm not sure if the
> automatic-ness helps us.
But we do not need seccomp->suspended at all?
Unless I missed something PTRACE_O_ needs a one-liner patch (ignoring
the defines in include files),
--- x/kernel/seccomp.c
+++ x/kernel/seccomp.c
@@ -692,6 +692,9 @@ u32 seccomp_phase1(struct seccomp_data *
int this_syscall = sd ? sd->nr :
syscall_get_nr(current, task_pt_regs(current));
+ if (unlikely(current->ptrace & PT_NAME_OF_THIS_OPTION))
+ return OK;
+
switch (mode) {
case SECCOMP_MODE_STRICT:
__secure_computing_strict(this_syscall); /* may call do_exit */
OK, and the same check in secure_computing_strict().
No?
Oleg.
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 16:58 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Andrey Wagin, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook,
Andy Lutomirski, Will Drewry, Roland McGrath, Pavel Emelyanov,
Serge E. Hallyn
In-Reply-To: <20150603165451.GA20911-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Wed, Jun 03, 2015 at 06:54:51PM +0200, Oleg Nesterov wrote:
> On 06/03, Tycho Andersen wrote:
> >
> > On Tue, Jun 02, 2015 at 08:48:48PM +0200, Oleg Nesterov wrote:
> >
> > > Otherwise, if we use PTRACE_O_ instead, it goes away automatically if
> > > the tracer dies or does PTRACE_DETACH.
> >
> > IIRC the flag goes away, but we still have to do something in
> > __ptrace_unlink to clear the seccomp suspended, so I'm not sure if the
> > automatic-ness helps us.
>
> But we do not need seccomp->suspended at all?
>
> Unless I missed something PTRACE_O_ needs a one-liner patch (ignoring
> the defines in include files),
>
> --- x/kernel/seccomp.c
> +++ x/kernel/seccomp.c
> @@ -692,6 +692,9 @@ u32 seccomp_phase1(struct seccomp_data *
> int this_syscall = sd ? sd->nr :
> syscall_get_nr(current, task_pt_regs(current));
>
> + if (unlikely(current->ptrace & PT_NAME_OF_THIS_OPTION))
> + return OK;
> +
> switch (mode) {
> case SECCOMP_MODE_STRICT:
> __secure_computing_strict(this_syscall); /* may call do_exit */
>
>
> OK, and the same check in secure_computing_strict().
>
> No?
I see, I misunderstood. Yes, this is a lot nicer, thank you.
Tycho
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 17:10 UTC (permalink / raw)
To: Oleg Nesterov
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150603164121.GA19189-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Hi Oleg,
On Wed, Jun 03, 2015 at 06:41:21PM +0200, Oleg Nesterov wrote:
> On 06/03, Tycho Andersen wrote:
> >
> > On Tue, Jun 02, 2015 at 08:28:29PM +0200, Oleg Nesterov wrote:
> > > On 06/01, Tycho Andersen wrote:
> > > >
> > > > --- a/include/linux/seccomp.h
> > > > +++ b/include/linux/seccomp.h
> > > > @@ -25,6 +25,9 @@ struct seccomp_filter;
> > > > struct seccomp {
> > > > int mode;
> > > > struct seccomp_filter *filter;
> > > > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > > > + bool suspended;
> > > > +#endif
> > >
> > > Then afaics you need to change copy_seccomp() to clear ->suspended.
> > > At least if the child is not traced.
> >
> > Yes, thank you.
>
> And if we really need to play with TIF_NOTSC, then copy_seccomp() should
> set it too if SUSPEND has cleared in parent's flags.
>
> > > But why do we bother to play with TIF_NOTSC, could you explain?
> >
> > The procedure for restoring is to call seccomp suspend, restore the
> > seccomp filters (and potentially other stuff), and then resume them at
> > the end. If the other stuff happens to use RDTSC, the process gets
> > killed because TIF_NOTSC has been set.
>
> This is clear, just I thought that CRIU doesn't use rdtsc on behalf of
> the traced task...
Unfortunately it does (I think to print timestamps in logs, although I
didn't look closely).
> > We can work around this in criu by doing the seccomp restore as the
> > very last thing before the final sigreturn,
>
> Not sure I understand... You need to suspend at "dump" time too afaics,
> otherwise, say, syscall_seized() can fail because this syscall is nacked
> by seccomp?
Yes, but thankfully criu's dump code doesn't seem to use RDTSC, so it
just happens to work. Of course, if the dump code starts to use it,
we'll have to revisit this change.
> > but that seems like the
> > seccomp suspend API is incomplete, IMO. However, since both you and
> > Andy complained, perhaps I should remove it :)
>
> Well, this is up to you ;)
>
> But. Note that a process can also disable TSC via PR_SET_TSC. So if
> dump or restore can't work without enabling TSC you probably want to
> handle this case too.
>
> And this makes me think that this needs a separate interface. I dunno.
I guess if we want to disable the TSC we need to save the state
irrespective of seccomp. I think I will ignore this for now, since we
can work around it in CRIU, and hope that we don't have to revisit it
because of the complexity r.e. tracer dying you mention below.
Tycho
> > > And I am not sure I understand why do we need the additional security
> > > check, but I leave this to you and Andy.
> >
> > Yes, it is required to prevent the case Pavel mentions (although there
> > are other ways to get around seccomp with ptrace, the goal here is to
> > not depend on that behavior so that when it is eventually fixed this
> > doesn't break).
>
> I still do not think it makes any sense. again, if you can trace this
> process then you can disable the filtering anyway. Lets assume that
> seccomp_run_filters() acks, say, sys_getpid(). Or fork() in the case
> Pavel mentioned, this doesn't matter. Now you can force the tracee to
> call this syscall, then change syscall_nr.
>
> But as I said I won't argue, please forget.
>
> > Ok, this has changed slightly with the "always resume on
> > detach/unlink" change Pavel suggested,
>
> To remind, it is not easy to restore TIF_NOTSC if the tracer dies.
>
> PTRACE_DETACH can do this because the tracee can't be woken up. But
> personally I'd prefer the expicit RESUME request rather than "rely
> on PTRACE_DETACH".
>
> If we avoid the TSC games, then, again, please consider
> PTRACE_O_SECCOMP_DISABLE. This will solve the problems with
> fork/detach/tracer-death automatically.
>
> Oleg.
>
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Andy Lutomirski @ 2015-06-03 17:11 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Tycho Andersen, linux-kernel@vger.kernel.org, Linux API,
Kees Cook, Will Drewry, Roland McGrath, Pavel Emelyanov,
Serge E. Hallyn
In-Reply-To: <20150603164121.GA19189@redhat.com>
On Wed, Jun 3, 2015 at 9:41 AM, Oleg Nesterov <oleg@redhat.com> wrote:
> On 06/03, Tycho Andersen wrote:
>>
>> On Tue, Jun 02, 2015 at 08:28:29PM +0200, Oleg Nesterov wrote:
>> > On 06/01, Tycho Andersen wrote:
>> > >
>> > > --- a/include/linux/seccomp.h
>> > > +++ b/include/linux/seccomp.h
>> > > @@ -25,6 +25,9 @@ struct seccomp_filter;
>> > > struct seccomp {
>> > > int mode;
>> > > struct seccomp_filter *filter;
>> > > +#ifdef CONFIG_CHECKPOINT_RESTORE
>> > > + bool suspended;
>> > > +#endif
>> >
>> > Then afaics you need to change copy_seccomp() to clear ->suspended.
>> > At least if the child is not traced.
>>
>> Yes, thank you.
>
> And if we really need to play with TIF_NOTSC, then copy_seccomp() should
> set it too if SUSPEND has cleared in parent's flags.
>
>> > But why do we bother to play with TIF_NOTSC, could you explain?
>>
>> The procedure for restoring is to call seccomp suspend, restore the
>> seccomp filters (and potentially other stuff), and then resume them at
>> the end. If the other stuff happens to use RDTSC, the process gets
>> killed because TIF_NOTSC has been set.
>
> This is clear, just I thought that CRIU doesn't use rdtsc on behalf of
> the traced task...
>
>> We can work around this in criu by doing the seccomp restore as the
>> very last thing before the final sigreturn,
>
> Not sure I understand... You need to suspend at "dump" time too afaics,
> otherwise, say, syscall_seized() can fail because this syscall is nacked
> by seccomp?
>
>> but that seems like the
>> seccomp suspend API is incomplete, IMO. However, since both you and
>> Andy complained, perhaps I should remove it :)
>
> Well, this is up to you ;)
>
> But. Note that a process can also disable TSC via PR_SET_TSC. So if
> dump or restore can't work without enabling TSC you probably want to
> handle this case too.
>
> And this makes me think that this needs a separate interface. I dunno.
>
True. Or we could keep track of all the reasons the TSC is off.
--Andy
^ permalink raw reply
* Re: [PATCH 09/98] via_drm.h: include linux/types.h instead of non-existing via_drmclient.h
From: Emil Velikov @ 2015-06-03 17:16 UTC (permalink / raw)
To: Mikko Rapeli; +Cc: linux-api, Linux-Kernel@Vger. Kernel. Org, ML dri-devel
In-Reply-To: <1433000370-19509-10-git-send-email-mikko.rapeli@iki.fi>
Hi Mikko,
On 30 May 2015 at 16:38, Mikko Rapeli <mikko.rapeli@iki.fi> wrote:
> Fixes compiler error:
>
> drm/via_drm.h:36:27: fatal error: via_drmclient.h: No such file or directory
>
> Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>
> ---
> include/uapi/drm/via_drm.h | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/include/uapi/drm/via_drm.h b/include/uapi/drm/via_drm.h
> index 8b0533c..791531e 100644
> --- a/include/uapi/drm/via_drm.h
> +++ b/include/uapi/drm/via_drm.h
> @@ -24,6 +24,7 @@
> #ifndef _VIA_DRM_H_
> #define _VIA_DRM_H_
>
> +#include <linux/types.h>
As mentioned elsewhere one could avoid this, and just use drm.h to
manage the approapriate types (uint32_t vs __u32 and so on).
> #include <drm/drm.h>
>
> /* WARNING: These defines must be the same as what the Xserver uses.
> @@ -33,9 +34,6 @@
> #ifndef _VIA_DEFINES_
> #define _VIA_DEFINES_
>
> -#ifndef __KERNEL__
> -#include "via_drmclient.h"
> -#endif
>
I fear that this one is a particular example of a nasty legacy from
the UMS days. The file is available/provided in very old mesa versions
and at the very same time mesa requires via_drm.h. So I would kindly
ask that you:
- Grab the libdrm userspace package, and apply a similar change.
- Rebuild/install the above.
- Fetch mesa 7.11, and try building the via dri module. Ideally
things will continue to build, alternatively we might need to add
another/additional guard for this include.
Thanks
Emil
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 03/98] drm.h: use __kernel_size_t instead of size_t
From: Emil Velikov @ 2015-06-03 17:19 UTC (permalink / raw)
To: Mikko Rapeli; +Cc: linux-api, Linux-Kernel@Vger. Kernel. Org, ML dri-devel
In-Reply-To: <1433000370-19509-4-git-send-email-mikko.rapeli@iki.fi>
On 30 May 2015 at 16:37, Mikko Rapeli <mikko.rapeli@iki.fi> wrote:
> Fixes userspace compilation error:
>
> drm/drm.h:132:2: error: unknown type name ‘size_t’
>
> Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>
> ---
> include/uapi/drm/drm.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index ff6ef62..b197650 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -129,11 +129,11 @@ struct drm_version {
> int version_major; /**< Major version */
> int version_minor; /**< Minor version */
> int version_patchlevel; /**< Patch level */
> - size_t name_len; /**< Length of name buffer */
> + __kernel_size_t name_len; /**< Length of name buffer */
> char __user *name; /**< Name of driver */
> - size_t date_len; /**< Length of date buffer */
> + __kernel_size_t date_len; /**< Length of date buffer */
> char __user *date; /**< User-space buffer to hold date */
> - size_t desc_len; /**< Length of desc buffer */
> + __kernel_size_t desc_len; /**< Length of desc buffer */
> char __user *desc; /**< User-space buffer to hold desc */
> };
>
> @@ -143,7 +143,7 @@ struct drm_version {
> * \sa drmGetBusid() and drmSetBusId().
> */
> struct drm_unique {
> - size_t unique_len; /**< Length of unique */
> + __kernel_size_t unique_len; /**< Length of unique */
As the file is used by other platforms than Linux this change will
break them. Can you add a typedef similar to how __u8 and friends are
handled at the top of the file.
Thanks
Emil
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH] seccomp: add ptrace commands for suspend/resume
From: Tycho Andersen @ 2015-06-03 18:36 UTC (permalink / raw)
To: Oleg Nesterov, Andy Lutomirski
Cc: Andrey Wagin, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150603165451.GA20911-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Wed, Jun 03, 2015 at 06:54:51PM +0200, Oleg Nesterov wrote:
> On 06/03, Tycho Andersen wrote:
> >
> > On Tue, Jun 02, 2015 at 08:48:48PM +0200, Oleg Nesterov wrote:
> >
> > > Otherwise, if we use PTRACE_O_ instead, it goes away automatically if
> > > the tracer dies or does PTRACE_DETACH.
> >
> > IIRC the flag goes away, but we still have to do something in
> > __ptrace_unlink to clear the seccomp suspended, so I'm not sure if the
> > automatic-ness helps us.
>
> But we do not need seccomp->suspended at all?
>
> Unless I missed something PTRACE_O_ needs a one-liner patch (ignoring
> the defines in include files),
>
> --- x/kernel/seccomp.c
> +++ x/kernel/seccomp.c
> @@ -692,6 +692,9 @@ u32 seccomp_phase1(struct seccomp_data *
> int this_syscall = sd ? sd->nr :
> syscall_get_nr(current, task_pt_regs(current));
>
> + if (unlikely(current->ptrace & PT_NAME_OF_THIS_OPTION))
> + return OK;
> +
> switch (mode) {
> case SECCOMP_MODE_STRICT:
> __secure_computing_strict(this_syscall); /* may call do_exit */
>
>
> OK, and the same check in secure_computing_strict().
>
> No?
One problem with this is that we still incur the runtime overhead of
checking, which I guess is a question of ptrace vs. seccomp
complexity.
Andy had suggested multiplexing seccomp->suspended into seccomp->mode
directly to avoid this, but the above still requires a check. We could
play with TIF_SECCOMP, but that has the same problems as playing with
TIF_NOTSC.
Thoughts?
Tycho
^ permalink raw reply
* Re: [PATCH v5 02/21] libnvdimm, nfit: initial libnvdimm infrastructure and NFIT support
From: Williams, Dan J @ 2015-06-03 19:24 UTC (permalink / raw)
To: hch-jcswGhMUV9g@public.gmane.org
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
neilb-l3A5Bk7waGM@public.gmane.org,
jmoyer-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
axboe-tSWWG44O7X1aa/9Udqfwiw@public.gmane.org,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org,
sfr-3FnU+UHB4dNDw9hX6IcOSA@public.gmane.org,
linux-nvdimm-hn68Rpc1hR1g9hUCZPvPmw@public.gmane.org,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org,
rafael-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
linux-acpi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20150603145704.GA22311-jcswGhMUV9g@public.gmane.org>
On Wed, 2015-06-03 at 16:57 +0200, Christoph Hellwig wrote:
> On Mon, Jun 01, 2015 at 08:14:19PM -0400, Dan Williams wrote:
> > A libnvdimm bus is the anchor device for registering nvdimm resources and
> > interfaces, for example, a character control device, nvdimm devices,
> > and I/O region devices. The ACPI NFIT (NVDIMM Firmware Interface Table)
> > is one possible platform description for such non-volatile memory
> > resources in a system. The nfit.ko driver attaches to the "ACPI0012"
> > device that indicates the presence of the NFIT and parses the table to
> > register a libnvdimm bus instance.
>
> Havin lib in a name of a bus seems odd. Why not simply the nvdimm bus?
Sorry, that is a typo the bus is indeed an struct nvdimm_bus instance.
> Also this seems to both have the generic nvdimm infrastructure as well
> as the acpi wiring. Might make sense to split this into two patches?
I like to show an initial infrastructure consumer with the initial
implementation in one patch. Makes it easier to catch premature
implementation of features.
>
> > +config ACPI_NFIT
> > + tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
> > + depends on PHYS_ADDR_T_64BIT
> > + depends on BLK_DEV
> > + select NVDIMM_DEVICES
> > + select LIBNVDIMM
>
> Is this the right way for the user to chose it? It seems like enabling
> the NVMDIMM subsystem would be the obvious choice, and ACPI would
> simply enable the table parsing in that case.
The NVDIMM sub-system is enabled by an external provider. We have the
e820 type-12 provider and the NFIT provider that select LIBNVDIMM.
> > +static u8 nfit_uuid[NFIT_UUID_MAX][16];
>
> Should this use the uuid_le type?
>
That would depend on Rafael being open to changing the
acpi_str_to_uuid() prototype to take an uuid_le.
> > +static const char *spa_type_name(u16 type)
> > +{
> > + switch (type) {
> > + case NFIT_SPA_VOLATILE: return "volatile";
> > + case NFIT_SPA_PM: return "pmem";
> > + case NFIT_SPA_DCR: return "dimm-control-region";
> > + case NFIT_SPA_BDW: return "block-data-window";
> > + default: return "unknown";
>
> Please never put code on the same line as a switch (or goto) label.
Ok, fixed.
>
> > +static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, const void *end)
> > +{
> > + struct device *dev = acpi_desc->dev;
> > + struct acpi_nfit_header *hdr;
> > + void *err = ERR_PTR(-ENOMEM);
> > +
> > + if (table >= end)
> > + return NULL;
> > +
> > + hdr = (struct acpi_nfit_header *) table;
>
> No need to case from void * to another pointer type.
Whoops, fixed.
>
> > + switch (hdr->type) {
> > + case ACPI_NFIT_TYPE_SYSTEM_ADDRESS: {
> > + struct nfit_spa *nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa),
> > + GFP_KERNEL);
> > + struct acpi_nfit_system_address *spa = table;
> > +
> > + if (!nfit_spa)
> > + return err;
> > + INIT_LIST_HEAD(&nfit_spa->list);
> > + nfit_spa->spa = spa;
> > + list_add_tail(&nfit_spa->list, &acpi_desc->spas);
> > + dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
> > + spa->range_index,
> > + spa_type_name(nfit_spa_type(spa)));
>
> If you need local variables inside a switch statement you probably
> want to split each case into a separate helper function.
Yeah, probably better that way. Done.
>
> > +static inline struct acpi_nfit_memory_map *__to_nfit_memdev(struct nfit_mem *nfit_mem)
>
> This line is over 80 characters.
I generally don't see the point of fixing up occasional small incursions
over 80 characters if it makes the code more amenable to grep.
> Also why the odd __-prefix?
Later on the series there's a to_nfit_memdev() that takes a struct
device *, and this one is an internal helper.
>
> > new file mode 100644
> > index 000000000000..24b51dbc8215
> > --- /dev/null
> > +++ b/drivers/nvdimm/Kconfig
> > @@ -0,0 +1,20 @@
> > +menuconfig NVDIMM_DEVICES
> > + bool "NVDIMM (Non-Volatile Memory Device) Support"
> > + help
> > + Generic support for non-volatile memory devices including
> > + ACPI-6-NFIT defined resources. On platforms that define an
> > + NFIT, or otherwise can discover NVDIMM resources, a libnvdimm
> > + bus is registered to advertise PMEM (persistent memory)
> > + namespaces (/dev/pmemX) and BLK (sliding mmio window(s))
> > + namespaces (/dev/ndX). A PMEM namespace refers to a memory
> > + resource that may span multiple DIMMs and support DAX (see
> > + CONFIG_DAX). A BLK namespace refers to an NVDIMM control
> > + region which exposes an mmio register set for windowed
> > + access mode to non-volatile memory.
> > +
> > +if NVDIMM_DEVICES
> > +
> > +config LIBNVDIMM
> > + tristate
> > +
> > +endif
>
> What different meanings will CONFIG_NVDIMM_DEVICES and CONFIG_LIBNVDIMM
> have?
Hmm, nothing worthwhile. I'll merge them into one menuconfig
CONFIG_LIBNVDIMM tristate.
>
> > diff --git a/drivers/nvdimm/nd-private.h b/drivers/nvdimm/nd-private.h
> > new file mode 100644
> > index 000000000000..e7c4e99a22a4
> > --- /dev/null
> > +++ b/drivers/nvdimm/nd-private.h
>
> No need for -private if you're already under drivers/nvdimm..
This is the private private-header in the sense that it defines
infrastructure that is only meant for the core. Drivers (btt, pmem,
blk, etc) must not include nd-private.h. I'll rename it "nd-core.h" to
make this more clear.
> > +#ifndef __ND_PRIVATE_H__
> > +#define __ND_PRIVATE_H__
> > +#include <linux/libnvdimm.h>
> > +#include <linux/device.h>
> > +
> > +struct nvdimm_bus {
> > + struct nvdimm_bus_descriptor *nd_desc;
> > + struct device dev;
> > + int id;
> > +};
> > +#endif /* __ND_PRIVATE_H__ */
>
> At least so far this header doesn't need libnvdimm.h
struct nvdimm_bus_descriptor is defined there and a forward declaration
does not make sense since we'll need the rest of the header later in the
series.
>
> > +#ifndef __LIBNVDIMM_H__
> > +#define __LIBNVDIMM_H__
> > +struct nvdimm;
> > +struct nvdimm_bus_descriptor;
> > +typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
> > + struct nvdimm *nvdimm, unsigned int cmd, void *buf,
> > + unsigned int buf_len);
> > +
> > +struct nvdimm_bus_descriptor {
> > + unsigned long dsm_mask;
> > + char *provider_name;
> > + ndctl_fn ndctl;
> > +};
>
> Please provide proper methods that do one thing properly instead of
> ioctl-like multiplexers.
This *is* the ioctl multiplexer. The generic ioctl implementation in
libnvdimm uses the ndctl_fn to call back out to the provider to process
the command. In the case of ACPI this maps to a _DSM (device specific
method), for nfit_test it's a emulated implementation, and for
e820-type-12 this is obviously not implemented.
Reflowed patch with these fixes follows...
8<-----
Subject: libnvdimm, nfit: initial libnvdimm infrastructure and NFIT support
From: Dan Williams <dan.j.williams@intel.com>
A libnvdimm bus is the anchor device for registering nvdimm resources and
interfaces, for example, a character control device, nvdimm devices,
and I/O region devices. The ACPI NFIT (NVDIMM Firmware Interface Table)
is one possible platform description for such non-volatile memory
resources in a system. The nfit.ko driver attaches to the "ACPI0012"
device that indicates the presence of the NFIT and parses the table to
register a struct nvdimm_bus instance.
Cc: <linux-acpi@vger.kernel.org>
Cc: Lv Zheng <lv.zheng@intel.com>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
drivers/Kconfig | 2
drivers/Makefile | 1
drivers/acpi/Kconfig | 14 +
drivers/acpi/Makefile | 1
drivers/acpi/nfit.c | 481 +++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/nfit.h | 89 ++++++++
drivers/nvdimm/Kconfig | 13 +
drivers/nvdimm/Makefile | 3
drivers/nvdimm/core.c | 67 ++++++
drivers/nvdimm/nd-core.h | 23 ++
include/linux/libnvdimm.h | 34 +++
11 files changed, 728 insertions(+)
create mode 100644 drivers/acpi/nfit.c
create mode 100644 drivers/acpi/nfit.h
create mode 100644 drivers/nvdimm/Kconfig
create mode 100644 drivers/nvdimm/Makefile
create mode 100644 drivers/nvdimm/core.c
create mode 100644 drivers/nvdimm/nd-core.h
create mode 100644 include/linux/libnvdimm.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c0cc96bab9e7..6e973b8e3a3b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -182,4 +182,6 @@ source "drivers/thunderbolt/Kconfig"
source "drivers/android/Kconfig"
+source "drivers/nvdimm/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 46d2554be404..692adf659028 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/
+obj-$(CONFIG_LIBNVDIMM) += nvdimm/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
obj-$(CONFIG_NUBUS) += nubus/
obj-y += macintosh/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ab2cbb51c6aa..300b4ef3712b 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -383,6 +383,20 @@ config ACPI_REDUCED_HARDWARE_ONLY
If you are unsure what to do, do not enable this option.
+config ACPI_NFIT
+ tristate "ACPI NVDIMM Firmware Interface Table (NFIT)"
+ depends on PHYS_ADDR_T_64BIT
+ depends on BLK_DEV
+ select LIBNVDIMM
+ help
+ Infrastructure to probe ACPI 6 compliant platforms for
+ NVDIMMs (NFIT) and register a libnvdimm device tree. In
+ addition to storage devices this also enables libnvdimm to pass
+ ACPI._DSM messages for platform/dimm configuration.
+
+ To compile this driver as a module, choose M here:
+ the module will be called nfit.
+
source "drivers/acpi/apei/Kconfig"
config ACPI_EXTLOG
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8a063e276530..f7e9c92ccdcb 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-y += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
+obj-$(CONFIG_ACPI_NFIT) += nfit.o
obj-y += acpi_memhotplug.o
obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
new file mode 100644
index 000000000000..c400d60018a5
--- /dev/null
+++ b/drivers/acpi/nfit.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <linux/list_sort.h>
+#include <linux/libnvdimm.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include "nfit.h"
+
+static u8 nfit_uuid[NFIT_UUID_MAX][16];
+
+static const u8 *to_nfit_uuid(enum nfit_uuids id)
+{
+ return nfit_uuid[id];
+}
+
+static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
+ struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+ unsigned int buf_len)
+{
+ return -ENOTTY;
+}
+
+static const char *spa_type_name(u16 type)
+{
+ static const char *to_name[] = {
+ [NFIT_SPA_VOLATILE] = "volatile",
+ [NFIT_SPA_PM] = "pmem",
+ [NFIT_SPA_DCR] = "dimm-control-region",
+ [NFIT_SPA_BDW] = "block-data-window",
+ [NFIT_SPA_VDISK] = "volatile-disk",
+ [NFIT_SPA_VCD] = "volatile-cd",
+ [NFIT_SPA_PDISK] = "persistent-disk",
+ [NFIT_SPA_PCD] = "persistent-cd",
+
+ };
+
+ if (type > NFIT_SPA_PCD)
+ return "unknown";
+
+ return to_name[type];
+}
+
+static int nfit_spa_type(struct acpi_nfit_system_address *spa)
+{
+ int i;
+
+ for (i = 0; i < NFIT_UUID_MAX; i++)
+ if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
+ return i;
+ return -1;
+}
+
+static bool add_spa(struct acpi_nfit_desc *acpi_desc,
+ struct acpi_nfit_system_address *spa)
+{
+ struct device *dev = acpi_desc->dev;
+ struct nfit_spa *nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa),
+ GFP_KERNEL);
+
+ if (!nfit_spa)
+ return false;
+ INIT_LIST_HEAD(&nfit_spa->list);
+ nfit_spa->spa = spa;
+ list_add_tail(&nfit_spa->list, &acpi_desc->spas);
+ dev_dbg(dev, "%s: spa index: %d type: %s\n", __func__,
+ spa->range_index,
+ spa_type_name(nfit_spa_type(spa)));
+ return true;
+}
+
+static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
+ struct acpi_nfit_memory_map *memdev)
+{
+ struct device *dev = acpi_desc->dev;
+ struct nfit_memdev *nfit_memdev = devm_kzalloc(dev,
+ sizeof(*nfit_memdev), GFP_KERNEL);
+
+ if (!nfit_memdev)
+ return false;
+ INIT_LIST_HEAD(&nfit_memdev->list);
+ nfit_memdev->memdev = memdev;
+ list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+ dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n",
+ __func__, memdev->device_handle, memdev->range_index,
+ memdev->region_index);
+ return true;
+}
+
+static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
+ struct acpi_nfit_control_region *dcr)
+{
+ struct device *dev = acpi_desc->dev;
+ struct nfit_dcr *nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr),
+ GFP_KERNEL);
+
+ if (!nfit_dcr)
+ return false;
+ INIT_LIST_HEAD(&nfit_dcr->list);
+ nfit_dcr->dcr = dcr;
+ list_add_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+ dev_dbg(dev, "%s: dcr index: %d windows: %d\n", __func__,
+ dcr->region_index, dcr->windows);
+ return true;
+}
+
+static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
+ struct acpi_nfit_data_region *bdw)
+{
+ struct device *dev = acpi_desc->dev;
+ struct nfit_bdw *nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw),
+ GFP_KERNEL);
+
+ if (!nfit_bdw)
+ return false;
+ INIT_LIST_HEAD(&nfit_bdw->list);
+ nfit_bdw->bdw = bdw;
+ list_add_tail(&nfit_bdw->list, &acpi_desc->bdws);
+ dev_dbg(dev, "%s: bdw dcr: %d windows: %d\n", __func__,
+ bdw->region_index, bdw->windows);
+ return true;
+}
+
+static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, const void *end)
+{
+ struct device *dev = acpi_desc->dev;
+ struct acpi_nfit_header *hdr;
+ void *err = ERR_PTR(-ENOMEM);
+
+ if (table >= end)
+ return NULL;
+
+ hdr = table;
+ switch (hdr->type) {
+ case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
+ if (!add_spa(acpi_desc, table))
+ return err;
+ break;
+ case ACPI_NFIT_TYPE_MEMORY_MAP:
+ if (!add_memdev(acpi_desc, table))
+ return err;
+ break;
+ case ACPI_NFIT_TYPE_CONTROL_REGION:
+ if (!add_dcr(acpi_desc, table))
+ return err;
+ break;
+ case ACPI_NFIT_TYPE_DATA_REGION:
+ if (!add_bdw(acpi_desc, table))
+ return err;
+ break;
+ /* TODO */
+ case ACPI_NFIT_TYPE_INTERLEAVE:
+ dev_dbg(dev, "%s: idt\n", __func__);
+ break;
+ case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
+ dev_dbg(dev, "%s: flush\n", __func__);
+ break;
+ case ACPI_NFIT_TYPE_SMBIOS:
+ dev_dbg(dev, "%s: smbios\n", __func__);
+ break;
+ default:
+ dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
+ break;
+ }
+
+ return table + hdr->length;
+}
+
+static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_mem *nfit_mem)
+{
+ u32 device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
+ u16 dcr_index = nfit_mem->dcr->region_index;
+ struct nfit_spa *nfit_spa;
+
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ u16 range_index = nfit_spa->spa->range_index;
+ int type = nfit_spa_type(nfit_spa->spa);
+ struct nfit_memdev *nfit_memdev;
+
+ if (type != NFIT_SPA_BDW)
+ continue;
+
+ list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+ if (nfit_memdev->memdev->range_index != range_index)
+ continue;
+ if (nfit_memdev->memdev->device_handle != device_handle)
+ continue;
+ if (nfit_memdev->memdev->region_index != dcr_index)
+ continue;
+
+ nfit_mem->spa_bdw = nfit_spa->spa;
+ return;
+ }
+ }
+
+ dev_dbg(acpi_desc->dev, "SPA-BDW not found for SPA-DCR %d\n",
+ nfit_mem->spa_dcr->range_index);
+ nfit_mem->bdw = NULL;
+}
+
+static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
+{
+ u16 dcr_index = __to_nfit_memdev(nfit_mem)->region_index;
+ struct nfit_dcr *nfit_dcr;
+ struct nfit_bdw *nfit_bdw;
+
+ list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+ if (nfit_dcr->dcr->region_index != dcr_index)
+ continue;
+ nfit_mem->dcr = nfit_dcr->dcr;
+ break;
+ }
+
+ if (!nfit_mem->dcr) {
+ dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n", spa->range_index,
+ __to_nfit_memdev(nfit_mem) ? "" : " MEMDEV",
+ nfit_mem->dcr ? "" : " DCR");
+ return -ENODEV;
+ }
+
+ /*
+ * We've found enough to create an nvdimm, optionally
+ * find an associated BDW
+ */
+ list_add(&nfit_mem->list, &acpi_desc->dimms);
+
+ list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
+ if (nfit_bdw->bdw->region_index != dcr_index)
+ continue;
+ nfit_mem->bdw = nfit_bdw->bdw;
+ break;
+ }
+
+ if (!nfit_mem->bdw)
+ return 0;
+
+ nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
+ return 0;
+}
+
+static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
+ struct acpi_nfit_system_address *spa)
+{
+ struct nfit_mem *nfit_mem, *found;
+ struct nfit_memdev *nfit_memdev;
+ int type = nfit_spa_type(spa);
+ u16 dcr_index;
+
+ switch (type) {
+ case NFIT_SPA_DCR:
+ case NFIT_SPA_PM:
+ break;
+ default:
+ return 0;
+ }
+
+ list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
+ int rc;
+
+ if (nfit_memdev->memdev->range_index != spa->range_index)
+ continue;
+ found = NULL;
+ dcr_index = nfit_memdev->memdev->region_index;
+ list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
+ if (__to_nfit_memdev(nfit_mem)->region_index == dcr_index) {
+ found = nfit_mem;
+ break;
+ }
+
+ if (found)
+ nfit_mem = found;
+ else {
+ nfit_mem = devm_kzalloc(acpi_desc->dev,
+ sizeof(*nfit_mem), GFP_KERNEL);
+ if (!nfit_mem)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&nfit_mem->list);
+ }
+
+ if (type == NFIT_SPA_DCR) {
+ /* multiple dimms may share a SPA when interleaved */
+ nfit_mem->spa_dcr = spa;
+ nfit_mem->memdev_dcr = nfit_memdev->memdev;
+ } else {
+ /*
+ * A single dimm may belong to multiple SPA-PM
+ * ranges, record at least one in addition to
+ * any SPA-DCR range.
+ */
+ nfit_mem->memdev_pmem = nfit_memdev->memdev;
+ }
+
+ if (found)
+ continue;
+
+ rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int nfit_mem_cmp(void *priv, struct list_head *__a, struct list_head *__b)
+{
+ struct nfit_mem *a = container_of(__a, typeof(*a), list);
+ struct nfit_mem *b = container_of(__b, typeof(*b), list);
+ u32 handleA, handleB;
+
+ handleA = __to_nfit_memdev(a)->device_handle;
+ handleB = __to_nfit_memdev(b)->device_handle;
+ if (handleA < handleB)
+ return -1;
+ else if (handleA > handleB)
+ return 1;
+ return 0;
+}
+
+static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc)
+{
+ struct nfit_spa *nfit_spa;
+
+ /*
+ * For each SPA-DCR or SPA-PMEM address range find its
+ * corresponding MEMDEV(s). From each MEMDEV find the
+ * corresponding DCR. Then, if we're operating on a SPA-DCR,
+ * try to find a SPA-BDW and a corresponding BDW that references
+ * the DCR. Throw it all into an nfit_mem object. Note, that
+ * BDWs are optional.
+ */
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ int rc;
+
+ rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa);
+ if (rc)
+ return rc;
+ }
+
+ list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp);
+
+ return 0;
+}
+
+static int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
+{
+ struct device *dev = acpi_desc->dev;
+ const void *end;
+ u8 *data;
+
+ INIT_LIST_HEAD(&acpi_desc->spas);
+ INIT_LIST_HEAD(&acpi_desc->dcrs);
+ INIT_LIST_HEAD(&acpi_desc->bdws);
+ INIT_LIST_HEAD(&acpi_desc->memdevs);
+ INIT_LIST_HEAD(&acpi_desc->dimms);
+
+ data = (u8 *) acpi_desc->nfit;
+ end = data + sz;
+ data += sizeof(struct acpi_table_nfit);
+ while (!IS_ERR_OR_NULL(data))
+ data = add_table(acpi_desc, data, end);
+
+ if (IS_ERR(data)) {
+ dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
+ PTR_ERR(data));
+ return PTR_ERR(data);
+ }
+
+ if (nfit_mem_init(acpi_desc) != 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int acpi_nfit_add(struct acpi_device *adev)
+{
+ struct nvdimm_bus_descriptor *nd_desc;
+ struct acpi_nfit_desc *acpi_desc;
+ struct device *dev = &adev->dev;
+ struct acpi_table_header *tbl;
+ acpi_status status = AE_OK;
+ acpi_size sz;
+ int rc;
+
+ status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to find NFIT\n");
+ return -ENXIO;
+ }
+
+ acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+ if (!acpi_desc)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, acpi_desc);
+ acpi_desc->dev = dev;
+ acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
+ nd_desc = &acpi_desc->nd_desc;
+ nd_desc->provider_name = "ACPI.NFIT";
+ nd_desc->ndctl = acpi_nfit_ctl;
+
+ acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, nd_desc);
+ if (!acpi_desc->nvdimm_bus)
+ return -ENXIO;
+
+ rc = acpi_nfit_init(acpi_desc, sz);
+ if (rc) {
+ nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+ return rc;
+ }
+ return 0;
+}
+
+static int acpi_nfit_remove(struct acpi_device *adev)
+{
+ struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
+
+ nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+ return 0;
+}
+
+static const struct acpi_device_id acpi_nfit_ids[] = {
+ { "ACPI0012", 0 },
+ { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, acpi_nfit_ids);
+
+static struct acpi_driver acpi_nfit_driver = {
+ .name = KBUILD_MODNAME,
+ .ids = acpi_nfit_ids,
+ .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+ .ops = {
+ .add = acpi_nfit_add,
+ .remove = acpi_nfit_remove,
+ },
+};
+
+static __init int nfit_init(void)
+{
+ BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_interleave) != 20);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
+ BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
+
+ acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
+ acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
+ acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
+ acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
+ acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
+ acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
+ acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
+ acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
+ acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
+ acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
+
+ return acpi_bus_register_driver(&acpi_nfit_driver);
+}
+
+static __exit void nfit_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_nfit_driver);
+}
+
+module_init(nfit_init);
+module_exit(nfit_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
new file mode 100644
index 000000000000..2d98cc1b7b6c
--- /dev/null
+++ b/drivers/acpi/nfit.h
@@ -0,0 +1,89 @@
+/*
+ * NVDIMM Firmware Interface Table - NFIT
+ *
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __NFIT_H__
+#define __NFIT_H__
+#include <linux/libnvdimm.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+#include <linux/acpi.h>
+#include <acpi/acuuid.h>
+
+#define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
+#define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66"
+
+enum nfit_uuids {
+ NFIT_SPA_VOLATILE,
+ NFIT_SPA_PM,
+ NFIT_SPA_DCR,
+ NFIT_SPA_BDW,
+ NFIT_SPA_VDISK,
+ NFIT_SPA_VCD,
+ NFIT_SPA_PDISK,
+ NFIT_SPA_PCD,
+ NFIT_DEV_BUS,
+ NFIT_DEV_DIMM,
+ NFIT_UUID_MAX,
+};
+
+struct nfit_spa {
+ struct acpi_nfit_system_address *spa;
+ struct list_head list;
+};
+
+struct nfit_dcr {
+ struct acpi_nfit_control_region *dcr;
+ struct list_head list;
+};
+
+struct nfit_bdw {
+ struct acpi_nfit_data_region *bdw;
+ struct list_head list;
+};
+
+struct nfit_memdev {
+ struct acpi_nfit_memory_map *memdev;
+ struct list_head list;
+};
+
+/* assembled tables for a given dimm/memory-device */
+struct nfit_mem {
+ struct acpi_nfit_memory_map *memdev_dcr;
+ struct acpi_nfit_memory_map *memdev_pmem;
+ struct acpi_nfit_control_region *dcr;
+ struct acpi_nfit_data_region *bdw;
+ struct acpi_nfit_system_address *spa_dcr;
+ struct acpi_nfit_system_address *spa_bdw;
+ struct list_head list;
+};
+
+struct acpi_nfit_desc {
+ struct nvdimm_bus_descriptor nd_desc;
+ struct acpi_table_nfit *nfit;
+ struct list_head memdevs;
+ struct list_head dimms;
+ struct list_head spas;
+ struct list_head dcrs;
+ struct list_head bdws;
+ struct nvdimm_bus *nvdimm_bus;
+ struct device *dev;
+};
+
+static inline struct acpi_nfit_memory_map *__to_nfit_memdev(struct nfit_mem *nfit_mem)
+{
+ if (nfit_mem->memdev_dcr)
+ return nfit_mem->memdev_dcr;
+ return nfit_mem->memdev_pmem;
+}
+#endif /* __NFIT_H__ */
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
new file mode 100644
index 000000000000..4f2291938ea0
--- /dev/null
+++ b/drivers/nvdimm/Kconfig
@@ -0,0 +1,13 @@
+config LIBNVDIMM
+ tristate "NVDIMM (Non-Volatile Memory Device) Support"
+ help
+ Generic support for non-volatile memory devices including
+ ACPI-6-NFIT defined resources. On platforms that define an
+ NFIT, or otherwise can discover NVDIMM resources, a libnvdimm
+ bus is registered to advertise PMEM (persistent memory)
+ namespaces (/dev/pmemX) and BLK (sliding mmio window(s))
+ namespaces (/dev/ndX). A PMEM namespace refers to a memory
+ resource that may span multiple DIMMs and support DAX (see
+ CONFIG_DAX). A BLK namespace refers to an NVDIMM control
+ region which exposes an mmio register set for windowed
+ access mode to non-volatile memory.
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
new file mode 100644
index 000000000000..10bc7af47992
--- /dev/null
+++ b/drivers/nvdimm/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
+
+libnvdimm-y := core.o
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
new file mode 100644
index 000000000000..5ccd500ffd4f
--- /dev/null
+++ b/drivers/nvdimm/core.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <linux/libnvdimm.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include "nd-core.h"
+
+static DEFINE_IDA(nd_ida);
+
+static void nvdimm_bus_release(struct device *dev)
+{
+ struct nvdimm_bus *nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
+
+ ida_simple_remove(&nd_ida, nvdimm_bus->id);
+ kfree(nvdimm_bus);
+}
+
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+ struct nvdimm_bus_descriptor *nd_desc)
+{
+ struct nvdimm_bus *nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
+ int rc;
+
+ if (!nvdimm_bus)
+ return NULL;
+ nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
+ if (nvdimm_bus->id < 0) {
+ kfree(nvdimm_bus);
+ return NULL;
+ }
+ nvdimm_bus->nd_desc = nd_desc;
+ nvdimm_bus->dev.parent = parent;
+ nvdimm_bus->dev.release = nvdimm_bus_release;
+ dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
+ rc = device_register(&nvdimm_bus->dev);
+ if (rc) {
+ dev_dbg(&nvdimm_bus->dev, "device registration failed: %d\n", rc);
+ put_device(&nvdimm_bus->dev);
+ return NULL;
+ }
+
+ return nvdimm_bus;
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_register);
+
+void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
+{
+ if (!nvdimm_bus)
+ return;
+ device_unregister(&nvdimm_bus->dev);
+}
+EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
new file mode 100644
index 000000000000..e7c4e99a22a4
--- /dev/null
+++ b/drivers/nvdimm/nd-core.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __ND_PRIVATE_H__
+#define __ND_PRIVATE_H__
+#include <linux/libnvdimm.h>
+#include <linux/device.h>
+
+struct nvdimm_bus {
+ struct nvdimm_bus_descriptor *nd_desc;
+ struct device dev;
+ int id;
+};
+#endif /* __ND_PRIVATE_H__ */
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
new file mode 100644
index 000000000000..2b3c63950c91
--- /dev/null
+++ b/include/linux/libnvdimm.h
@@ -0,0 +1,34 @@
+/*
+ * libnvdimm - Non-volatile-memory Devices Subsystem
+ *
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __LIBNVDIMM_H__
+#define __LIBNVDIMM_H__
+struct nvdimm;
+struct nvdimm_bus_descriptor;
+typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
+ struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+ unsigned int buf_len);
+
+struct nvdimm_bus_descriptor {
+ unsigned long dsm_mask;
+ char *provider_name;
+ ndctl_fn ndctl;
+};
+
+struct device;
+struct nvdimm_bus;
+struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
+ struct nvdimm_bus_descriptor *nfit_desc);
+void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
+#endif /* __LIBNVDIMM_H__ */
^ permalink raw reply related
* Re: [PATCH v5 09/21] libnvdimm, nd_pmem: add libnvdimm support to the pmem driver
From: Williams, Dan J @ 2015-06-03 19:31 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
linux-nvdimm-y27Ovi1pjclAfugRpC6u6w@public.gmane.org,
neilb-l3A5Bk7waGM@public.gmane.org,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
hch-jcswGhMUV9g@public.gmane.org,
axboe-tSWWG44O7X1aa/9Udqfwiw@public.gmane.org,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org,
sfr-3FnU+UHB4dNDw9hX6IcOSA@public.gmane.org,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org,
rafael-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
linux-acpi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20150603074424.GA24949-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
On Wed, 2015-06-03 at 00:44 -0700, Christoph Hellwig wrote:
> This patch doesn't apply, as it seems to use some git magic.
>
> But looking at it it's also wrong in that it mixes a file move
> and actual changes to the file.
I like move-modify patches because they make the reason for the move
clearer and revertible. Consider a general case where we later decide
the reason for a move was invalid. Reverting the reason also reverts
the file move, that doesn't automatically happen when it is split to
another commit.
In case you don't want to mess around with 'git apply' here's the
unmagical version of the patch (rebased according to the comments you
made to patch 2)...
8<---
libnvdimm, nd_pmem: add libnvdimm support to the pmem driver
From: Dan Williams <dan.j.williams@intel.com>
nd_pmem attaches to persistent memory regions and namespaces emitted by
the libnvdimm subsystem, and, same as the original pmem driver, presents
the system-physical-address range as a block device.
The existing e820-type-12 to pmem setup is converted to a full libnvdimm
bus that emits an nd_namespace_io device.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
arch/x86/Kconfig | 3 +
arch/x86/kernel/pmem.c | 92 +++++++++++------
drivers/block/Kconfig | 11 --
drivers/block/Makefile | 1
drivers/block/pmem.c | 262 -----------------------------------------------
drivers/nvdimm/Kconfig | 22 ++++
drivers/nvdimm/Makefile | 3 +
drivers/nvdimm/pmem.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 347 insertions(+), 307 deletions(-)
delete mode 100644 drivers/block/pmem.c
create mode 100644 drivers/nvdimm/pmem.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 226d5696e1d1..1a2cbf641667 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1424,6 +1424,9 @@ source "mm/Kconfig"
config X86_PMEM_LEGACY
bool "Support non-standard NVDIMMs and ADR protected memory"
+ depends on PHYS_ADDR_T_64BIT
+ depends on BLK_DEV
+ select LIBNVDIMM
help
Treat memory marked using the non-standard e820 type of 12 as used
by the Intel Sandy Bridge-EP reference BIOS as protected memory.
diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c
index 3420c874ddc5..40d734c8e3b1 100644
--- a/arch/x86/kernel/pmem.c
+++ b/arch/x86/kernel/pmem.c
@@ -1,53 +1,81 @@
/*
* Copyright (c) 2015, Christoph Hellwig.
+ * Copyright (c) 2015, Intel Corporation.
*/
-#include <linux/memblock.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/libnvdimm.h>
+#include <linux/module.h>
#include <asm/e820.h>
-#include <asm/page_types.h>
-#include <asm/setup.h>
-static __init void register_pmem_device(struct resource *res)
+static void e820_pmem_release(struct device *dev)
{
- struct platform_device *pdev;
- int error;
+ struct nvdimm_bus *nvdimm_bus = dev->platform_data;
- pdev = platform_device_alloc("pmem", PLATFORM_DEVID_AUTO);
- if (!pdev)
- return;
+ if (nvdimm_bus)
+ nvdimm_bus_unregister(nvdimm_bus);
+}
- error = platform_device_add_resources(pdev, res, 1);
- if (error)
- goto out_put_pdev;
+static struct platform_device e820_pmem = {
+ .name = "e820_pmem",
+ .id = -1,
+ .dev = {
+ .release = e820_pmem_release,
+ },
+};
- error = platform_device_add(pdev);
- if (error)
- goto out_put_pdev;
- return;
+static const struct attribute_group *e820_pmem_attribute_groups[] = {
+ &nvdimm_bus_attribute_group,
+ NULL,
+};
-out_put_pdev:
- dev_warn(&pdev->dev, "failed to add 'pmem' (persistent memory) device!\n");
- platform_device_put(pdev);
-}
+static const struct attribute_group *e820_pmem_region_attribute_groups[] = {
+ &nd_region_attribute_group,
+ &nd_device_attribute_group,
+ NULL,
+};
-static __init int register_pmem_devices(void)
+static __init int register_e820_pmem(void)
{
- int i;
+ static struct nvdimm_bus_descriptor nd_desc;
+ struct device *dev = &e820_pmem.dev;
+ struct nvdimm_bus *nvdimm_bus;
+ int rc, i;
+
+ rc = platform_device_register(&e820_pmem);
+ if (rc)
+ return rc;
+
+ nd_desc.attr_groups = e820_pmem_attribute_groups;
+ nd_desc.provider_name = "e820";
+ nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
+ if (!nvdimm_bus)
+ goto err;
+ dev->platform_data = nvdimm_bus;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
+ struct resource res = {
+ .flags = IORESOURCE_MEM,
+ .start = ei->addr,
+ .end = ei->addr + ei->size - 1,
+ };
+ struct nd_region_desc ndr_desc;
+
+ if (ei->type != E820_PRAM)
+ continue;
- if (ei->type == E820_PRAM) {
- struct resource res = {
- .flags = IORESOURCE_MEM,
- .start = ei->addr,
- .end = ei->addr + ei->size - 1,
- };
- register_pmem_device(&res);
- }
+ memset(&ndr_desc, 0, sizeof(ndr_desc));
+ ndr_desc.res = &res;
+ ndr_desc.attr_groups = e820_pmem_region_attribute_groups;
+ if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
+ goto err;
}
return 0;
+
+ err:
+ dev_err(dev, "failed to register legacy persistent memory ranges\n");
+ platform_device_unregister(&e820_pmem);
+ return -ENXIO;
}
-device_initcall(register_pmem_devices);
+late_initcall(register_e820_pmem);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index eb1fed5bd516..1b8094d4d7af 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -404,17 +404,6 @@ config BLK_DEV_RAM_DAX
and will prevent RAM block device backing store memory from being
allocated from highmem (only a problem for highmem systems).
-config BLK_DEV_PMEM
- tristate "Persistent memory block device support"
- help
- Saying Y here will allow you to use a contiguous range of reserved
- memory as one or more persistent block devices.
-
- To compile this driver as a module, choose M here: the module will be
- called 'pmem'.
-
- If unsure, say N.
-
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
depends on !UML
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9cc6c18a1c7e..02b688d1438d 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_PS3_VRAM) += ps3vram.o
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_BLK_DEV_RAM) += brd.o
-obj-$(CONFIG_BLK_DEV_PMEM) += pmem.o
obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
diff --git a/drivers/block/pmem.c b/drivers/block/pmem.c
deleted file mode 100644
index eabf4a8d0085..000000000000
--- a/drivers/block/pmem.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Persistent Memory Driver
- *
- * Copyright (c) 2014, Intel Corporation.
- * Copyright (c) 2015, Christoph Hellwig <hch@lst.de>.
- * Copyright (c) 2015, Boaz Harrosh <boaz@plexistor.com>.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- */
-
-#include <asm/cacheflush.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-
-#define PMEM_MINORS 16
-
-struct pmem_device {
- struct request_queue *pmem_queue;
- struct gendisk *pmem_disk;
-
- /* One contiguous memory region per device */
- phys_addr_t phys_addr;
- void *virt_addr;
- size_t size;
-};
-
-static int pmem_major;
-static atomic_t pmem_index;
-
-static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
- unsigned int len, unsigned int off, int rw,
- sector_t sector)
-{
- void *mem = kmap_atomic(page);
- size_t pmem_off = sector << 9;
-
- if (rw == READ) {
- memcpy(mem + off, pmem->virt_addr + pmem_off, len);
- flush_dcache_page(page);
- } else {
- flush_dcache_page(page);
- memcpy(pmem->virt_addr + pmem_off, mem + off, len);
- }
-
- kunmap_atomic(mem);
-}
-
-static void pmem_make_request(struct request_queue *q, struct bio *bio)
-{
- struct block_device *bdev = bio->bi_bdev;
- struct pmem_device *pmem = bdev->bd_disk->private_data;
- int rw;
- struct bio_vec bvec;
- sector_t sector;
- struct bvec_iter iter;
- int err = 0;
-
- if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) {
- err = -EIO;
- goto out;
- }
-
- BUG_ON(bio->bi_rw & REQ_DISCARD);
-
- rw = bio_data_dir(bio);
- sector = bio->bi_iter.bi_sector;
- bio_for_each_segment(bvec, bio, iter) {
- pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len, bvec.bv_offset,
- rw, sector);
- sector += bvec.bv_len >> 9;
- }
-
-out:
- bio_endio(bio, err);
-}
-
-static int pmem_rw_page(struct block_device *bdev, sector_t sector,
- struct page *page, int rw)
-{
- struct pmem_device *pmem = bdev->bd_disk->private_data;
-
- pmem_do_bvec(pmem, page, PAGE_CACHE_SIZE, 0, rw, sector);
- page_endio(page, rw & WRITE, 0);
-
- return 0;
-}
-
-static long pmem_direct_access(struct block_device *bdev, sector_t sector,
- void **kaddr, unsigned long *pfn, long size)
-{
- struct pmem_device *pmem = bdev->bd_disk->private_data;
- size_t offset = sector << 9;
-
- if (!pmem)
- return -ENODEV;
-
- *kaddr = pmem->virt_addr + offset;
- *pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT;
-
- return pmem->size - offset;
-}
-
-static const struct block_device_operations pmem_fops = {
- .owner = THIS_MODULE,
- .rw_page = pmem_rw_page,
- .direct_access = pmem_direct_access,
-};
-
-static struct pmem_device *pmem_alloc(struct device *dev, struct resource *res)
-{
- struct pmem_device *pmem;
- struct gendisk *disk;
- int idx, err;
-
- err = -ENOMEM;
- pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
- if (!pmem)
- goto out;
-
- pmem->phys_addr = res->start;
- pmem->size = resource_size(res);
-
- err = -EINVAL;
- if (!request_mem_region(pmem->phys_addr, pmem->size, "pmem")) {
- dev_warn(dev, "could not reserve region [0x%pa:0x%zx]\n", &pmem->phys_addr, pmem->size);
- goto out_free_dev;
- }
-
- /*
- * Map the memory as non-cachable, as we can't write back the contents
- * of the CPU caches in case of a crash.
- */
- err = -ENOMEM;
- pmem->virt_addr = ioremap_nocache(pmem->phys_addr, pmem->size);
- if (!pmem->virt_addr)
- goto out_release_region;
-
- pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL);
- if (!pmem->pmem_queue)
- goto out_unmap;
-
- blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
- blk_queue_max_hw_sectors(pmem->pmem_queue, 1024);
- blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY);
-
- disk = alloc_disk(PMEM_MINORS);
- if (!disk)
- goto out_free_queue;
-
- idx = atomic_inc_return(&pmem_index) - 1;
-
- disk->major = pmem_major;
- disk->first_minor = PMEM_MINORS * idx;
- disk->fops = &pmem_fops;
- disk->private_data = pmem;
- disk->queue = pmem->pmem_queue;
- disk->flags = GENHD_FL_EXT_DEVT;
- sprintf(disk->disk_name, "pmem%d", idx);
- disk->driverfs_dev = dev;
- set_capacity(disk, pmem->size >> 9);
- pmem->pmem_disk = disk;
-
- add_disk(disk);
-
- return pmem;
-
-out_free_queue:
- blk_cleanup_queue(pmem->pmem_queue);
-out_unmap:
- iounmap(pmem->virt_addr);
-out_release_region:
- release_mem_region(pmem->phys_addr, pmem->size);
-out_free_dev:
- kfree(pmem);
-out:
- return ERR_PTR(err);
-}
-
-static void pmem_free(struct pmem_device *pmem)
-{
- del_gendisk(pmem->pmem_disk);
- put_disk(pmem->pmem_disk);
- blk_cleanup_queue(pmem->pmem_queue);
- iounmap(pmem->virt_addr);
- release_mem_region(pmem->phys_addr, pmem->size);
- kfree(pmem);
-}
-
-static int pmem_probe(struct platform_device *pdev)
-{
- struct pmem_device *pmem;
- struct resource *res;
-
- if (WARN_ON(pdev->num_resources > 1))
- return -ENXIO;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- pmem = pmem_alloc(&pdev->dev, res);
- if (IS_ERR(pmem))
- return PTR_ERR(pmem);
-
- platform_set_drvdata(pdev, pmem);
-
- return 0;
-}
-
-static int pmem_remove(struct platform_device *pdev)
-{
- struct pmem_device *pmem = platform_get_drvdata(pdev);
-
- pmem_free(pmem);
- return 0;
-}
-
-static struct platform_driver pmem_driver = {
- .probe = pmem_probe,
- .remove = pmem_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "pmem",
- },
-};
-
-static int __init pmem_init(void)
-{
- int error;
-
- pmem_major = register_blkdev(0, "pmem");
- if (pmem_major < 0)
- return pmem_major;
-
- error = platform_driver_register(&pmem_driver);
- if (error)
- unregister_blkdev(pmem_major, "pmem");
- return error;
-}
-module_init(pmem_init);
-
-static void pmem_exit(void)
-{
- platform_driver_unregister(&pmem_driver);
- unregister_blkdev(pmem_major, "pmem");
-}
-module_exit(pmem_exit);
-
-MODULE_AUTHOR("Ross Zwisler <ross.zwisler@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
index 4f2291938ea0..818f219b037c 100644
--- a/drivers/nvdimm/Kconfig
+++ b/drivers/nvdimm/Kconfig
@@ -1,4 +1,4 @@
-config LIBNVDIMM
+menuconfig LIBNVDIMM
tristate "NVDIMM (Non-Volatile Memory Device) Support"
help
Generic support for non-volatile memory devices including
@@ -11,3 +11,23 @@ config LIBNVDIMM
CONFIG_DAX). A BLK namespace refers to an NVDIMM control
region which exposes an mmio register set for windowed
access mode to non-volatile memory.
+
+if LIBNVDIMM
+
+config BLK_DEV_PMEM
+ tristate "PMEM: Persistent memory block device support"
+ default LIBNVDIMM
+ help
+ Memory ranges for PMEM are described by either an NFIT
+ (NVDIMM Firmware Interface Table, see CONFIG_NFIT_ACPI), a
+ non-standard OEM-specific E820 memory type (type-12, see
+ CONFIG_X86_PMEM_LEGACY), or it is manually specified by the
+ 'memmap=nn[KMG]!ss[KMG]' kernel command line (see
+ Documentation/kernel-parameters.txt). This driver converts
+ these persistent memory ranges into block devices that are
+ capable of DAX (direct-access) file system mappings. See
+ Documentation/blockdev/nd.txt for more details.
+
+ Say Y if you want to use a NVDIMM described by NFIT
+
+endif
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index af5e2760ddbd..4d2a27f52faa 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -1,4 +1,7 @@
obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
+obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
+
+nd_pmem-y := pmem.o
libnvdimm-y := core.o
libnvdimm-y += bus.o
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
new file mode 100644
index 000000000000..cf5d53eda9e5
--- /dev/null
+++ b/drivers/nvdimm/pmem.c
@@ -0,0 +1,260 @@
+/*
+ * Persistent Memory Driver
+ *
+ * Copyright (c) 2014-2015, Intel Corporation.
+ * Copyright (c) 2015, Christoph Hellwig <hch@lst.de>.
+ * Copyright (c) 2015, Boaz Harrosh <boaz@plexistor.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/nd.h>
+#include "nd.h"
+
+#define PMEM_MINORS 16
+
+struct pmem_device {
+ struct request_queue *pmem_queue;
+ struct gendisk *pmem_disk;
+
+ /* One contiguous memory region per device */
+ phys_addr_t phys_addr;
+ void *virt_addr;
+ size_t size;
+};
+
+static int pmem_major;
+
+static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
+ unsigned int len, unsigned int off, int rw,
+ sector_t sector)
+{
+ void *mem = kmap_atomic(page);
+ size_t pmem_off = sector << 9;
+
+ if (rw == READ) {
+ memcpy(mem + off, pmem->virt_addr + pmem_off, len);
+ flush_dcache_page(page);
+ } else {
+ flush_dcache_page(page);
+ memcpy(pmem->virt_addr + pmem_off, mem + off, len);
+ }
+
+ kunmap_atomic(mem);
+}
+
+static void pmem_make_request(struct request_queue *q, struct bio *bio)
+{
+ struct block_device *bdev = bio->bi_bdev;
+ struct pmem_device *pmem = bdev->bd_disk->private_data;
+ int rw;
+ struct bio_vec bvec;
+ sector_t sector;
+ struct bvec_iter iter;
+ int err = 0;
+
+ if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) {
+ err = -EIO;
+ goto out;
+ }
+
+ BUG_ON(bio->bi_rw & REQ_DISCARD);
+
+ rw = bio_data_dir(bio);
+ sector = bio->bi_iter.bi_sector;
+ bio_for_each_segment(bvec, bio, iter) {
+ pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len, bvec.bv_offset,
+ rw, sector);
+ sector += bvec.bv_len >> 9;
+ }
+
+out:
+ bio_endio(bio, err);
+}
+
+static int pmem_rw_page(struct block_device *bdev, sector_t sector,
+ struct page *page, int rw)
+{
+ struct pmem_device *pmem = bdev->bd_disk->private_data;
+
+ pmem_do_bvec(pmem, page, PAGE_CACHE_SIZE, 0, rw, sector);
+ page_endio(page, rw & WRITE, 0);
+
+ return 0;
+}
+
+static long pmem_direct_access(struct block_device *bdev, sector_t sector,
+ void **kaddr, unsigned long *pfn, long size)
+{
+ struct pmem_device *pmem = bdev->bd_disk->private_data;
+ size_t offset = sector << 9;
+
+ if (!pmem)
+ return -ENODEV;
+
+ *kaddr = pmem->virt_addr + offset;
+ *pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT;
+
+ return pmem->size - offset;
+}
+
+static const struct block_device_operations pmem_fops = {
+ .owner = THIS_MODULE,
+ .rw_page = pmem_rw_page,
+ .direct_access = pmem_direct_access,
+};
+
+static struct pmem_device *pmem_alloc(struct device *dev, struct resource *res, int id)
+{
+ struct pmem_device *pmem;
+ struct gendisk *disk;
+ int err;
+
+ err = -ENOMEM;
+ pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
+ if (!pmem)
+ goto out;
+
+ pmem->phys_addr = res->start;
+ pmem->size = resource_size(res);
+
+ err = -EINVAL;
+ if (!request_mem_region(pmem->phys_addr, pmem->size, "pmem")) {
+ dev_warn(dev, "could not reserve region [0x%pa:0x%zx]\n", &pmem->phys_addr, pmem->size);
+ goto out_free_dev;
+ }
+
+ /*
+ * Map the memory as non-cachable, as we can't write back the contents
+ * of the CPU caches in case of a crash.
+ */
+ err = -ENOMEM;
+ pmem->virt_addr = ioremap_nocache(pmem->phys_addr, pmem->size);
+ if (!pmem->virt_addr)
+ goto out_release_region;
+
+ pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL);
+ if (!pmem->pmem_queue)
+ goto out_unmap;
+
+ blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
+ blk_queue_max_hw_sectors(pmem->pmem_queue, 1024);
+ blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY);
+
+ disk = alloc_disk(PMEM_MINORS);
+ if (!disk)
+ goto out_free_queue;
+
+ disk->major = pmem_major;
+ disk->first_minor = PMEM_MINORS * id;
+ disk->fops = &pmem_fops;
+ disk->private_data = pmem;
+ disk->queue = pmem->pmem_queue;
+ disk->flags = GENHD_FL_EXT_DEVT;
+ sprintf(disk->disk_name, "pmem%d", id);
+ disk->driverfs_dev = dev;
+ set_capacity(disk, pmem->size >> 9);
+ pmem->pmem_disk = disk;
+
+ add_disk(disk);
+
+ return pmem;
+
+out_free_queue:
+ blk_cleanup_queue(pmem->pmem_queue);
+out_unmap:
+ iounmap(pmem->virt_addr);
+out_release_region:
+ release_mem_region(pmem->phys_addr, pmem->size);
+out_free_dev:
+ kfree(pmem);
+out:
+ return ERR_PTR(err);
+}
+
+static void pmem_free(struct pmem_device *pmem)
+{
+ del_gendisk(pmem->pmem_disk);
+ put_disk(pmem->pmem_disk);
+ blk_cleanup_queue(pmem->pmem_queue);
+ iounmap(pmem->virt_addr);
+ release_mem_region(pmem->phys_addr, pmem->size);
+ kfree(pmem);
+}
+
+static int nd_pmem_probe(struct device *dev)
+{
+ struct nd_region *nd_region = to_nd_region(dev->parent);
+ struct nd_namespace_io *nsio = to_nd_namespace_io(dev);
+ struct pmem_device *pmem;
+
+ pmem = pmem_alloc(dev, &nsio->res, nd_region->id);
+ if (IS_ERR(pmem))
+ return PTR_ERR(pmem);
+
+ dev_set_drvdata(dev, pmem);
+
+ return 0;
+}
+
+static int nd_pmem_remove(struct device *dev)
+{
+ struct pmem_device *pmem = dev_get_drvdata(dev);
+
+ pmem_free(pmem);
+ return 0;
+}
+
+MODULE_ALIAS("pmem");
+MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_IO);
+static struct nd_device_driver nd_pmem_driver = {
+ .probe = nd_pmem_probe,
+ .remove = nd_pmem_remove,
+ .drv = {
+ .name = "nd_pmem",
+ },
+ .type = ND_DRIVER_NAMESPACE_IO,
+};
+
+static int __init pmem_init(void)
+{
+ int error;
+
+ pmem_major = register_blkdev(0, "pmem");
+ if (pmem_major < 0)
+ return pmem_major;
+
+ error = nd_driver_register(&nd_pmem_driver);
+ if (error) {
+ unregister_blkdev(pmem_major, "pmem");
+ return error;
+ }
+
+ return 0;
+}
+module_init(pmem_init);
+
+static void pmem_exit(void)
+{
+ driver_unregister(&nd_pmem_driver.drv);
+ unregister_blkdev(pmem_major, "pmem");
+}
+module_exit(pmem_exit);
+
+MODULE_AUTHOR("Ross Zwisler <ross.zwisler@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
^ permalink raw reply related
* Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)
From: Eric W. Biederman @ 2015-06-03 21:13 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Kenton Varda, Serge Hallyn, Seth Forshee, Linux API,
Linux Containers, Greg Kroah-Hartman, Michael Kerrisk-manpages,
Richard Weinberger, Linux FS Devel, Tejun Heo
In-Reply-To: <CALCETrVEA0Ug+3aj5rjupqZub-1tPLw+szzbs4kTyEyVvNs7qg@mail.gmail.com>
Andy Lutomirski <luto@amacapital.net> writes:
> One option would be to break the nosuid, nodev, and noexec parts into
> their own patch and then avoid tagging that patch for -stable if at
> all possible. It would be nice to avoid another -stable ABI break if
> at all possible.
So I don't think we actually have anything that could be called an ABI
break in the whole mess, but it is definitely a behavioral change that
is a regression for lxc and libvirt-lxc that prevents them from starting.
nodev does not actually matter because of the implicit silliness that
is being added right now.
We do want those programs fixed and after those programs are fixed we
can safely begin failing mount when those attributes are being cleared
in a fresh mount.
So it looks to me like the best thing to do is to print a warning
whenever lxc or libvirt-lxc gets it wrong, which should ensure the
authors are sufficiently pestered that in a kernel release or 3 we can
begin enforcing those attributes. Especially as the discussion on the
fix for those applications has already begun.
And if folks would double check the patch I am going to post in a moment
to ensure that lxc and libvirt-lxc continue to start I would appreciate it.
Eric
^ permalink raw reply
* [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible
From: Eric W. Biederman @ 2015-06-03 21:15 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Richard Weinberger, Seth Forshee, Greg Kroah-Hartman,
Linux Containers, Serge Hallyn, Kenton Varda,
Michael Kerrisk-manpages, Linux API, Linux FS Devel, Tejun Heo
In-Reply-To: <87k2vkebri.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
Not allowing programs to clear nosuid, nodev, and noexec on new mounts
of sysfs or proc will cause lxc and libvirt-lxc to fail to start (a
regression). There are no device nodes or executables on sysfs or
proc today which means clearing these flags is harmless today.
Instead of failing the fresh mounts of sysfs and proc emit a warning
when these flags are improprely cleared. We only reach this point
because lxc and libvirt-lxc clear flags they mount flags had not
intended to.
In a couple of kernel releases when lxc and libvirt-lxc have been
fixed we can start failing fresh mounts proc and sysfs that clear
nosuid, nodev and noexec. Userspace clearly means to enforce those
attributes and historically they have avoided bugs.
Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
fs/namespace.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index eccd925c6e82..eaa49b628d28 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3198,6 +3198,7 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) &&
!(new_flags & MNT_READONLY))
continue;
+#if 0 /* Avoid unnecessary regressions */
if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
!(new_flags & MNT_NODEV))
continue;
@@ -3207,6 +3208,7 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
!(new_flags & MNT_NOEXEC))
continue;
+#endif
if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
continue;
@@ -3226,10 +3228,35 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
}
/* Preserve the locked attributes */
*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
+ /* Avoid unnecessary regressions \
MNT_LOCK_NODEV | \
MNT_LOCK_NOSUID | \
MNT_LOCK_NOEXEC | \
+ */ \
MNT_LOCK_ATIME);
+ /* For now, warn about the "harmless" but invalid mnt flags */
+ {
+ bool nodev = false, nosuid = false, noexec = false;
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
+ !(new_flags & MNT_NODEV))
+ nodev = true;
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
+ !(new_flags & MNT_NOSUID))
+ nosuid = true;
+ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
+ !(new_flags & MNT_NOEXEC))
+ noexec = true;
+
+ if ((nodev || nosuid || noexec) && printk_ratelimit()) {
+ printk(KERN_INFO
+ "warning: process `%s' clears %s%s%sin mount of %s\n",
+ current->comm,
+ nodev ? "nodev ":"",
+ nosuid ? "nosuid ":"",
+ noexec ? "noexec ":"",
+ type->name);
+ }
+ }
visible = true;
goto found;
next: ;
--
2.2.1
^ permalink raw reply related
* [PATCH v2] seccomp: add ptrace options for suspend/resume
From: Tycho Andersen @ 2015-06-03 22:09 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
Cc: Tycho Andersen, Kees Cook, Andy Lutomirski, Will Drewry,
Roland McGrath, Oleg Nesterov, Pavel Emelyanov, Serge E. Hallyn
This patch is the first step in enabling checkpoint/restore of processes
with seccomp enabled.
One of the things CRIU does while dumping tasks is inject code into them
via ptrace to collect information that is only available to the process
itself. However, if we are in a seccomp mode where these processes are
prohibited from making these syscalls, then what CRIU does kills the task.
This patch adds a new ptrace option, PTRACE_O_SUSPEND_SECCOMP, that enables
a task from the init user namespace which has CAP_SYS_ADMIN and no seccomp
filters to disable (and re-enable) seccomp filters for another task so that
they can be successfully dumped (and restored). We restrict the set of
processes that can disable seccomp through ptrace because although today
ptrace can be used to bypass seccomp, there is some discussion of closing
this loophole in the future and we would like this patch to not depend on
that behavior and be future proofed for when it is removed.
Note that seccomp can be suspended before any filters are actually
installed; this behavior is useful on criu restore, so that we can suspend
seccomp, restore the filters, unmap our restore code from the restored
process' address space, and then resume the task by detaching and have the
filters resumed as well.
v2 changes:
* require that the tracer have no seccomp filters installed
* drop TIF_NOTSC manipulation from the patch
* change from ptrace command to a ptrace option and use this ptrace option
as the flag to check. This means that as soon as the tracer
detaches/dies, seccomp is re-enabled and as a corrollary that one can not
disable seccomp across PTRACE_ATTACHs.
Signed-off-by: Tycho Andersen <tycho.andersen-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
CC: Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
CC: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
CC: Will Drewry <wad-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
CC: Roland McGrath <roland-/Z5OmTQCD9xF6kxbq+BtvQ@public.gmane.org>
CC: Oleg Nesterov <oleg-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
CC: Pavel Emelyanov <xemul-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
CC: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
---
include/linux/ptrace.h | 1 +
include/linux/seccomp.h | 4 ++++
include/uapi/linux/ptrace.h | 6 ++++--
kernel/ptrace.c | 6 ++++++
kernel/seccomp.c | 23 +++++++++++++++++++++++
5 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 987a73a..061265f 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -34,6 +34,7 @@
#define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP)
#define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
+#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT)
/* single stepping state bits (used on ARM and PA-RISC) */
#define PT_SINGLESTEP_BIT 31
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index a19ddac..ae3ec52 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -53,6 +53,10 @@ static inline int seccomp_mode(struct seccomp *s)
return s->mode;
}
+#ifdef CONFIG_CHECKPOINT_RESTORE
+extern bool may_suspend_seccomp(void);
+#endif
+
#else /* CONFIG_SECCOMP */
#include <linux/errno.h>
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index cf1019e..a7a6979 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -89,9 +89,11 @@ struct ptrace_peeksiginfo_args {
#define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP)
/* eventless options */
-#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_SUSPEND_SECCOMP (1 << 21)
-#define PTRACE_O_MASK (0x000000ff | PTRACE_O_EXITKILL)
+#define PTRACE_O_MASK (\
+ 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP)
#include <asm/ptrace.h>
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c8e0e05..e3e68a2 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -15,6 +15,7 @@
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/ptrace.h>
+#include <linux/seccomp.h>
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/uio.h>
@@ -556,6 +557,11 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
if (data & ~(unsigned long)PTRACE_O_MASK)
return -EINVAL;
+#ifdef CONFIG_CHECKPOINT_RESTORE
+ if (data & PTRACE_O_SUSPEND_SECCOMP && !may_suspend_seccomp())
+ return -EPERM;
+#endif
+
/* Avoid intermediate state when all opts are cleared */
flags = child->ptrace;
flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 980fd26..2a1bd35 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -590,6 +590,11 @@ void secure_computing_strict(int this_syscall)
{
int mode = current->seccomp.mode;
+#ifdef CONFIG_CHECKPOINT_RESTORE
+ if (unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+ return;
+#endif
+
if (mode == 0)
return;
else if (mode == SECCOMP_MODE_STRICT)
@@ -691,6 +696,11 @@ u32 seccomp_phase1(struct seccomp_data *sd)
int this_syscall = sd ? sd->nr :
syscall_get_nr(current, task_pt_regs(current));
+#ifdef CONFIG_CHECKPOINT_RESTORE
+ if (unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+ return SECCOMP_PHASE1_OK;
+#endif
+
switch (mode) {
case SECCOMP_MODE_STRICT:
__secure_computing_strict(this_syscall); /* may call do_exit */
@@ -901,3 +911,16 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
/* prctl interface doesn't have flags, so they are always zero. */
return do_seccomp(op, 0, uargs);
}
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+bool may_suspend_seccomp(void)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return false;
+
+ if (current->seccomp.mode != SECCOMP_MODE_DISABLED)
+ return false;
+
+ return true;
+}
+#endif /* CONFIG_CHECKPOINT_RESTORE */
--
2.1.4
^ permalink raw reply related
* [CFT][PATCH 11/10] mnt: Avoid unnecessary regressions in fs_fully_visible (take 2)
From: Eric W. Biederman @ 2015-06-04 4:35 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Kenton Varda, Serge Hallyn, Seth Forshee, Linux API,
Linux Containers, Greg Kroah-Hartman, Michael Kerrisk-manpages,
Richard Weinberger, Linux FS Devel, Tejun Heo
In-Reply-To: <87eglseboh.fsf_-_-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
Not allowing programs to clear nosuid and noexec on new mounts of
sysfs or proc will cause lxc and libvirt-lxc to fail to start (a
regression). There are no executables files on sysfs or proc today
which means clearing these flags is harmless today.
Instead of failing the fresh mounts of sysfs and proc emit a warning
when these flags are improprely cleared. We only reach this point
because lxc and libvirt-lxc clear flags they mount flags had not
intended to.
In a couple of kernel releases when lxc and libvirt-lxc have been
fixed we can start failing fresh mounts proc and sysfs that clear
nosuid and noexec. Userspace clearly means to enforce those
attributes and enforcing these attributes have historically avoided
bugs in the setattr implementations of proc and sysfs.
Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
Now with warning on problematic remounts as well.
nodev is also ignored because it is not currently problematic.
fs/namespace.c | 33 +++++++++++++++++++++++++++++++++
include/linux/mount.h | 5 +++++
2 files changed, 38 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index eccd925c6e82..3c3f8172c734 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2162,6 +2162,18 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) {
return -EPERM;
}
+ if ((mnt->mnt.mnt_flags & MNT_WARN_NOSUID) &&
+ !(mnt_flags & MNT_NOSUID) && printk_ratelimit()) {
+ printk(KERN_INFO
+ "warning: process `%s' clears nosuid in remount of %s\n",
+ current->comm, sb->s_type->name);
+ }
+ if ((mnt->mnt.mnt_flags & MNT_WARN_NOEXEC) &&
+ !(mnt_flags & MNT_NOEXEC) && printk_ratelimit()) {
+ printk(KERN_INFO
+ "warning: process `%s' clears noexec in remount of %s\n",
+ current->comm, sb->s_type->name);
+ }
err = security_sb_remount(sb, data);
if (err)
@@ -3201,12 +3213,14 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
!(new_flags & MNT_NODEV))
continue;
+#if 0 /* Avoid unnecessary regressions */
if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
!(new_flags & MNT_NOSUID))
continue;
if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) &&
!(new_flags & MNT_NOEXEC))
continue;
+#endif
if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) &&
((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))
continue;
@@ -3227,9 +3241,28 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)
/* Preserve the locked attributes */
*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \
MNT_LOCK_NODEV | \
+ /* Avoid unnecessary regressions \
MNT_LOCK_NOSUID | \
MNT_LOCK_NOEXEC | \
+ */ \
MNT_LOCK_ATIME);
+ /* For now, warn about the "harmless" but invalid mnt flags */
+ if (mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) {
+ *new_mnt_flags |= MNT_WARN_NOSUID;
+ if (!(new_flags & MNT_NOSUID) && printk_ratelimit()) {
+ printk(KERN_INFO
+ "warning: process `%s' clears nosuid in mount of %s\n",
+ current->comm, type->name);
+ }
+ }
+ if (mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) {
+ *new_mnt_flags |= MNT_WARN_NOEXEC;
+ if (!(new_flags & MNT_NOEXEC) && printk_ratelimit()) {
+ printk(KERN_INFO
+ "warning: process `%s' clears noexec in mount of %s\n",
+ current->comm, type->name);
+ }
+ }
visible = true;
goto found;
next: ;
diff --git a/include/linux/mount.h b/include/linux/mount.h
index f822c3c11377..a9ac188413fd 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -52,6 +52,11 @@ struct mnt_namespace;
#define MNT_INTERNAL 0x4000
+/* These warning options should be removed in a few kernel releases
+ * once userspace has been fixed.
+ */
+#define MNT_WARN_NOSUID 0x010000
+#define MNT_WARN_NOEXEC 0x020000
#define MNT_LOCK_ATIME 0x040000
#define MNT_LOCK_NOEXEC 0x080000
#define MNT_LOCK_NOSUID 0x100000
--
2.2.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox