Linux userland API discussions
 help / color / mirror / Atom feed
* Re: Odd hang on suspend and shutdown
From: Linus Torvalds @ 2015-07-06 17:29 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Tomas Winkler, Greg Kroah-Hartman, Linux API
In-Reply-To: <20150706165959.GB22015-nKCvNrh56OoJmsy6czSMtA@public.gmane.org>

On Mon, Jul 6, 2015 at 9:59 AM, Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org> wrote:
>
> Ok, if you can suspend after this modprobe we're looking at some
> potential mei bus or mei core issues.

Just looking at the mei/bus.c code to match the driver, and it looks just odd.

Before the commit that breaks for me, it used to have this loop:

-       while (id->name[0]) {

and now it has

+       while (uuid_le_cmp(NULL_UUID_LE, uuid_le_cast(id->uuid))) {

which seems to mean that together with my change to make a working
kernel (just removing the UUID entirely) means that now the
device_driver isn't matched against anything at all any more.

So I'm not sure "modprobe pn544_mei" ends up actually triggering
anything at all with my change to make it not lock up for me.

                  Linus

^ permalink raw reply

* Re: [PATCH 0/24] kernel: add a netlink interface to get information about processes (v2)
From: Andy Lutomirski @ 2015-07-06 17:10 UTC (permalink / raw)
  To: Andrey Vagin
  Cc: linux-kernel@vger.kernel.org, Linux API, Oleg Nesterov,
	Andrew Morton, Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi,
	Arnd Bergmann, Arnaldo Carvalho de Melo, David Ahern,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

On Mon, Jul 6, 2015 at 1:47 AM, Andrey Vagin <avagin@openvz.org> wrote:
> Currently we use the proc file system, where all information are
> presented in text files, what is convenient for humans.  But if we need
> to get information about processes from code (e.g. in C), the procfs
> doesn't look so cool.
>
> From code we would prefer to get information in binary format and to be
> able to specify which information and for which tasks are required. Here
> is a new interface with all these features, which is called task_diag.
> In addition it's much faster than procfs.
>
> task_diag is based on netlink sockets and looks like socket-diag, which
> is used to get information about sockets.

I think I like this in principle, but I have can see a few potential
problems with using netlink for this:

1. Netlink very naturally handles net namespaces, but it doesn't
naturally handle any other kind of namespace.  In fact, the taskstats
code that you're building on has highly broken user and pid namespace
support.  (Look for some obviously useless init_user_ns and
init_pid_ns references.  But that's only the obvious problem.  That
code calls current_user_ns() and task_active_pid_ns(current) from
.doit, which is, in turn, called from sys_write, and looking at
current's security state from sys_write is a big no-no.)

You could partially fix it by looking at f_cred's namespaces, but that
would be a change of what it means to create a netlink socket, and I'm
not sure that's a good idea.

2. These look like generally useful interfaces, which means that
people might want to use them in common non-system software, which
means that some of that software might get run inside of sandboxes
(Sandstorm, xdg-app, etc.)  Sandboxes like that might block netlink
outright, since it can't be usefully filtered by seccomp.  (This isn't
really the case now, since netlink route queries are too common, but
still.)

3. Netlink is a bit tedious to use from userspace.  Especially for
things like task_diag, which are really just queries that generate
single replies.

Would it make more sense to have a new syscall instead?  You could
even still use nlattr formatting for the syscall results.

--Andy

^ permalink raw reply

* Re: Odd hang on suspend and shutdown
From: Samuel Ortiz @ 2015-07-06 16:59 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Tomas Winkler, Greg Kroah-Hartman, Linux API
In-Reply-To: <CA+55aFxfENpyWSDxgaQhB1mBHE6zs=w=Mc0VEQLgdwSaCMX5eQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Mon, Jul 06, 2015 at 09:49:51AM -0700, Linus Torvalds wrote:
> I just tested, and loading it manually with "modprobe pn544_mei"
> doesn't seem to do anything bad.  I can still suspend with a good
> kernel. So it's not just about loading the module, there's some other
> interaction going on.
Ok, if you can suspend after this modprobe we're looking at some
potential mei bus or mei core issues. I'll revamp one of my HSW box and
will try to reproduce that issue on a 4.2-rc1 kernel.
I'll keep you posted.

Cheers,
Samuel.

^ permalink raw reply

* Re: Odd hang on suspend and shutdown
From: Linus Torvalds @ 2015-07-06 16:49 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Tomas Winkler, Greg Kroah-Hartman, Linux API
In-Reply-To: <20150706160706.GA22015-nKCvNrh56OoJmsy6czSMtA@public.gmane.org>

On Mon, Jul 6, 2015 at 9:07 AM, Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org> wrote:
>
> I suppose you were not seeing this issue on e.g. a 4.1 kernel (assuming
> this is not a brand new laptop) ?

Nope, 4.1 is fine. This is my travel laptop for the last almost two
years. Best laptop I've ever had (I like them small and light).

> If that's the case, is any of the pn544* kernel modules loaded when
> running on top of a good kernel ?

So it doesn't show up in lsmod, but presumably the module got loaded
and then errored out or something. The mei and mei_me modules are
loaded, nut no pn544_mei.

I'm not even sure why it's in my configuration, because I tend to try
to keep those small, and my config was generated (long ago) with "make
localmodconfig", but maybe there's something non-obvious that brought
it in. Presumably that pn544 module was loaded at _some_ point in the
past.

I just tested, and loading it manually with "modprobe pn544_mei"
doesn't seem to do anything bad.  I can still suspend with a good
kernel. So it's not just about loading the module, there's some other
interaction going on.

                     Linus

^ permalink raw reply

* Re: Odd hang on suspend and shutdown
From: Samuel Ortiz @ 2015-07-06 16:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Tomas Winkler, Greg Kroah-Hartman, Linux API
In-Reply-To: <CA+55aFy1x6iwbdV8WfR+wawj_1+PxJ+P-Js=EVqD9ZsQetSNJA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Sun, Jul 05, 2015 at 04:20:02PM -0700, Linus Torvalds wrote:
> On my Sony VAIO Pro 11 laptop, commit c93b76b34b4d ("mei: bus: report
> also uuid in module alias") seems to cause problems at suspend and
> shutdown.
> 
> In particular, reverting just the oneliner to drivers/nfc/pn544/mei.c
> seems to fix things for me. The bisection was a pain, because it took
> me forever to realize that it was that one-liner that caused it: I had
> initially undone that one line simply because it didn't compile with
> it in place (complaints about MEI_NFC_UUID not being constant). So I
> continued to bisect with the fix unintentionally in place.
> 
> So just removing the MEI_NFC_UUID entry from the pn544_mei_tbl[] array
> initialization makes things work for me again.
I suppose you were not seeing this issue on e.g. a 4.1 kernel (assuming
this is not a brand new laptop) ?
If that's the case, is any of the pn544* kernel modules loaded when
running on top of a good kernel ?

Cheers,
Samuel.

^ permalink raw reply

* [PATCH v3] ipc: Modify message queue accounting to not take kernel data structures into account
From: Marcus Gelderie @ 2015-07-06 15:49 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: mtk.manpages, Doug Ledford, redmnic, lkml, David Howells,
	Alexander Viro, John Duffy, Arto Bendiken, Linux API, akpm
In-Reply-To: <1435256484.11852.30.camel@stgolabs.net>

A while back, the message queue implementation in the kernel was
improved to use btrees to speed up retrieval of messages (commit
d6629859b36). The patch introducing the improved kernel handling of
message queues (using btrees) has, as a by-product, changed the
meaning of the QSIZE field in the pseudo-file created for the queue.
Before, this field reflected the size of the user-data in the queue.
Since, it also takes kernel data structures into account. For
example, if 13 bytes of user data are in the queue, on my machine the
file reports a size of 61 bytes.

There was some discussion on this topic before (for example
https://lkml.org/lkml/2014/10/1/115). Commenting on a th lkml, Michael
Kerrisk gave the following background (https://lkml.org/lkml/2015/6/16/74):

    The pseudofiles in the mqueue filesystem (usually mounted at
    /dev/mqueue) expose fields with metadata describing a message
    queue. One of these fields, QSIZE, as originally implemented,
    showed the total number of bytes of user data in all messages in
    the message queue, and this feature was documented from the
    beginning in the mq_overview(7) page. In 3.5, some other (useful)
    work happened to break the user-space API in a couple of places,
    including the value exposed via QSIZE, which now includes a measure
    of kernel overhead bytes for the queue, a figure that renders QSIZE
    useless for its original purpose, since there's no way to deduce
    the number of overhead bytes consumed by the implementation.
    (The other user-space breakage was subsequently fixed.)

This patch removes the accounting of kernel data structures in the
queue. Reporting the size of these data-structures in the QSIZE field
was a breaking change (see Michael's comment above). Without the QSIZE
field reporting the total size of user-data in the queue, there is no
way to deduce this number.

It should be noted that the resource limit RLIMIT_MSGQUEUE is counted
against the worst-case size of the queue (in both the old and the new
implementation). Therefore, the kernel overhead accounting in QSIZE is
not necessary to help the user understand the limitations RLIMIT imposes
on the processes.

Signed-off-by: Marcus Gelderie <redmnic@gmail.com>

v3 Changes: Revert QSIZE to old meaning and remove QKERSIZE field, because the rlimit accounting does not take runtime kernel overhead into account (it is a worst case measure).

---
 ipc/mqueue.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 3aaea7f..c3fc5c2 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -143,7 +143,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
 		if (!leaf)
 			return -ENOMEM;
 		INIT_LIST_HEAD(&leaf->msg_list);
-		info->qsize += sizeof(*leaf);
 	}
 	leaf->priority = msg->m_type;
 	rb_link_node(&leaf->rb_node, parent, p);
@@ -188,7 +187,6 @@ try_again:
 			     "lazy leaf delete!\n");
 		rb_erase(&leaf->rb_node, &info->msg_tree);
 		if (info->node_cache) {
-			info->qsize -= sizeof(*leaf);
 			kfree(leaf);
 		} else {
 			info->node_cache = leaf;
@@ -201,7 +199,6 @@ try_again:
 		if (list_empty(&leaf->msg_list)) {
 			rb_erase(&leaf->rb_node, &info->msg_tree);
 			if (info->node_cache) {
-				info->qsize -= sizeof(*leaf);
 				kfree(leaf);
 			} else {
 				info->node_cache = leaf;
@@ -1026,7 +1023,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
 		/* Save our speculative allocation into the cache */
 		INIT_LIST_HEAD(&new_leaf->msg_list);
 		info->node_cache = new_leaf;
-		info->qsize += sizeof(*new_leaf);
 		new_leaf = NULL;
 	} else {
 		kfree(new_leaf);
@@ -1133,7 +1129,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
 		/* Save our speculative allocation into the cache */
 		INIT_LIST_HEAD(&new_leaf->msg_list);
 		info->node_cache = new_leaf;
-		info->qsize += sizeof(*new_leaf);
 	} else {
 		kfree(new_leaf);
 	}
-- 
2.4.5

^ permalink raw reply related

* Re: Odd hang on suspend and shutdown
From: Linus Torvalds @ 2015-07-06 15:28 UTC (permalink / raw)
  To: Winkler, Tomas; +Cc: Greg Kroah-Hartman, Linux API, Samuel Ortiz
In-Reply-To: <5B8DA87D05A7694D9FA63FD143655C1B3D3E1F3F-Jy8z56yoSI8MvF1YICWikbfspsVTdybXVpNB7YpNyf8@public.gmane.org>

On Mon, Jul 6, 2015 at 6:26 AM, Winkler, Tomas <tomas.winkler-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote:
>
> We had  suspend issue that was resolved by a patch below

That patch is in 4.2-rc1, and that's what I see the problem with. So
it doesn't fix anything for me, I'm afraid.

                      Linus

^ permalink raw reply

* RE: Odd hang on suspend and shutdown
From: Winkler, Tomas @ 2015-07-06 13:26 UTC (permalink / raw)
  To: Linus Torvalds, Greg Kroah-Hartman; +Cc: Linux API, Samuel Ortiz
In-Reply-To: <CA+55aFy1x6iwbdV8WfR+wawj_1+PxJ+P-Js=EVqD9ZsQetSNJA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>


> 
> On my Sony VAIO Pro 11 laptop, commit c93b76b34b4d ("mei: bus: report
> also uuid in module alias") seems to cause problems at suspend and
> shutdown.
> 
> In particular, reverting just the oneliner to drivers/nfc/pn544/mei.c
> seems to fix things for me. The bisection was a pain, because it took
> me forever to realize that it was that one-liner that caused it: I had
> initially undone that one line simply because it didn't compile with
> it in place (complaints about MEI_NFC_UUID not being constant). So I
> continued to bisect with the fix unintentionally in place.
> 
> So just removing the MEI_NFC_UUID entry from the pn544_mei_tbl[] array
> initialization makes things work for me again.
> 
> The symptoms are just a hard hang at suspend or shutdown.
> 
> This is a pretty regular Intel-only laptop, running Fedora 22.
> 
> Any ideas?
> 
>                     Linus


I'm looking into this (not sure I get the exact platform to test with)

There was a miss order in how patches were applied, which may confuse bisection even more 
The fix for that was provided in this patch

In commit b144ce2d37619e05afdb0a15676500d76a64b1be
Author: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date:   Wed May 27 17:17:27 2015 -0700

    mei: fix up uuid matching


We had  suspend issue that was resolved by a patch bellow, but it's not related to the NFC at all. 
The NFC under Haswell should not be actually operational, I'm not sure if Samuel is planning to support it at all.
Still need to figure out what caused that regression. 
 
commit 3dc196eae1db548f05e53e5875ff87b8ff79f249
Author: Alexander Usyskin <alexander.usyskin@intel.com>
Date:   Sat Jun 13 08:51:17 2015 +0300

    mei: me: wait for power gating exit confirmation

    Fix the hbm power gating state machine so it will wait till it receives
    confirmation interrupt for the PG_ISOLATION_EXIT message.

Thanks
Tomas



^ permalink raw reply

* [PATCH v3 01/11] stm class: Introduce an abstraction for System Trace Module devices
From: Alexander Shishkin @ 2015-07-06 10:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, mathieu.poirier, peter.lachner, norbert.schulz,
	keven.boell, yann.fouassier, laurent.fert, Alexander Shishkin,
	linux-api
In-Reply-To: <1436177344-16751-1-git-send-email-alexander.shishkin@linux.intel.com>

A System Trace Module (STM) is a device exporting data in System Trace
Protocol (STP) format as defined by MIPI STP standards. Examples of such
devices are Intel Trace Hub and Coresight STM.

This abstraction provides a unified interface for software trace sources
to send their data over an STM device to a debug host. In order to do
that, such a trace source needs to be assigned a pair of master/channel
identifiers that all the data from this source will be tagged with. The
STP decoder on the debug host side will use these master/channel tags to
distinguish different trace streams from one another inside one STP
stream.

This abstraction provides a configfs-based policy management mechanism
for dynamic allocation of these master/channel pairs based on trace
source-supplied string identifier. It has the flexibility of being
defined at runtime and at the same time (provided that the policy
definition is aligned with the decoding end) consistency.

For userspace trace sources, this abstraction provides write()-based and
mmap()-based (if the underlying stm device allows this) output mechanism.

For kernel-side trace sources, we provide "stm_source" device class that
can be connected to an stm device at run time.

Cc: linux-api@vger.kernel.org
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
 Documentation/ABI/testing/configfs-stp-policy    |   48 +
 Documentation/ABI/testing/sysfs-class-stm        |   14 +
 Documentation/ABI/testing/sysfs-class-stm_source |   11 +
 Documentation/ioctl/ioctl-number.txt             |    3 +
 Documentation/trace/stm.txt                      |   80 ++
 drivers/Kconfig                                  |    2 +
 drivers/Makefile                                 |    1 +
 drivers/hwtracing/stm/Kconfig                    |    8 +
 drivers/hwtracing/stm/Makefile                   |    3 +
 drivers/hwtracing/stm/core.c                     | 1029 ++++++++++++++++++++++
 drivers/hwtracing/stm/policy.c                   |  529 +++++++++++
 drivers/hwtracing/stm/stm.h                      |   87 ++
 include/linux/stm.h                              |  126 +++
 include/uapi/linux/stm.h                         |   50 ++
 14 files changed, 1991 insertions(+)
 create mode 100644 Documentation/ABI/testing/configfs-stp-policy
 create mode 100644 Documentation/ABI/testing/sysfs-class-stm
 create mode 100644 Documentation/ABI/testing/sysfs-class-stm_source
 create mode 100644 Documentation/trace/stm.txt
 create mode 100644 drivers/hwtracing/stm/Kconfig
 create mode 100644 drivers/hwtracing/stm/Makefile
 create mode 100644 drivers/hwtracing/stm/core.c
 create mode 100644 drivers/hwtracing/stm/policy.c
 create mode 100644 drivers/hwtracing/stm/stm.h
 create mode 100644 include/linux/stm.h
 create mode 100644 include/uapi/linux/stm.h

diff --git a/Documentation/ABI/testing/configfs-stp-policy b/Documentation/ABI/testing/configfs-stp-policy
new file mode 100644
index 0000000000..421ce6825c
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-stp-policy
@@ -0,0 +1,48 @@
+What:		/config/stp-policy
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		This group contains policies mandating Master/Channel allocation
+		for software sources wishing to send trace data over an STM
+		device.
+
+What:		/config/stp-policy/<device>.<policy>
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		This group is the root of a policy; its name is a concatenation
+		of an stm device name to which this policy applies and an
+		arbitrary string. If <device> part doesn't match an existing
+		stm device, mkdir will fail with ENODEV; if that device already
+		has a policy assigned to it, mkdir will fail with EBUSY.
+
+What:		/config/stp-policy/<device>.<policy>/device
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		STM device to which this policy applies, read only. Same as the
+		<device> component of its parent directory.
+
+What:		/config/stp-policy/<device>.<policy>/<node>
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		Policy node is a string identifier that software clients will
+		use to request a master/channel to be allocated and assigned to
+		them.
+
+What:		/config/stp-policy/<device>.<policy>/<node>/masters
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		Range of masters from which to allocate for users of this node.
+		Write two numbers: the first master and the last master number.
+
+What:		/config/stp-policy/<device>.<policy>/<node>/channels
+Date:		June 2015
+KernelVersion:	4.3
+Description:
+		Range of channels from which to allocate for users of this node.
+		Write two numbers: the first channel and the last channel
+		number.
+
diff --git a/Documentation/ABI/testing/sysfs-class-stm b/Documentation/ABI/testing/sysfs-class-stm
new file mode 100644
index 0000000000..c9aa4f3fc9
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-stm
@@ -0,0 +1,14 @@
+What:		/sys/class/stm/<stm>/masters
+Date:		June 2015
+KernelVersion:	4.3
+Contact:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Description:
+		Shows first and last available to software master numbers on
+		this STM device.
+
+What:		/sys/class/stm/<stm>/channels
+Date:		June 2015
+KernelVersion:	4.3
+Contact:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Description:
+		Shows the number of channels per master on this STM device.
diff --git a/Documentation/ABI/testing/sysfs-class-stm_source b/Documentation/ABI/testing/sysfs-class-stm_source
new file mode 100644
index 0000000000..57b8dd39bb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-stm_source
@@ -0,0 +1,11 @@
+What:		/sys/class/stm_source/<stm_source>/stm_source_link
+Date:		June 2015
+KernelVersion:	4.3
+Contact:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Description:
+		stm_source device linkage to stm device, where its tracing data
+		is directed. Reads return an existing connection or "<none>" if
+		this stm_source is not connected to any stm device yet.
+		Write an existing (registered) stm device's name here to
+		connect that device. If a device is already connected to this
+		stm_source, it will first be disconnected.
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 611c52267d..7fa29b4ece 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -81,6 +81,9 @@ Code  Seq#(hex)	Include File		Comments
 0x22	all	scsi/sg.h
 '#'	00-3F	IEEE 1394 Subsystem	Block for the entire subsystem
 '$'	00-0F	linux/perf_counter.h, linux/perf_event.h
+'%'	00-0F	include/uapi/linux/stm.h
+					System Trace Module subsystem
+					<mailto:alexander.shishkin@linux.intel.com>
 '&'	00-07	drivers/firewire/nosy-user.h
 '1'	00-1F	<linux/timepps.h>	PPS kit from Ulrich Windl
 					<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
diff --git a/Documentation/trace/stm.txt b/Documentation/trace/stm.txt
new file mode 100644
index 0000000000..e140f2e8d7
--- /dev/null
+++ b/Documentation/trace/stm.txt
@@ -0,0 +1,80 @@
+System Trace Module
+===================
+
+System Trace Module (STM) is a device described in MIPI STP specs as
+STP trace stream generator. STP (System Trace Protocol) is a trace
+protocol multiplexing data from multiple trace sources, each one of
+which is assigned a unique pair of master and channel. While some of
+these masters and channels are statically allocated to certain
+hardware trace sources, others are available to software. Software
+trace sources are usually free to pick for themselves any
+master/channel combination from this pool.
+
+On the receiving end of this STP stream (the decoder side), trace
+sources can only be identified by master/channel combination, so in
+order for the decoder to be able to make sense of the trace that
+involves multiple trace sources, it needs to be able to map those
+master/channel pairs to the trace sources that it understands.
+
+For instance, it is helpful to know that syslog messages come on
+master 7 channel 15, while arbitrary user applications can use masters
+48 to 63 and channels 0 to 127.
+
+To solve this mapping problem, stm class provides a policy management
+mechanism via configfs, that allows defining rules that map string
+identifiers to ranges of masters and channels. If these rules (policy)
+are consistent with what decoder expects, it will be able to properly
+process the trace data.
+
+This policy is a tree structure containing rules (policy_node) that
+have a name (string identifier) and a range of masters and channels
+associated with it, located in "stp-policy" subsystem directory in
+configfs. The topmost directory's name (the policy) is formatted as
+the STM device name to which this policy applies and and arbitrary
+string identifier separated by a stop. From the examle above, a rule
+may look like this:
+
+$ ls /config/stp-policy/dummy_stm.my-policy/user
+channels masters
+$ cat /config/stp-policy/dummy_stm.my-policy/user/masters
+48 63
+$ cat /config/stp-policy/dummy_stm.my-policy/user/channels
+0 127
+
+which means that the master allocation pool for this rule consists of
+masters 48 through 63 and channel allocation pool has channels 0
+through 127 in it. Now, any producer (trace source) identifying itself
+with "user" identification string will be allocated a master and
+channel from within these ranges.
+
+These rules can be nested, for example, one can define a rule "dummy"
+under "user" directory from the example above and this new rule will
+be used for trace sources with the id string of "user/dummy".
+
+Trace sources have to open the stm class device's node and write their
+trace data into its file descriptor. In order to identify themselves
+to the policy, they need to do a STP_POLICY_ID_SET ioctl on this file
+descriptor providing their id string. Otherwise, they will be
+automatically allocated a master/channel pair upon first write to this
+file descriptor according to the "default" rule of the policy, if such
+exists.
+
+Some STM devices may allow direct mapping of the channel mmio regions
+to userspace for zero-copy writing. One mappable page (in terms of
+mmu) will usually contain multiple channels' mmios, so the user will
+need to allocate that many channels to themselves (via the
+aforementioned ioctl() call) to be able to do this. That is, if your
+stm device's channel mmio region is 64 bytes and hardware page size is
+4096 bytes, after a successful STP_POLICY_ID_SET ioctl() call with
+width==64, you should be able to mmap() one page on this file
+descriptor and obtain direct access to an mmio region for 64 channels.
+
+For kernel-based trace sources, there is "stm_source" device
+class. Devices of this class can be connected and disconnected to/from
+stm devices at runtime via a sysfs attribute.
+
+Examples of STM devices are Intel Trace Hub [1] and Coresight STM
+[2].
+
+[1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf
+[2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 6e973b8e3a..96efe4522c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/android/Kconfig"
 
 source "drivers/nvdimm/Kconfig"
 
+source "drivers/hwtracing/stm/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index b64b49f6e0..6647bc923f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -164,4 +164,5 @@ obj-$(CONFIG_MCB)		+= mcb/
 obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
+obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_ANDROID)		+= android/
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
new file mode 100644
index 0000000000..90ed327461
--- /dev/null
+++ b/drivers/hwtracing/stm/Kconfig
@@ -0,0 +1,8 @@
+config STM
+	tristate "System Trace Module devices"
+	help
+	  A System Trace Module (STM) is a device exporting data in System
+	  Trace Protocol (STP) format as defined by MIPI STP standards.
+	  Examples of such devices are Intel Trace Hub and Coresight STM.
+
+	  Say Y here to enable System Trace Module device support.
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
new file mode 100644
index 0000000000..adec701649
--- /dev/null
+++ b/drivers/hwtracing/stm/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_STM)	+= stm_core.o
+
+stm_core-y		:= core.o policy.o
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
new file mode 100644
index 0000000000..b79c42c625
--- /dev/null
+++ b/drivers/hwtracing/stm/core.c
@@ -0,0 +1,1029 @@
+/*
+ * System Trace Module (STM) infrastructure
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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.
+ *
+ * STM class implements generic infrastructure for  System Trace Module devices
+ * as defined in MIPI STPv2 specification.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/compat.h>
+#include <linux/kdev_t.h>
+#include <linux/srcu.h>
+#include <linux/slab.h>
+#include <linux/stm.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include "stm.h"
+
+#include <uapi/linux/stm.h>
+
+static unsigned int stm_core_up;
+
+/*
+ * The SRCU here makes sure that STM device doesn't disappear from under a
+ * stm_source_write() caller, which may want to have as little overhead as
+ * possible.
+ */
+static struct srcu_struct stm_source_srcu;
+
+static ssize_t masters_show(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	struct stm_device *stm = to_stm_device(dev);
+	int ret;
+
+	ret = sprintf(buf, "%u %u\n", stm->data->sw_start, stm->data->sw_end);
+
+	return ret;
+}
+
+static DEVICE_ATTR_RO(masters);
+
+static ssize_t channels_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct stm_device *stm = to_stm_device(dev);
+	int ret;
+
+	ret = sprintf(buf, "%u\n", stm->data->sw_nchannels);
+
+	return ret;
+}
+
+static DEVICE_ATTR_RO(channels);
+
+static struct attribute *stm_attrs[] = {
+	&dev_attr_masters.attr,
+	&dev_attr_channels.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(stm);
+
+static struct class stm_class = {
+	.name		= "stm",
+	.dev_groups	= stm_groups,
+};
+
+static int stm_dev_match(struct device *dev, const void *data)
+{
+	const char *name = data;
+
+	return sysfs_streq(name, dev_name(dev));
+}
+
+/**
+ * stm_find_device() - find stm device by name
+ * @buf:	character buffer containing the name
+ *
+ * This is called when either policy gets assigned to an stm device or an
+ * stm_source device gets linked to an stm device.
+ *
+ * This grabs device's reference (get_device()) and module reference, both
+ * of which the calling path needs to make sure to drop with stm_put_device().
+ *
+ * Return:	stm device pointer or null if lookup failed.
+ */
+struct stm_device *stm_find_device(const char *buf)
+{
+	struct stm_device *stm;
+	struct device *dev;
+
+	if (!stm_core_up)
+		return NULL;
+
+	dev = class_find_device(&stm_class, NULL, buf, stm_dev_match);
+	if (!dev)
+		return NULL;
+
+	stm = to_stm_device(dev);
+	if (!try_module_get(stm->owner)) {
+		put_device(dev);
+		return NULL;
+	}
+
+	return stm;
+}
+
+/**
+ * stm_put_device() - drop references on the stm device
+ * @stm:	stm device, previously acquired by stm_find_device()
+ *
+ * This drops the module reference and device reference taken by
+ * stm_find_device().
+ */
+void stm_put_device(struct stm_device *stm)
+{
+	module_put(stm->owner);
+	put_device(&stm->dev);
+}
+
+/*
+ * Internally we only care about software-writable masters here, that is the
+ * ones in the range [stm_data->sw_start..stm_data..sw_end], however we need
+ * original master numbers to be visible externally, since they are the ones
+ * that will appear in the STP stream. Thus, the internal bookkeeping uses
+ * $master - stm_data->sw_start to reference master descriptors and such.
+ */
+
+#define __stm_master(_s, _m)				\
+	((_s)->masters[(_m) - (_s)->data->sw_start])
+
+static inline struct stp_master *
+stm_master(struct stm_device *stm, unsigned int idx)
+{
+	if (idx < stm->data->sw_start || idx > stm->data->sw_end)
+		return NULL;
+
+	return __stm_master(stm, idx);
+}
+
+static int stp_master_alloc(struct stm_device *stm, unsigned int idx)
+{
+	struct stp_master *master;
+	size_t size;
+
+	size = ALIGN(stm->data->sw_nchannels, 8) / 8;
+	size += sizeof(struct stp_master);
+	master = kzalloc(size, GFP_ATOMIC);
+	if (!master)
+		return -ENOMEM;
+
+	master->nr_free = stm->data->sw_nchannels;
+	__stm_master(stm, idx) = master;
+
+	return 0;
+}
+
+static void stp_master_free(struct stm_device *stm, unsigned int idx)
+{
+	struct stp_master *master = stm_master(stm, idx);
+
+	if (!master)
+		return;
+
+	__stm_master(stm, idx) = NULL;
+	kfree(master);
+}
+
+static void stm_output_claim(struct stm_device *stm, struct stm_output *output)
+{
+	struct stp_master *master = stm_master(stm, output->master);
+
+	if (WARN_ON_ONCE(master->nr_free < output->nr_chans))
+		return;
+
+	bitmap_allocate_region(&master->chan_map[0], output->channel,
+			       ilog2(output->nr_chans));
+
+	master->nr_free -= output->nr_chans;
+}
+
+static void
+stm_output_disclaim(struct stm_device *stm, struct stm_output *output)
+{
+	struct stp_master *master = stm_master(stm, output->master);
+
+	bitmap_release_region(&master->chan_map[0], output->channel,
+			      ilog2(output->nr_chans));
+
+	output->nr_chans = 0;
+	master->nr_free += output->nr_chans;
+}
+
+/*
+ * This is like bitmap_find_free_region(), except it can ignore @start bits
+ * at the beginning.
+ */
+static int find_free_channels(unsigned long *bitmap, unsigned int start,
+			      unsigned int end, unsigned int width)
+{
+	unsigned int pos;
+	int i;
+
+	for (pos = start; pos < end + 1; pos = ALIGN(pos, width)) {
+		pos = find_next_zero_bit(bitmap, end + 1, pos);
+		if (pos + width > end + 1)
+			break;
+
+		if (pos & (width - 1))
+			continue;
+
+		for (i = 1; i < width && !test_bit(pos + i, bitmap); i++)
+			;
+		if (i == width)
+			return pos;
+	}
+
+	return -1;
+}
+
+static unsigned int
+stm_find_master_chan(struct stm_device *stm, unsigned int width,
+		     unsigned int *mstart, unsigned int mend,
+		     unsigned int *cstart, unsigned int cend)
+{
+	struct stp_master *master;
+	unsigned int midx;
+	int pos, err;
+
+	for (midx = *mstart; midx <= mend; midx++) {
+		if (!stm_master(stm, midx)) {
+			err = stp_master_alloc(stm, midx);
+			if (err)
+				return err;
+		}
+
+		master = stm_master(stm, midx);
+
+		if (!master->nr_free)
+			continue;
+
+		pos = find_free_channels(master->chan_map, *cstart, cend,
+					 width);
+		if (pos < 0)
+			continue;
+
+		*mstart = midx;
+		*cstart = pos;
+		return 0;
+	}
+
+	return -ENOSPC;
+}
+
+static int stm_output_assign(struct stm_device *stm, unsigned int width,
+			     struct stp_policy_node *policy_node,
+			     struct stm_output *output)
+{
+	unsigned int midx, cidx, mend, cend;
+	int ret = -EINVAL;
+
+	if (width > stm->data->sw_nchannels)
+		return -EINVAL;
+
+	if (policy_node) {
+		stp_policy_node_get_ranges(policy_node,
+					   &midx, &mend, &cidx, &cend);
+	} else {
+		midx = stm->data->sw_start;
+		cidx = 0;
+		mend = stm->data->sw_end;
+		cend = stm->data->sw_nchannels - 1;
+	}
+
+	spin_lock(&stm->mc_lock);
+	/* output is already assigned -- shouldn't happen */
+	if (WARN_ON_ONCE(output->nr_chans))
+		goto unlock;
+
+	ret = stm_find_master_chan(stm, width, &midx, mend, &cidx, cend);
+	if (ret)
+		goto unlock;
+
+	output->master = midx;
+	output->channel = cidx;
+	output->nr_chans = width;
+	stm_output_claim(stm, output);
+	dev_dbg(&stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width);
+
+	ret = 0;
+unlock:
+	spin_unlock(&stm->mc_lock);
+
+	return ret;
+}
+
+static void stm_output_free(struct stm_device *stm, struct stm_output *output)
+{
+	spin_lock(&stm->mc_lock);
+	if (output->nr_chans)
+		stm_output_disclaim(stm, output);
+	spin_unlock(&stm->mc_lock);
+}
+
+static int major_match(struct device *dev, const void *data)
+{
+	unsigned int major = *(unsigned int *)data;
+
+	return MAJOR(dev->devt) == major;
+}
+
+static int stm_char_open(struct inode *inode, struct file *file)
+{
+	struct stm_file *stmf;
+	struct device *dev;
+	unsigned int major = imajor(inode);
+	int err = -ENODEV;
+
+	dev = class_find_device(&stm_class, NULL, &major, major_match);
+	if (!dev)
+		return -ENODEV;
+
+	stmf = kzalloc(sizeof(*stmf), GFP_KERNEL);
+	if (!stmf)
+		return -ENOMEM;
+
+	stmf->stm = to_stm_device(dev);
+
+	if (!try_module_get(stmf->stm->owner))
+		goto err_free;
+
+	file->private_data = stmf;
+
+	return nonseekable_open(inode, file);
+
+err_free:
+	kfree(stmf);
+
+	return err;
+}
+
+static int stm_char_release(struct inode *inode, struct file *file)
+{
+	struct stm_file *stmf = file->private_data;
+
+	stm_output_free(stmf->stm, &stmf->output);
+	stm_put_device(stmf->stm);
+	kfree(stmf);
+
+	return 0;
+}
+
+static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
+{
+	struct stm_device *stm = stmf->stm;
+	int ret;
+
+	stmf->policy_node = stp_policy_node_lookup(stm, id);
+
+	ret = stm_output_assign(stm, width, stmf->policy_node, &stmf->output);
+
+	if (stmf->policy_node)
+		stp_policy_node_put(stmf->policy_node);
+
+	return ret;
+}
+
+static void stm_write(struct stm_data *data, unsigned int master,
+		      unsigned int channel, const char *buf, size_t count)
+{
+	unsigned int flags = STP_PACKET_TIMESTAMPED;
+	const unsigned char *p = buf, nil = 0;
+	size_t pos;
+	ssize_t sz;
+
+	for (pos = 0, p = buf; count > pos; pos += sz, p += sz) {
+		sz = min_t(unsigned int, count - pos, 8);
+		sz = data->packet(data, master, channel, STP_PACKET_DATA, flags,
+				  sz, p);
+		flags = 0;
+	}
+
+	data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil);
+}
+
+static ssize_t stm_char_write(struct file *file, const char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct stm_file *stmf = file->private_data;
+	struct stm_device *stm = stmf->stm;
+	char *kbuf;
+	int err;
+
+	/*
+	 * if no m/c have been assigned to this writer up to this
+	 * point, use "default" policy entry
+	 */
+	if (!stmf->output.nr_chans) {
+		err = stm_file_assign(stmf, "default", 1);
+		/*
+		 * EBUSY means that somebody else just assigned this
+		 * output, which is just fine for write()
+		 */
+		if (err && err != -EBUSY)
+			return err;
+	}
+
+	kbuf = kmalloc(count + 1, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	err = copy_from_user(kbuf, buf, count);
+	if (err) {
+		kfree(kbuf);
+		return -EFAULT;
+	}
+
+	stm_write(stm->data, stmf->output.master, stmf->output.channel, kbuf,
+		  count);
+
+	kfree(kbuf);
+
+	return count;
+}
+
+static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct stm_file *stmf = file->private_data;
+	struct stm_device *stm = stmf->stm;
+	unsigned long size, phys;
+
+	if (!stm->data->mmio_addr)
+		return -EOPNOTSUPP;
+
+	if (vma->vm_pgoff)
+		return -EINVAL;
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (stmf->output.nr_chans * stm->data->sw_mmiosz != size)
+		return -EINVAL;
+
+	phys = stm->data->mmio_addr(stm->data, stmf->output.master,
+				    stmf->output.channel,
+				    stmf->output.nr_chans);
+
+	if (!phys)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+	vm_iomap_memory(vma, phys, size);
+
+	return 0;
+}
+
+static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
+{
+	struct stm_device *stm = stmf->stm;
+	struct stp_policy_id *id;
+	int ret = -EINVAL;
+	u32 size;
+
+	if (stmf->output.nr_chans)
+		return -EBUSY;
+
+	if (copy_from_user(&size, arg, sizeof(size)))
+		return -EFAULT;
+
+	if (size >= PATH_MAX + sizeof(*id))
+		return -EINVAL;
+
+	/*
+	 * size + 1 to make sure the .id string at the bottom is terminated,
+	 * which is also why memdup_user() is not useful here
+	 */
+	id = kzalloc(size + 1, GFP_KERNEL);
+	if (!id)
+		return -ENOMEM;
+
+	if (copy_from_user(id, arg, size)) {
+		ret = -EFAULT;
+		goto err_free;
+	}
+
+	if (id->__reserved_0 || id->__reserved_1)
+		goto err_free;
+
+	if (id->width < 1 ||
+	    id->width > PAGE_SIZE / stm->data->sw_mmiosz)
+		goto err_free;
+
+	ret = stm_file_assign(stmf, id->id, id->width);
+	if (ret)
+		goto err_free;
+
+	ret = 0;
+
+	if (stm->data->link)
+		ret = stm->data->link(stm->data, stmf->output.master,
+				      stmf->output.channel);
+
+	if (ret) {
+		stm_output_free(stmf->stm, &stmf->output);
+		stm_put_device(stmf->stm);
+	}
+
+err_free:
+	kfree(id);
+
+	return ret;
+}
+
+static int stm_char_policy_get_ioctl(struct stm_file *stmf, void __user *arg)
+{
+	struct stp_policy_id id = {
+		.size		= sizeof(id),
+		.master		= stmf->output.master,
+		.channel	= stmf->output.channel,
+		.width		= stmf->output.nr_chans,
+		.__reserved_0	= 0,
+		.__reserved_1	= 0,
+	};
+
+	return copy_to_user(arg, &id, id.size) ? -EFAULT : 0;
+}
+
+static long
+stm_char_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct stm_file *stmf = file->private_data;
+	struct stm_data *stm_data = stmf->stm->data;
+	int err = -ENOTTY;
+	u64 options;
+
+	switch (cmd) {
+	case STP_POLICY_ID_SET:
+		err = stm_char_policy_set_ioctl(stmf, (void __user *)arg);
+		if (err)
+			return err;
+
+		return stm_char_policy_get_ioctl(stmf, (void __user *)arg);
+
+	case STP_POLICY_ID_GET:
+		return stm_char_policy_get_ioctl(stmf, (void __user *)arg);
+
+	case STP_SET_OPTIONS:
+		if (copy_from_user(&options, (u64 __user *)arg, sizeof(u64)))
+			return -EFAULT;
+
+		if (stm_data->set_options)
+			err = stm_data->set_options(stm_data,
+						    stmf->output.master,
+						    stmf->output.channel,
+						    stmf->output.nr_chans,
+						    options);
+
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+stm_char_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return stm_char_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define stm_char_compat_ioctl	NULL
+#endif
+
+static const struct file_operations stm_fops = {
+	.open		= stm_char_open,
+	.release	= stm_char_release,
+	.write		= stm_char_write,
+	.mmap		= stm_char_mmap,
+	.unlocked_ioctl	= stm_char_ioctl,
+	.compat_ioctl	= stm_char_compat_ioctl,
+	.llseek		= no_llseek,
+};
+
+static void stm_device_release(struct device *dev)
+{
+	struct stm_device *stm = to_stm_device(dev);
+
+	kfree(stm);
+}
+
+int stm_register_device(struct device *parent, struct stm_data *stm_data,
+			struct module *owner)
+{
+	struct stm_device *stm;
+	unsigned int nmasters;
+	int err = -ENOMEM;
+
+	if (!stm_core_up)
+		return -EPROBE_DEFER;
+
+	if (!stm_data->packet || !stm_data->sw_nchannels)
+		return -EINVAL;
+
+	nmasters = stm_data->sw_end - stm_data->sw_start;
+	stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL);
+	if (!stm)
+		return -ENOMEM;
+
+	stm->major = register_chrdev(0, stm_data->name, &stm_fops);
+	if (stm->major < 0)
+		goto err_free;
+
+	device_initialize(&stm->dev);
+	stm->dev.devt = MKDEV(stm->major, 0);
+	stm->dev.class = &stm_class;
+	stm->dev.parent = parent;
+	stm->dev.release = stm_device_release;
+
+	err = kobject_set_name(&stm->dev.kobj, "%s", stm_data->name);
+	if (err)
+		goto err_device;
+
+	err = device_add(&stm->dev);
+	if (err)
+		goto err_device;
+
+	spin_lock_init(&stm->link_lock);
+	INIT_LIST_HEAD(&stm->link_list);
+
+	spin_lock_init(&stm->mc_lock);
+	mutex_init(&stm->policy_mutex);
+	stm->sw_nmasters = nmasters;
+	stm->owner = owner;
+	stm->data = stm_data;
+	stm_data->stm = stm;
+
+	return 0;
+
+err_device:
+	put_device(&stm->dev);
+err_free:
+	kfree(stm);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(stm_register_device);
+
+static void __stm_source_link_drop(struct stm_source_device *src,
+				   struct stm_device *stm);
+
+void stm_unregister_device(struct stm_data *stm_data)
+{
+	struct stm_device *stm = stm_data->stm;
+	struct stm_source_device *src, *iter;
+	int i;
+
+	spin_lock(&stm->link_lock);
+	list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
+		__stm_source_link_drop(src, stm);
+	}
+	spin_unlock(&stm->link_lock);
+
+	synchronize_srcu(&stm_source_srcu);
+
+	unregister_chrdev(stm->major, stm_data->name);
+
+	mutex_lock(&stm->policy_mutex);
+	if (stm->policy)
+		stp_policy_unbind(stm->policy);
+	mutex_unlock(&stm->policy_mutex);
+
+	for (i = 0; i < stm->sw_nmasters; i++)
+		stp_master_free(stm, i);
+
+	device_unregister(&stm->dev);
+	stm_data->stm = NULL;
+}
+EXPORT_SYMBOL_GPL(stm_unregister_device);
+
+/**
+ * stm_source_link_add() - connect an stm_source device to an stm device
+ * @src:	stm_source device
+ * @stm:	stm device
+ *
+ * This function establishes a link from stm_source to an stm device so that
+ * the former can send out trace data to the latter.
+ *
+ * Return:	0 on success, -errno otherwise.
+ */
+static int stm_source_link_add(struct stm_source_device *src,
+			       struct stm_device *stm)
+{
+	char *id;
+	int err;
+
+	spin_lock(&stm->link_lock);
+	spin_lock(&src->link_lock);
+
+	/* src->link is dereferenced under stm_source_srcu but not the list */
+	rcu_assign_pointer(src->link, stm);
+	list_add_tail(&src->link_entry, &stm->link_list);
+
+	spin_unlock(&src->link_lock);
+	spin_unlock(&stm->link_lock);
+
+	id = kstrdup(src->data->name, GFP_KERNEL);
+	if (id) {
+		src->policy_node =
+			stp_policy_node_lookup(stm, id);
+
+		kfree(id);
+	}
+
+	err = stm_output_assign(stm, src->data->nr_chans,
+				src->policy_node, &src->output);
+
+	if (src->policy_node)
+		stp_policy_node_put(src->policy_node);
+
+	if (err)
+		goto fail_detach;
+
+	/* this is to notify the STM device that a new link has been made */
+	if (stm->data->link)
+		err = stm->data->link(stm->data, src->output.master,
+				      src->output.channel);
+
+	if (err)
+		goto fail_free_output;
+
+	/* this is to let the source carry out all necessary preparations */
+	if (src->data->link)
+		src->data->link(src->data);
+
+	return 0;
+
+fail_free_output:
+	stm_output_free(stm, &src->output);
+	stm_put_device(stm);
+
+fail_detach:
+	spin_lock(&stm->link_lock);
+	spin_lock(&src->link_lock);
+
+	rcu_assign_pointer(src->link, NULL);
+	list_del_init(&src->link_entry);
+
+	spin_unlock(&src->link_lock);
+	spin_unlock(&stm->link_lock);
+
+	return err;
+}
+
+/**
+ * __stm_source_link_drop() - detach stm_source from an stm device
+ * @src:	stm_source device
+ * @stm:	stm device
+ *
+ * If @stm is @src::link, disconnect them from one another and put the
+ * reference on the @stm device.
+ *
+ * Caller must hold stm::link_lock.
+ */
+static void __stm_source_link_drop(struct stm_source_device *src,
+				   struct stm_device *stm)
+{
+	spin_lock(&src->link_lock);
+	if (WARN_ON_ONCE(src->link != stm)) {
+		spin_unlock(&src->link_lock);
+		return;
+	}
+
+	stm_output_free(src->link, &src->output);
+	/* caller must hold stm::link_lock */
+	list_del_init(&src->link_entry);
+	/* matches stm_find_device() from stm_source_link_store() */
+	stm_put_device(src->link);
+	rcu_assign_pointer(src->link, NULL);
+
+	spin_unlock(&src->link_lock);
+}
+
+/**
+ * stm_source_link_drop() - detach stm_source from its stm device
+ * @src:	stm_source device
+ *
+ * Unlinking means disconnecting from source's STM device; after this
+ * writes will be unsuccessful until it is linked to a new STM device.
+ *
+ * This will happen on "stm_source_link" sysfs attribute write to undo
+ * the existing link (if any), or on linked STM device's de-registration.
+ */
+static void stm_source_link_drop(struct stm_source_device *src)
+{
+	struct stm_device *stm;
+	int idx;
+
+	idx = srcu_read_lock(&stm_source_srcu);
+	stm = srcu_dereference(src->link, &stm_source_srcu);
+
+	if (stm) {
+		if (src->data->unlink)
+			src->data->unlink(src->data);
+
+		spin_lock(&stm->link_lock);
+		__stm_source_link_drop(src, stm);
+		spin_unlock(&stm->link_lock);
+	}
+
+	srcu_read_unlock(&stm_source_srcu, idx);
+}
+
+static ssize_t stm_source_link_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct stm_source_device *src = to_stm_source_device(dev);
+	struct stm_device *stm;
+	int idx, ret;
+
+	idx = srcu_read_lock(&stm_source_srcu);
+	stm = srcu_dereference(src->link, &stm_source_srcu);
+	ret = sprintf(buf, "%s\n",
+		      stm ? dev_name(&stm->dev) : "<none>");
+	srcu_read_unlock(&stm_source_srcu, idx);
+
+	return ret;
+}
+
+static ssize_t stm_source_link_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct stm_source_device *src = to_stm_source_device(dev);
+	struct stm_device *link;
+	int err;
+
+	stm_source_link_drop(src);
+
+	link = stm_find_device(buf);
+	if (!link)
+		return -EINVAL;
+
+	err = stm_source_link_add(src, link);
+	if (err)
+		stm_put_device(link);
+
+	return err ? : count;
+}
+
+static DEVICE_ATTR_RW(stm_source_link);
+
+static struct attribute *stm_source_attrs[] = {
+	&dev_attr_stm_source_link.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(stm_source);
+
+static struct class stm_source_class = {
+	.name		= "stm_source",
+	.dev_groups	= stm_source_groups,
+};
+
+static void stm_source_device_release(struct device *dev)
+{
+	struct stm_source_device *src = to_stm_source_device(dev);
+
+	kfree(src);
+}
+
+/**
+ * stm_source_register_device() - register an stm_source device
+ * @parent:	parent device
+ * @data:	device description structure
+ *
+ * This will create a device of stm_source class that can write
+ * data to an stm device once linked.
+ *
+ * Return:	0 on success, -errno otherwise.
+ */
+int stm_source_register_device(struct device *parent,
+			       struct stm_source_data *data)
+{
+	struct stm_source_device *src;
+	int err;
+
+	if (!stm_core_up)
+		return -EPROBE_DEFER;
+
+	src = kzalloc(sizeof(*src), GFP_KERNEL);
+	if (!src)
+		return -ENOMEM;
+
+	device_initialize(&src->dev);
+	src->dev.class = &stm_source_class;
+	src->dev.parent = parent;
+	src->dev.release = stm_source_device_release;
+
+	err = kobject_set_name(&src->dev.kobj, "%s", data->name);
+	if (err)
+		goto err;
+
+	err = device_add(&src->dev);
+	if (err)
+		goto err;
+
+	spin_lock_init(&src->link_lock);
+	INIT_LIST_HEAD(&src->link_entry);
+	src->data = data;
+	data->src = src;
+
+	return 0;
+
+err:
+	put_device(&src->dev);
+	kfree(src);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(stm_source_register_device);
+
+/**
+ * stm_source_unregister_device() - unregister an stm_source device
+ * @data:	device description that was used to register the device
+ *
+ * This will remove a previously created stm_source device from the system.
+ */
+void stm_source_unregister_device(struct stm_source_data *data)
+{
+	struct stm_source_device *src = data->src;
+
+	stm_source_link_drop(src);
+
+	device_destroy(&stm_source_class, src->dev.devt);
+}
+EXPORT_SYMBOL_GPL(stm_source_unregister_device);
+
+int stm_source_write(struct stm_source_data *data, unsigned int chan,
+		     const char *buf, size_t count)
+{
+	struct stm_source_device *src = data->src;
+	struct stm_device *stm;
+	int idx;
+
+	if (!src->output.nr_chans)
+		return -ENODEV;
+
+	if (chan >= src->output.nr_chans)
+		return -EINVAL;
+
+	idx = srcu_read_lock(&stm_source_srcu);
+
+	stm = srcu_dereference(src->link, &stm_source_srcu);
+	if (stm)
+		stm_write(stm->data, src->output.master,
+			  src->output.channel + chan,
+			  buf, count);
+	else
+		count = -ENODEV;
+
+	srcu_read_unlock(&stm_source_srcu, idx);
+
+	return count;
+}
+EXPORT_SYMBOL_GPL(stm_source_write);
+
+static int __init stm_core_init(void)
+{
+	int err;
+
+	err = class_register(&stm_class);
+	if (err)
+		return err;
+
+	err = class_register(&stm_source_class);
+	if (err)
+		goto err_stm;
+
+	err = stp_configfs_init();
+	if (err)
+		goto err_src;
+
+	init_srcu_struct(&stm_source_srcu);
+
+	stm_core_up++;
+
+	return 0;
+
+err_src:
+	class_unregister(&stm_source_class);
+err_stm:
+	class_unregister(&stm_class);
+
+	return err;
+}
+
+module_init(stm_core_init);
+
+static void __exit stm_core_exit(void)
+{
+	cleanup_srcu_struct(&stm_source_srcu);
+	class_unregister(&stm_source_class);
+	class_unregister(&stm_class);
+	stp_configfs_exit();
+}
+
+module_exit(stm_core_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("System Trace Module device class");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
new file mode 100644
index 0000000000..6498a9dbb7
--- /dev/null
+++ b/drivers/hwtracing/stm/policy.c
@@ -0,0 +1,529 @@
+/*
+ * System Trace Module (STM) master/channel allocation policy management
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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.
+ *
+ * A master/channel allocation policy allows mapping string identifiers to
+ * master and channel ranges, where allocation can be done.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/configfs.h>
+#include <linux/slab.h>
+#include <linux/stm.h>
+#include "stm.h"
+
+/*
+ * STP Master/Channel allocation policy configfs layout.
+ */
+
+struct stp_policy {
+	struct config_group	group;
+	struct stm_device	*stm;
+};
+
+struct stp_policy_node {
+	struct config_group	group;
+	struct stp_policy	*policy;
+	unsigned int		first_master;
+	unsigned int		last_master;
+	unsigned int		first_channel;
+	unsigned int		last_channel;
+};
+
+static struct configfs_subsystem stp_policy_subsys;
+
+void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
+				unsigned int *mstart, unsigned int *mend,
+				unsigned int *cstart, unsigned int *cend)
+{
+	*mstart	= policy_node->first_master;
+	*mend	= policy_node->last_master;
+	*cstart	= policy_node->first_channel;
+	*cend	= policy_node->last_channel;
+}
+
+static inline char *stp_policy_node_name(struct stp_policy_node *policy_node)
+{
+	return policy_node->group.cg_item.ci_name ? : "<none>";
+}
+
+static inline struct stp_policy *to_stp_policy(struct config_item *item)
+{
+	return item ?
+		container_of(to_config_group(item), struct stp_policy, group) :
+		NULL;
+}
+
+static inline struct stp_policy_node *
+to_stp_policy_node(struct config_item *item)
+{
+	return item ?
+		container_of(to_config_group(item), struct stp_policy_node,
+			     group) :
+		NULL;
+}
+
+static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node,
+					    char *page)
+{
+	ssize_t count;
+
+	count = sprintf(page, "%u %u\n", policy_node->first_master,
+			policy_node->last_master);
+
+	return count;
+}
+
+static ssize_t
+stp_policy_node_masters_store(struct stp_policy_node *policy_node,
+			      const char *page, size_t count)
+{
+	unsigned int first, last;
+	struct stm_device *stm;
+	char *p = (char *)page;
+	ssize_t ret = -ENODEV;
+
+	if (sscanf(p, "%u %u", &first, &last) != 2)
+		return -EINVAL;
+
+	mutex_lock(&stp_policy_subsys.su_mutex);
+	stm = policy_node->policy->stm;
+	if (!stm)
+		goto unlock;
+
+	/* must be within [sw_start..sw_end], which is an inclusive range */
+	if (first > INT_MAX || last > INT_MAX || first > last ||
+	    first < stm->data->sw_start ||
+	    last > stm->data->sw_end) {
+		ret = -ERANGE;
+		goto unlock;
+	}
+
+	ret = count;
+	policy_node->first_master = first;
+	policy_node->last_master = last;
+
+unlock:
+	mutex_unlock(&stp_policy_subsys.su_mutex);
+
+	return ret;
+}
+
+static ssize_t
+stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page)
+{
+	ssize_t count;
+
+	count = sprintf(page, "%u %u\n", policy_node->first_channel,
+			policy_node->last_channel);
+
+	return count;
+}
+
+static ssize_t
+stp_policy_node_channels_store(struct stp_policy_node *policy_node,
+			       const char *page, size_t count)
+{
+	unsigned int first, last;
+	struct stm_device *stm;
+	char *p = (char *)page;
+	ssize_t ret = -ENODEV;
+
+	if (sscanf(p, "%u %u", &first, &last) != 2)
+		return -EINVAL;
+
+	mutex_lock(&stp_policy_subsys.su_mutex);
+	stm = policy_node->policy->stm;
+	if (!stm)
+		goto unlock;
+
+	if (first > INT_MAX || last > INT_MAX || first > last ||
+	    last >= stm->data->sw_nchannels) {
+		ret = -ERANGE;
+		goto unlock;
+	}
+
+	ret = count;
+	policy_node->first_channel = first;
+	policy_node->last_channel = last;
+
+unlock:
+	mutex_unlock(&stp_policy_subsys.su_mutex);
+
+	return ret;
+}
+
+static void stp_policy_node_release(struct config_item *item)
+{
+	kfree(to_stp_policy_node(item));
+}
+
+struct stp_policy_node_attribute {
+	struct configfs_attribute	attr;
+	ssize_t (*show)(struct stp_policy_node *, char *);
+	ssize_t (*store)(struct stp_policy_node *, const char *, size_t);
+};
+
+static ssize_t stp_policy_node_attr_show(struct config_item *item,
+					 struct configfs_attribute *attr,
+					 char *page)
+{
+	struct stp_policy_node *policy_node = to_stp_policy_node(item);
+	struct stp_policy_node_attribute *pn_attr =
+		container_of(attr, struct stp_policy_node_attribute, attr);
+	ssize_t count = 0;
+
+	if (pn_attr->show)
+		count = pn_attr->show(policy_node, page);
+
+	return count;
+}
+
+static ssize_t stp_policy_node_attr_store(struct config_item *item,
+					  struct configfs_attribute *attr,
+					  const char *page, size_t len)
+{
+	struct stp_policy_node *policy_node = to_stp_policy_node(item);
+	struct stp_policy_node_attribute *pn_attr =
+		container_of(attr, struct stp_policy_node_attribute, attr);
+	ssize_t count = -EINVAL;
+
+	if (pn_attr->store)
+		count = pn_attr->store(policy_node, page, len);
+
+	return count;
+}
+
+static struct configfs_item_operations stp_policy_node_item_ops = {
+	.release		= stp_policy_node_release,
+	.show_attribute		= stp_policy_node_attr_show,
+	.store_attribute	= stp_policy_node_attr_store,
+};
+
+static struct stp_policy_node_attribute stp_policy_node_attr_range = {
+	.attr	= {
+		.ca_owner = THIS_MODULE,
+		.ca_name = "masters",
+		.ca_mode = S_IRUGO | S_IWUSR,
+	},
+	.show	= stp_policy_node_masters_show,
+	.store	= stp_policy_node_masters_store,
+};
+
+static struct stp_policy_node_attribute stp_policy_node_attr_channels = {
+	.attr	= {
+		.ca_owner = THIS_MODULE,
+		.ca_name = "channels",
+		.ca_mode = S_IRUGO | S_IWUSR,
+	},
+	.show	= stp_policy_node_channels_show,
+	.store	= stp_policy_node_channels_store,
+};
+
+static struct configfs_attribute *stp_policy_node_attrs[] = {
+	&stp_policy_node_attr_range.attr,
+	&stp_policy_node_attr_channels.attr,
+	NULL,
+};
+
+static struct config_item_type stp_policy_type;
+static struct config_item_type stp_policy_node_type;
+
+static struct config_group *
+stp_policy_node_make(struct config_group *group, const char *name)
+{
+	struct stp_policy_node *policy_node, *parent_node;
+	struct stp_policy *policy;
+
+	if (group->cg_item.ci_type == &stp_policy_type) {
+		policy = container_of(group, struct stp_policy, group);
+	} else {
+		parent_node = container_of(group, struct stp_policy_node,
+					   group);
+		policy = parent_node->policy;
+	}
+
+	if (!policy->stm)
+		return ERR_PTR(-ENODEV);
+
+	policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
+	if (!policy_node)
+		return ERR_PTR(-ENOMEM);
+
+	config_group_init_type_name(&policy_node->group, name,
+				    &stp_policy_node_type);
+
+	policy_node->policy = policy;
+
+	/* default values for the attributes */
+	policy_node->first_master = policy->stm->data->sw_start;
+	policy_node->last_master = policy->stm->data->sw_end;
+	policy_node->first_channel = 0;
+	policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
+
+	return &policy_node->group;
+}
+
+static void
+stp_policy_node_drop(struct config_group *group, struct config_item *item)
+{
+	config_item_put(item);
+}
+
+static struct configfs_group_operations stp_policy_node_group_ops = {
+	.make_group	= stp_policy_node_make,
+	.drop_item	= stp_policy_node_drop,
+};
+
+static struct config_item_type stp_policy_node_type = {
+	.ct_item_ops	= &stp_policy_node_item_ops,
+	.ct_group_ops	= &stp_policy_node_group_ops,
+	.ct_attrs	= stp_policy_node_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/*
+ * Root group: policies.
+ */
+static struct configfs_attribute stp_policy_attr_device = {
+	.ca_owner = THIS_MODULE,
+	.ca_name = "device",
+	.ca_mode = S_IRUGO,
+};
+
+static struct configfs_attribute *stp_policy_attrs[] = {
+	&stp_policy_attr_device,
+	NULL,
+};
+
+static ssize_t stp_policy_attr_show(struct config_item *item,
+				    struct configfs_attribute *attr,
+				    char *page)
+{
+	struct stp_policy *policy = to_stp_policy(item);
+	ssize_t count;
+
+	count = sprintf(page, "%s\n",
+			(policy && policy->stm) ?
+			policy->stm->data->name :
+			"<none>");
+
+	return count;
+}
+
+void stp_policy_unbind(struct stp_policy *policy)
+{
+	struct stm_device *stm = policy->stm;
+
+	if (WARN_ON_ONCE(!policy->stm))
+		return;
+
+	mutex_lock(&stm->policy_mutex);
+	stm->policy = NULL;
+	mutex_unlock(&stm->policy_mutex);
+
+	policy->stm = NULL;
+
+	stm_put_device(stm);
+}
+
+static void stp_policy_release(struct config_item *item)
+{
+	struct stp_policy *policy = to_stp_policy(item);
+
+	stp_policy_unbind(policy);
+	kfree(policy);
+}
+
+static struct configfs_item_operations stp_policy_item_ops = {
+	.release		= stp_policy_release,
+	.show_attribute		= stp_policy_attr_show,
+};
+
+static struct configfs_group_operations stp_policy_group_ops = {
+	.make_group	= stp_policy_node_make,
+};
+
+static struct config_item_type stp_policy_type = {
+	.ct_item_ops	= &stp_policy_item_ops,
+	.ct_group_ops	= &stp_policy_group_ops,
+	.ct_attrs	= stp_policy_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *
+stp_policies_make(struct config_group *group, const char *name)
+{
+	struct config_group *ret;
+	struct stm_device *stm;
+	char *devname, *p;
+
+	devname = kasprintf(GFP_KERNEL, "%s", name);
+	if (!devname)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * node must look like <device_name>.<policy_name>, where
+	 * <device_name> is the name of an existing stm device and
+	 * <policy_name> is an arbitrary string
+	 */
+	p = strchr(devname, '.');
+	if (!p) {
+		kfree(devname);
+		return ERR_PTR(-EINVAL);
+	}
+
+	*p++ = '\0';
+
+	stm = stm_find_device(devname);
+	kfree(devname);
+
+	if (!stm)
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&stm->policy_mutex);
+	if (stm->policy) {
+		ret = ERR_PTR(-EBUSY);
+		goto unlock_policy;
+	}
+
+	stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
+	if (!stm->policy) {
+		ret = ERR_PTR(-ENOMEM);
+		goto unlock_policy;
+	}
+
+	config_group_init_type_name(&stm->policy->group, name,
+				    &stp_policy_type);
+	stm->policy->stm = stm;
+
+	ret = &stm->policy->group;
+
+unlock_policy:
+	mutex_unlock(&stm->policy_mutex);
+
+	if (IS_ERR(ret))
+		stm_put_device(stm);
+
+	return ret;
+}
+
+static struct configfs_group_operations stp_policies_group_ops = {
+	.make_group	= stp_policies_make,
+};
+
+static struct config_item_type stp_policies_type = {
+	.ct_group_ops	= &stp_policies_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct configfs_subsystem stp_policy_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf	= "stp-policy",
+			.ci_type	= &stp_policies_type,
+		},
+	},
+};
+
+/*
+ * Lock the policy mutex from the outside
+ */
+static struct stp_policy_node *
+__stp_policy_node_lookup(struct stp_policy *policy, char *s)
+{
+	struct stp_policy_node *policy_node, *ret;
+	struct list_head *head = &policy->group.cg_children;
+	struct config_item *item;
+	char *start, *end = s;
+
+	if (list_empty(head))
+		return NULL;
+
+	/* return the first entry if everything else fails */
+	item = list_entry(head->next, struct config_item, ci_entry);
+	ret = to_stp_policy_node(item);
+
+next:
+	for (;;) {
+		start = strsep(&end, "/");
+		if (!start)
+			break;
+
+		if (!*start)
+			continue;
+
+		list_for_each_entry(item, head, ci_entry) {
+			policy_node = to_stp_policy_node(item);
+
+			if (!strcmp(start,
+				    policy_node->group.cg_item.ci_name)) {
+				ret = policy_node;
+
+				if (!end)
+					goto out;
+
+				head = &policy_node->group.cg_children;
+				goto next;
+			}
+		}
+		break;
+	}
+
+out:
+	return ret;
+}
+
+
+struct stp_policy_node *
+stp_policy_node_lookup(struct stm_device *stm, char *s)
+{
+	struct stp_policy_node *policy_node = NULL;
+
+	mutex_lock(&stp_policy_subsys.su_mutex);
+
+	mutex_lock(&stm->policy_mutex);
+	if (stm->policy)
+		policy_node = __stp_policy_node_lookup(stm->policy, s);
+	mutex_unlock(&stm->policy_mutex);
+
+	if (policy_node)
+		config_item_get(&policy_node->group.cg_item);
+	mutex_unlock(&stp_policy_subsys.su_mutex);
+
+	return policy_node;
+}
+
+void stp_policy_node_put(struct stp_policy_node *policy_node)
+{
+	config_item_put(&policy_node->group.cg_item);
+}
+
+int __init stp_configfs_init(void)
+{
+	int err;
+
+	config_group_init(&stp_policy_subsys.su_group);
+	mutex_init(&stp_policy_subsys.su_mutex);
+	err = configfs_register_subsystem(&stp_policy_subsys);
+
+	return err;
+}
+
+void __exit stp_configfs_exit(void)
+{
+	configfs_unregister_subsystem(&stp_policy_subsys);
+}
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
new file mode 100644
index 0000000000..cf33bf976a
--- /dev/null
+++ b/drivers/hwtracing/stm/stm.h
@@ -0,0 +1,87 @@
+/*
+ * System Trace Module (STM) infrastructure
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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.
+ *
+ * STM class implements generic infrastructure for  System Trace Module devices
+ * as defined in MIPI STPv2 specification.
+ */
+
+#ifndef _STM_STM_H_
+#define _STM_STM_H_
+
+struct stp_policy;
+struct stp_policy_node;
+
+struct stp_policy_node *
+stp_policy_node_lookup(struct stm_device *stm, char *s);
+void stp_policy_node_put(struct stp_policy_node *policy_node);
+void stp_policy_unbind(struct stp_policy *policy);
+
+void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
+				unsigned int *mstart, unsigned int *mend,
+				unsigned int *cstart, unsigned int *cend);
+int stp_configfs_init(void);
+void stp_configfs_exit(void);
+
+struct stp_master {
+	unsigned int	nr_free;
+	unsigned long	chan_map[0];
+};
+
+struct stm_device {
+	struct device		dev;
+	struct module		*owner;
+	struct stp_policy	*policy;
+	struct mutex		policy_mutex;
+	int			major;
+	unsigned int		sw_nmasters;
+	struct stm_data		*data;
+	spinlock_t		link_lock;
+	struct list_head	link_list;
+	/* master allocation */
+	spinlock_t		mc_lock;
+	struct stp_master	*masters[0];
+};
+
+#define to_stm_device(_d)				\
+	container_of((_d), struct stm_device, dev)
+
+struct stm_output {
+	unsigned int		master;
+	unsigned int		channel;
+	unsigned int		nr_chans;
+};
+
+struct stm_file {
+	struct stm_device	*stm;
+	struct stp_policy_node	*policy_node;
+	struct stm_output	output;
+};
+
+struct stm_device *stm_find_device(const char *name);
+void stm_put_device(struct stm_device *stm);
+
+struct stm_source_device {
+	struct device		dev;
+	struct stm_source_data	*data;
+	spinlock_t		link_lock;
+	struct stm_device	*link;
+	struct list_head	link_entry;
+	/* one output per stm_source device */
+	struct stp_policy_node	*policy_node;
+	struct stm_output	output;
+};
+
+#define to_stm_source_device(_d)				\
+	container_of((_d), struct stm_source_device, dev)
+
+#endif /* _STM_STM_H_ */
diff --git a/include/linux/stm.h b/include/linux/stm.h
new file mode 100644
index 0000000000..9d0083d364
--- /dev/null
+++ b/include/linux/stm.h
@@ -0,0 +1,126 @@
+/*
+ * System Trace Module (STM) infrastructure apis
+ * Copyright (C) 2014 Intel Corporation.
+ *
+ * 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.
+ */
+
+#ifndef _STM_H_
+#define _STM_H_
+
+#include <linux/device.h>
+
+/**
+ * enum stp_packet_type - STP packets that an STM driver sends
+ */
+enum stp_packet_type {
+	STP_PACKET_DATA = 0,
+	STP_PACKET_FLAG,
+	STP_PACKET_USER,
+	STP_PACKET_MERR,
+	STP_PACKET_GERR,
+	STP_PACKET_TRIG,
+	STP_PACKET_XSYNC,
+};
+
+/**
+ * enum stp_packet_flags - STP packet modifiers
+ */
+enum stp_packet_flags {
+	STP_PACKET_MARKED	= 0x1,
+	STP_PACKET_TIMESTAMPED	= 0x2,
+};
+
+struct stp_policy;
+
+struct stm_device;
+
+/**
+ * struct stm_data - STM device description and callbacks
+ * @name:		device name
+ * @stm:		internal structure, only used by stm class code
+ * @sw_start:		first STP master available to software
+ * @sw_end:		last STP master available to software
+ * @sw_nchannels:	number of STP channels per master
+ * @sw_mmiosz:		size of one channel's IO space, for mmap, optional
+ * @packet:		callback that sends an STP packet
+ * @mmio_addr:		mmap callback, optional
+ * @link:		called when a new stm_source gets linked to us, optional
+ * @unlink:		likewise for unlinking, again optional
+ * @set_options:	set device-specific options on a channel
+ *
+ * Fill out this structure before calling stm_register_device() to create
+ * an STM device and stm_unregister_device() to destroy it. It will also be
+ * passed back to @packet(), @mmio_addr(), @link(), @unlink() and @set_options()
+ * callbacks.
+ *
+ * Normally, an STM device will have a range of masters available to software
+ * and the rest being statically assigned to various hardware trace sources.
+ * The former is defined by the the range [@sw_start..@sw_end] of the device
+ * description. That is, the lowest master that can be allocated to software
+ * writers is @sw_start and data from this writer will appear is @sw_start
+ * master in the STP stream.
+ */
+struct stm_data {
+	const char		*name;
+	struct stm_device	*stm;
+	unsigned int		sw_start;
+	unsigned int		sw_end;
+	unsigned int		sw_nchannels;
+	unsigned int		sw_mmiosz;
+	ssize_t			(*packet)(struct stm_data *, unsigned int,
+					  unsigned int, unsigned int,
+					  unsigned int, unsigned int,
+					  const unsigned char *);
+	phys_addr_t		(*mmio_addr)(struct stm_data *, unsigned int,
+					     unsigned int, unsigned int);
+	int			(*link)(struct stm_data *, unsigned int,
+					unsigned int);
+	void			(*unlink)(struct stm_data *, unsigned int,
+					  unsigned int);
+	long			(*set_options)(struct stm_data *, unsigned int,
+					       unsigned int, unsigned int,
+					       unsigned long);
+};
+
+int stm_register_device(struct device *parent, struct stm_data *stm_data,
+			struct module *owner);
+void stm_unregister_device(struct stm_data *stm_data);
+
+struct stm_source_device;
+
+/**
+ * struct stm_source_data - STM source device description and callbacks
+ * @name:	device name, will be used for policy lookup
+ * @src:	internal structure, only used by stm class code
+ * @nr_chans:	number of channels to allocate
+ * @link:	called when this source gets linked to an STM device
+ * @unlink:	called when this source is about to get unlinked from its STM
+ *
+ * Fill in this structure before calling stm_source_register_device() to
+ * register a source device. Also pass it to unregister and write calls.
+ */
+struct stm_source_data {
+	const char		*name;
+	struct stm_source_device *src;
+	unsigned int		percpu;
+	unsigned int		nr_chans;
+	int			(*link)(struct stm_source_data *data);
+	void			(*unlink)(struct stm_source_data *data);
+};
+
+int stm_source_register_device(struct device *parent,
+			       struct stm_source_data *data);
+void stm_source_unregister_device(struct stm_source_data *data);
+
+int stm_source_write(struct stm_source_data *data, unsigned int chan,
+		     const char *buf, size_t count);
+
+#endif /* _STM_H_ */
diff --git a/include/uapi/linux/stm.h b/include/uapi/linux/stm.h
new file mode 100644
index 0000000000..626a8d3f63
--- /dev/null
+++ b/include/uapi/linux/stm.h
@@ -0,0 +1,50 @@
+/*
+ * System Trace Module (STM) userspace interfaces
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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.
+ *
+ * STM class implements generic infrastructure for  System Trace Module devices
+ * as defined in MIPI STPv2 specification.
+ */
+
+#ifndef _UAPI_LINUX_STM_H
+#define _UAPI_LINUX_STM_H
+
+#include <linux/types.h>
+
+/**
+ * struct stp_policy_id - identification for the STP policy
+ * @size:	size of the structure including real id[] length
+ * @master:	assigned master
+ * @channel:	first assigned channel
+ * @width:	number of requested channels
+ * @id:		identification string
+ *
+ * User must calculate the total size of the structure and put it into
+ * @size field, fill out the @id and desired @width. In return, kernel
+ * fills out @master, @channel and @width.
+ */
+struct stp_policy_id {
+	__u32		size;
+	__u16		master;
+	__u16		channel;
+	__u16		width;
+	/* padding */
+	__u16		__reserved_0;
+	__u32		__reserved_1;
+	char		id[0];
+};
+
+#define STP_POLICY_ID_SET	_IOWR('%', 0, struct stp_policy_id)
+#define STP_POLICY_ID_GET	_IOR('%', 1, struct stp_policy_id)
+#define STP_SET_OPTIONS		_IOW('%', 2, __u64)
+
+#endif /* _UAPI_LINUX_STM_H */
-- 
2.1.4

^ permalink raw reply related

* Re: [PATCH RESEND] virtio: Fix typecast of pointer in vring_init()
From: Thomas Huth @ 2015-07-06 10:05 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150706124939-mutt-send-email-mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

On Mon, 6 Jul 2015 12:50:22 +0300
"Michael S. Tsirkin" <mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:

> On Mon, Jul 06, 2015 at 11:24:42AM +0200, Thomas Huth wrote:
> > On Sun, 5 Jul 2015 14:59:54 +0200
> > "Michael S. Tsirkin" <mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> > 
> > > On Sun, Jul 05, 2015 at 12:58:53PM +0200, Michael S. Tsirkin wrote:
> > > > On Thu, Jul 02, 2015 at 09:21:22AM +0200, Thomas Huth wrote:
> > > > > The virtio_ring.h header is used in userspace programs (ie. QEMU),
> > > > > too. Here we can not assume that sizeof(pointer) is the same as
> > > > > sizeof(long), e.g. when compiling for Windows, so the typecast in
> > > > > vring_init() should be done with (uintptr_t) instead of (unsigned long).
> > > > > 
> > > > > Signed-off-by: Thomas Huth <thuth-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> > > > 
> > > > This seems to break some userspace too:
> > > > 
> > > >   INSTALL usr/include/linux/ (413 files)
> > > >   CHECK   usr/include/linux/ (413 files)
> > > >   HOSTCC  Documentation/accounting/getdelays
> > > >   HOSTCC  Documentation/connector/ucon
> > > >   HOSTCC  Documentation/mic/mpssd/mpssd.o
> > > > In file included from Documentation/mic/mpssd/mpssd.c:36:0:
> > > > ./usr/include/linux/virtio_ring.h: In function ‘vring_init’:
> > > > ./usr/include/linux/virtio_ring.h:146:24: error: ‘uintptr_t’ undeclared
> > > > (first use in this function)
> > > >   vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] +
> > > > sizeof(__virtio16)
> > > >                         ^
> > > > ./usr/include/linux/virtio_ring.h:146:24: note: each undeclared
> > > > identifier is reported only once for each function it appears in
> > > > scripts/Makefile.host:108: recipe for target
> > 
> > D'oh, I only built the kernel for powerpc, that's why I did not notice
> > this breakage in the MIC code. Sorry!
> > 
> > > > E.g. fuse.h has this code:
> > > > #ifdef __KERNEL__
> > > > #include <linux/types.h>
> > > > #else
> > > > #include <stdint.h>
> > > > #endif
> > > > 
> > > > Maybe we need something similar.
> > > 
> > > The following seems to help.  Does it help the windows build?
> > ...
> > > diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h
> > > index 8682551..c072959 100644
> > > --- a/include/uapi/linux/virtio_ring.h
> > > +++ b/include/uapi/linux/virtio_ring.h
> > > @@ -31,6 +31,9 @@
> > >   * SUCH DAMAGE.
> > >   *
> > >   * Copyright Rusty Russell IBM Corporation 2007. */
> > > +#ifndef __KERNEL__
> > > +#include <stdint.h>
> > > +#endif
> > >  #include <linux/types.h>
> > >  #include <linux/virtio_types.h>
> > 
> > Since the update-linux-headers.sh script from QEMU replaces the
> > "#include <linux/types.h>" in virtio_ring.h to include a file that again
> > includes stdint.h already, your above patch should not do any
> > difference for compiling QEMU for Windows, I think. It's really just
> > about replacing the typecast there.
> > 
> > But you're right of course for other user space applications which
> > include this header by other means. So I'm fine if you change my patch
> > with your hunk above (or add it as an additional patch). Or shall I
> > rather resend my patch with your above hunk included?
> > 
> >  Thomas
> 
> You don't have to, but could you confirm that stdint has uintptr_t on
> mingw?
> 

$ grep typedef.*uintptr /usr/x86_64-w64-mingw32/sys-root/mingw/include/*.h
...
/usr/x86_64-w64-mingw32/sys-root/mingw/include/crtdefs.h:__MINGW_EXTENSION typedef unsigned __int64 uintptr_t;
...

And the stdint.h from my MinGW installation includes crtdefs.h.
So yes, confirmed that stdint.h provides uintptr_t there, too.

 Thomas

^ permalink raw reply

* Re: [PATCH RESEND] virtio: Fix typecast of pointer in vring_init()
From: Michael S. Tsirkin @ 2015-07-06  9:50 UTC (permalink / raw)
  To: Thomas Huth
  Cc: virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150706112442.60079de5@thh440s>

On Mon, Jul 06, 2015 at 11:24:42AM +0200, Thomas Huth wrote:
> On Sun, 5 Jul 2015 14:59:54 +0200
> "Michael S. Tsirkin" <mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> 
> > On Sun, Jul 05, 2015 at 12:58:53PM +0200, Michael S. Tsirkin wrote:
> > > On Thu, Jul 02, 2015 at 09:21:22AM +0200, Thomas Huth wrote:
> > > > The virtio_ring.h header is used in userspace programs (ie. QEMU),
> > > > too. Here we can not assume that sizeof(pointer) is the same as
> > > > sizeof(long), e.g. when compiling for Windows, so the typecast in
> > > > vring_init() should be done with (uintptr_t) instead of (unsigned long).
> > > > 
> > > > Signed-off-by: Thomas Huth <thuth-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> > > 
> > > This seems to break some userspace too:
> > > 
> > >   INSTALL usr/include/linux/ (413 files)
> > >   CHECK   usr/include/linux/ (413 files)
> > >   HOSTCC  Documentation/accounting/getdelays
> > >   HOSTCC  Documentation/connector/ucon
> > >   HOSTCC  Documentation/mic/mpssd/mpssd.o
> > > In file included from Documentation/mic/mpssd/mpssd.c:36:0:
> > > ./usr/include/linux/virtio_ring.h: In function ‘vring_init’:
> > > ./usr/include/linux/virtio_ring.h:146:24: error: ‘uintptr_t’ undeclared
> > > (first use in this function)
> > >   vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] +
> > > sizeof(__virtio16)
> > >                         ^
> > > ./usr/include/linux/virtio_ring.h:146:24: note: each undeclared
> > > identifier is reported only once for each function it appears in
> > > scripts/Makefile.host:108: recipe for target
> 
> D'oh, I only built the kernel for powerpc, that's why I did not notice
> this breakage in the MIC code. Sorry!
> 
> > > E.g. fuse.h has this code:
> > > #ifdef __KERNEL__
> > > #include <linux/types.h>
> > > #else
> > > #include <stdint.h>
> > > #endif
> > > 
> > > Maybe we need something similar.
> > 
> > The following seems to help.  Does it help the windows build?
> ...
> > diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h
> > index 8682551..c072959 100644
> > --- a/include/uapi/linux/virtio_ring.h
> > +++ b/include/uapi/linux/virtio_ring.h
> > @@ -31,6 +31,9 @@
> >   * SUCH DAMAGE.
> >   *
> >   * Copyright Rusty Russell IBM Corporation 2007. */
> > +#ifndef __KERNEL__
> > +#include <stdint.h>
> > +#endif
> >  #include <linux/types.h>
> >  #include <linux/virtio_types.h>
> 
> Since the update-linux-headers.sh script from QEMU replaces the
> "#include <linux/types.h>" in virtio_ring.h to include a file that again
> includes stdint.h already, your above patch should not do any
> difference for compiling QEMU for Windows, I think. It's really just
> about replacing the typecast there.
> 
> But you're right of course for other user space applications which
> include this header by other means. So I'm fine if you change my patch
> with your hunk above (or add it as an additional patch). Or shall I
> rather resend my patch with your above hunk included?
> 
>  Thomas

You don't have to, but could you confirm that stdint has uintptr_t on
mingw?

-- 
MST

^ permalink raw reply

* Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
From: Christoffer Dall @ 2015-07-06  9:31 UTC (permalink / raw)
  To: Will Deacon
  Cc: Alex Bennée, kvm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, Marc Zyngier,
	peter.maydell@linaro.org, agraf@suse.de, drjones@redhat.com,
	pbonzini@redhat.com, zhichao.huang@linaro.org,
	jan.kiszka@siemens.com, dahi@linux.vnet.ibm.com,
	r65777@freescale.com, bp@suse.de, Gleb Natapov, Jonathan Corbet,
	Catalin Marinas, Lorenzo Pieralisi, Ingo Molnar
In-Reply-To: <20150706085140.GA30342@arm.com>

On Mon, Jul 06, 2015 at 09:51:40AM +0100, Will Deacon wrote:
> On Fri, Jul 03, 2015 at 05:07:41PM +0100, Alex Bennée wrote:
> > Will Deacon <will.deacon@arm.com> writes:
> > > On Thu, Jul 02, 2015 at 02:50:33PM +0100, Alex Bennée wrote:
> > >> Are you happy with this?:
> > >
> > > [...]
> > >
> > >> +/**
> > >> + * kvm_arch_dev_ioctl_check_extension
> > >> + *
> > >> + * We currently assume that the number of HW registers is uniform
> > >> + * across all CPUs (see cpuinfo_sanity_check).
> > >> + */
> > >>  int kvm_arch_dev_ioctl_check_extension(long ext)
> > >>  {
> > >>         int r;
> > >> @@ -64,6 +71,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
> > >>         case KVM_CAP_ARM_EL1_32BIT:
> > >>                 r = cpu_has_32bit_el1();
> > >>                 break;
> > >> +       case KVM_CAP_GUEST_DEBUG_HW_BPS:
> > >> +               r = hw_breakpoint_slots(TYPE_INST);
> > >> +               break;
> > >> +       case KVM_CAP_GUEST_DEBUG_HW_WPS:
> > >> +               r  = hw_breakpoint_slots(TYPE_DATA);
> > >> +               break;
> > >
> > > Whilst I much prefer this code, it actually adds an unwanted dependency
> > > on PERF_EVENTS that I didn't think about to start with. Sorry to keep
> > > messing you about -- I guess your original patch is the best thing after
> > > all.
> > 
> > Everything looks to be in hw_breakpoint.[ch] which does depend on
> > CONFIG_HAVE_HW_BREAKPOINT which depends on PERF_EVENTS to be built.
> > However the previous code depended on this behaviour as well.
> 
> I think your original approach (of sticking stuff in the header file) works
> regardless of the CONFIG option, no?
> 
> > It would seem weird to enable guest debug using HW debug registers to
> > debug the guest yet not allowing the host kernel to use them? Of course
> > this is the only code they would share as all the magic of guest
> > debugging is already mostly there for dirty guest handling.
> > 
> > I'm not familiar with Kconfig but it looks like this is all part of
> > arm64 defconfig. Are people really going to want to disable PERF_EVENTS
> > but still debug their guests with HW support?
> 
> Then it's your call. I just find the host dependency on perf a bit weird
> to get guest debug working (especially as the dependency is completely
> "fake" because we don't use any perf infrastructure at all).
> 
Agreed, let's see if we can avoid this.

Thanks,
-Christoffer

^ permalink raw reply

* Re: [PATCH RESEND] virtio: Fix typecast of pointer in vring_init()
From: Thomas Huth @ 2015-07-06  9:24 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150705145917-mutt-send-email-mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

On Sun, 5 Jul 2015 14:59:54 +0200
"Michael S. Tsirkin" <mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:

> On Sun, Jul 05, 2015 at 12:58:53PM +0200, Michael S. Tsirkin wrote:
> > On Thu, Jul 02, 2015 at 09:21:22AM +0200, Thomas Huth wrote:
> > > The virtio_ring.h header is used in userspace programs (ie. QEMU),
> > > too. Here we can not assume that sizeof(pointer) is the same as
> > > sizeof(long), e.g. when compiling for Windows, so the typecast in
> > > vring_init() should be done with (uintptr_t) instead of (unsigned long).
> > > 
> > > Signed-off-by: Thomas Huth <thuth-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> > 
> > This seems to break some userspace too:
> > 
> >   INSTALL usr/include/linux/ (413 files)
> >   CHECK   usr/include/linux/ (413 files)
> >   HOSTCC  Documentation/accounting/getdelays
> >   HOSTCC  Documentation/connector/ucon
> >   HOSTCC  Documentation/mic/mpssd/mpssd.o
> > In file included from Documentation/mic/mpssd/mpssd.c:36:0:
> > ./usr/include/linux/virtio_ring.h: In function ‘vring_init’:
> > ./usr/include/linux/virtio_ring.h:146:24: error: ‘uintptr_t’ undeclared
> > (first use in this function)
> >   vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] +
> > sizeof(__virtio16)
> >                         ^
> > ./usr/include/linux/virtio_ring.h:146:24: note: each undeclared
> > identifier is reported only once for each function it appears in
> > scripts/Makefile.host:108: recipe for target

D'oh, I only built the kernel for powerpc, that's why I did not notice
this breakage in the MIC code. Sorry!

> > E.g. fuse.h has this code:
> > #ifdef __KERNEL__
> > #include <linux/types.h>
> > #else
> > #include <stdint.h>
> > #endif
> > 
> > Maybe we need something similar.
> 
> The following seems to help.  Does it help the windows build?
...
> diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h
> index 8682551..c072959 100644
> --- a/include/uapi/linux/virtio_ring.h
> +++ b/include/uapi/linux/virtio_ring.h
> @@ -31,6 +31,9 @@
>   * SUCH DAMAGE.
>   *
>   * Copyright Rusty Russell IBM Corporation 2007. */
> +#ifndef __KERNEL__
> +#include <stdint.h>
> +#endif
>  #include <linux/types.h>
>  #include <linux/virtio_types.h>

Since the update-linux-headers.sh script from QEMU replaces the
"#include <linux/types.h>" in virtio_ring.h to include a file that again
includes stdint.h already, your above patch should not do any
difference for compiling QEMU for Windows, I think. It's really just
about replacing the typecast there.

But you're right of course for other user space applications which
include this header by other means. So I'm fine if you change my patch
with your hunk above (or add it as an additional patch). Or shall I
rather resend my patch with your above hunk included?

 Thomas

^ permalink raw reply

* Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
From: Alex Bennée @ 2015-07-06  9:02 UTC (permalink / raw)
  To: Will Deacon
  Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, christoffer.dall@linaro.org,
	Marc Zyngier, peter.maydell@linaro.org, agraf@suse.de,
	drjones@redhat.com, pbonzini@redhat.com, zhichao.huang@linaro.org,
	jan.kiszka@siemens.com, dahi@linux.vnet.ibm.com,
	r65777@freescale.com, bp@suse.de, Gleb Natapov, Jonathan Corbet,
	Catalin Marinas, Lorenzo Pieralisi, Ingo Molnar
In-Reply-To: <20150706085140.GA30342@arm.com>


Will Deacon <will.deacon@arm.com> writes:

> On Fri, Jul 03, 2015 at 05:07:41PM +0100, Alex Bennée wrote:
>> Will Deacon <will.deacon@arm.com> writes:
>> > On Thu, Jul 02, 2015 at 02:50:33PM +0100, Alex Bennée wrote:
>> >> Are you happy with this?:
>> >
>> > [...]
>> >
>> >> +/**
>> >> + * kvm_arch_dev_ioctl_check_extension
>> >> + *
>> >> + * We currently assume that the number of HW registers is uniform
>> >> + * across all CPUs (see cpuinfo_sanity_check).
>> >> + */
>> >>  int kvm_arch_dev_ioctl_check_extension(long ext)
>> >>  {
>> >>         int r;
>> >> @@ -64,6 +71,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
>> >>         case KVM_CAP_ARM_EL1_32BIT:
>> >>                 r = cpu_has_32bit_el1();
>> >>                 break;
>> >> +       case KVM_CAP_GUEST_DEBUG_HW_BPS:
>> >> +               r = hw_breakpoint_slots(TYPE_INST);
>> >> +               break;
>> >> +       case KVM_CAP_GUEST_DEBUG_HW_WPS:
>> >> +               r  = hw_breakpoint_slots(TYPE_DATA);
>> >> +               break;
>> >
>> > Whilst I much prefer this code, it actually adds an unwanted dependency
>> > on PERF_EVENTS that I didn't think about to start with. Sorry to keep
>> > messing you about -- I guess your original patch is the best thing after
>> > all.
>> 
>> Everything looks to be in hw_breakpoint.[ch] which does depend on
>> CONFIG_HAVE_HW_BREAKPOINT which depends on PERF_EVENTS to be built.
>> However the previous code depended on this behaviour as well.
>
> I think your original approach (of sticking stuff in the header file) works
> regardless of the CONFIG option, no?

Ahh yeah I reverted that to an extern due to random compile breakage:

http://storage.kernelci.org/alex/v4.1-12-gd38574dba3ec/arm64-allmodconfig/build.log

I'll see if I can fix that up.

>> It would seem weird to enable guest debug using HW debug registers to
>> debug the guest yet not allowing the host kernel to use them? Of course
>> this is the only code they would share as all the magic of guest
>> debugging is already mostly there for dirty guest handling.
>> 
>> I'm not familiar with Kconfig but it looks like this is all part of
>> arm64 defconfig. Are people really going to want to disable PERF_EVENTS
>> but still debug their guests with HW support?
>
> Then it's your call. I just find the host dependency on perf a bit weird
> to get guest debug working (especially as the dependency is completely
> "fake" because we don't use any perf infrastructure at all).
>
> Will

-- 
Alex Bennée

^ permalink raw reply

* Re: [PATCH v7 09/11] KVM: arm64: guest debug, HW assisted debug support
From: Will Deacon @ 2015-07-06  8:51 UTC (permalink / raw)
  To: Alex Bennée
  Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, christoffer.dall@linaro.org,
	Marc Zyngier, peter.maydell@linaro.org, agraf@suse.de,
	drjones@redhat.com, pbonzini@redhat.com, zhichao.huang@linaro.org,
	jan.kiszka@siemens.com, dahi@linux.vnet.ibm.com,
	r65777@freescale.com, bp@suse.de, Gleb Natapov, Jonathan Corbet,
	Catalin Marinas, Lorenzo Pieralisi, Ingo Molnar
In-Reply-To: <87h9plrzqq.fsf@linaro.org>

On Fri, Jul 03, 2015 at 05:07:41PM +0100, Alex Bennée wrote:
> Will Deacon <will.deacon@arm.com> writes:
> > On Thu, Jul 02, 2015 at 02:50:33PM +0100, Alex Bennée wrote:
> >> Are you happy with this?:
> >
> > [...]
> >
> >> +/**
> >> + * kvm_arch_dev_ioctl_check_extension
> >> + *
> >> + * We currently assume that the number of HW registers is uniform
> >> + * across all CPUs (see cpuinfo_sanity_check).
> >> + */
> >>  int kvm_arch_dev_ioctl_check_extension(long ext)
> >>  {
> >>         int r;
> >> @@ -64,6 +71,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
> >>         case KVM_CAP_ARM_EL1_32BIT:
> >>                 r = cpu_has_32bit_el1();
> >>                 break;
> >> +       case KVM_CAP_GUEST_DEBUG_HW_BPS:
> >> +               r = hw_breakpoint_slots(TYPE_INST);
> >> +               break;
> >> +       case KVM_CAP_GUEST_DEBUG_HW_WPS:
> >> +               r  = hw_breakpoint_slots(TYPE_DATA);
> >> +               break;
> >
> > Whilst I much prefer this code, it actually adds an unwanted dependency
> > on PERF_EVENTS that I didn't think about to start with. Sorry to keep
> > messing you about -- I guess your original patch is the best thing after
> > all.
> 
> Everything looks to be in hw_breakpoint.[ch] which does depend on
> CONFIG_HAVE_HW_BREAKPOINT which depends on PERF_EVENTS to be built.
> However the previous code depended on this behaviour as well.

I think your original approach (of sticking stuff in the header file) works
regardless of the CONFIG option, no?

> It would seem weird to enable guest debug using HW debug registers to
> debug the guest yet not allowing the host kernel to use them? Of course
> this is the only code they would share as all the magic of guest
> debugging is already mostly there for dirty guest handling.
> 
> I'm not familiar with Kconfig but it looks like this is all part of
> arm64 defconfig. Are people really going to want to disable PERF_EVENTS
> but still debug their guests with HW support?

Then it's your call. I just find the host dependency on perf a bit weird
to get guest debug working (especially as the dependency is completely
"fake" because we don't use any perf infrastructure at all).

Will

^ permalink raw reply

* [PATCH 24/24] task_diag: Enhance fork tool to spawn threads
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-api-u79uwXL29TY76Z2rM5mHXA, Andrey Vagin, Oleg Nesterov,
	Andrew Morton, Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi,
	Arnd Bergmann, Arnaldo Carvalho de Melo, David Ahern,
	Andy Lutomirski, Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>

From: David Ahern <dsahern-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Add option to fork threads as well as processes.
Make the sleep time configurable too so that spawned
tasks exit on their own.

Signed-off-by: David Ahern <dsahern-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Andrey Vagin <avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
---
 tools/testing/selftests/task_diag/Makefile |  2 ++
 tools/testing/selftests/task_diag/fork.c   | 36 ++++++++++++++++++++++++++----
 tools/testing/selftests/task_diag/run.sh   |  4 ++--
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/task_diag/Makefile b/tools/testing/selftests/task_diag/Makefile
index 7104573..0c53cf6 100644
--- a/tools/testing/selftests/task_diag/Makefile
+++ b/tools/testing/selftests/task_diag/Makefile
@@ -12,6 +12,8 @@ task_diag_comm.o: task_diag_comm.c task_diag_comm.h
 task_diag_all: task_diag_all.o task_diag_comm.o
 task_diag: task_diag.o task_diag_comm.o
 fork: fork.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lpthread
+
 task_proc_all: task_proc_all.c
 
 clean:
diff --git a/tools/testing/selftests/task_diag/fork.c b/tools/testing/selftests/task_diag/fork.c
index c6e17d1..ebddedd2 100644
--- a/tools/testing/selftests/task_diag/fork.c
+++ b/tools/testing/selftests/task_diag/fork.c
@@ -2,15 +2,39 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <pthread.h>
 
+void *f(void *arg)
+{
+	unsigned long t = (unsigned long) arg;
+
+	sleep(t);
+	return NULL;
+}
+
+/* usage: fork nproc [mthreads [sleep]] */
 int main(int argc, char **argv)
 {
-	int i, n;
+	int i, j, n, m = 0;
+	unsigned long t_sleep = 1000;
+	pthread_attr_t attr;
+	pthread_t id;
 
-	if (argc < 2)
+	if (argc < 2) {
+		fprintf(stderr, "usage: fork nproc [mthreads [sleep]]\n");
 		return 1;
+	}
 
 	n = atoi(argv[1]);
+
+	if (argc > 2)
+		m = atoi(argv[2]);
+
+	if (argc > 3)
+		t_sleep = atoi(argv[3]);
+
+	pthread_attr_init(&attr);
+
 	for (i = 0; i < n; i++) {
 		pid_t pid;
 
@@ -20,8 +44,12 @@ int main(int argc, char **argv)
 			return 1;
 		}
 		if (pid == 0) {
-			while (1)
-				sleep(1000);
+			if (m) {
+				for (j = 0; j < m-1; ++j)
+					pthread_create(&id, &attr, f, (void *)t_sleep);
+			}
+
+			sleep(t_sleep);
 			return 0;
 		}
 	}
diff --git a/tools/testing/selftests/task_diag/run.sh b/tools/testing/selftests/task_diag/run.sh
index 62250a5..06e182d 100755
--- a/tools/testing/selftests/task_diag/run.sh
+++ b/tools/testing/selftests/task_diag/run.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
-./fork 1000
+./fork 1000 10
 nproc=`./task_diag_all A | grep 'pid.*tgid.*ppid.*comm fork$' | wc -l`
 killall -9 fork
-[ "$nproc" -eq 1000 ] && exit 0
+[ "$nproc" -eq 10000 ] && exit 0
 echo "Unexpected number of tasks '$nproc'" 1>&2
-- 
2.1.0

^ permalink raw reply related

* [PATCH 23/24] selftest: check the task_diag functinonality
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

Here are two test (example) programs.

task_diag - request information for two processes.
test_diag_all - request information about all processes

v2: Fixes from David Ahern:
    * task_diag: Fix 8-byte alignment for vma and vma_stats

Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/task_diag/Makefile         |  18 +++
 tools/testing/selftests/task_diag/fork.c           |  30 ++++
 tools/testing/selftests/task_diag/run.sh           |   6 +
 tools/testing/selftests/task_diag/task_diag.c      | 115 +++++++++++++++
 tools/testing/selftests/task_diag/task_diag.h      |   1 +
 tools/testing/selftests/task_diag/task_diag_all.c  | 145 +++++++++++++++++++
 tools/testing/selftests/task_diag/task_diag_comm.c | 157 +++++++++++++++++++++
 tools/testing/selftests/task_diag/task_diag_comm.h |  33 +++++
 tools/testing/selftests/task_diag/task_proc_all.c  |  35 +++++
 tools/testing/selftests/task_diag/taskstats.h      |   1 +
 11 files changed, 542 insertions(+)
 create mode 100644 tools/testing/selftests/task_diag/Makefile
 create mode 100644 tools/testing/selftests/task_diag/fork.c
 create mode 100755 tools/testing/selftests/task_diag/run.sh
 create mode 100644 tools/testing/selftests/task_diag/task_diag.c
 create mode 120000 tools/testing/selftests/task_diag/task_diag.h
 create mode 100644 tools/testing/selftests/task_diag/task_diag_all.c
 create mode 100644 tools/testing/selftests/task_diag/task_diag_comm.c
 create mode 100644 tools/testing/selftests/task_diag/task_diag_comm.h
 create mode 100644 tools/testing/selftests/task_diag/task_proc_all.c
 create mode 120000 tools/testing/selftests/task_diag/taskstats.h

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 95abddc..25a42de 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -18,6 +18,7 @@ TARGETS += timers
 TARGETS += user
 TARGETS += vm
 TARGETS += x86
+TARGETS += task_diag
 #Please keep the TARGETS list alphabetically sorted
 
 TARGETS_HOTPLUG = cpu-hotplug
diff --git a/tools/testing/selftests/task_diag/Makefile b/tools/testing/selftests/task_diag/Makefile
new file mode 100644
index 0000000..7104573
--- /dev/null
+++ b/tools/testing/selftests/task_diag/Makefile
@@ -0,0 +1,18 @@
+all: task_diag task_diag_all fork task_proc_all fork
+
+CFLAGS += -Wall -O2 -I/usr/include/libnl3
+LDFLAGS += -lnl-3 -lnl-genl-3
+TEST_PROGS := run.sh
+include ../lib.mk
+
+task_diag.o: task_diag.c task_diag_comm.h
+task_diag_all.o: task_diag_all.c task_diag_comm.h
+task_diag_comm.o: task_diag_comm.c task_diag_comm.h
+
+task_diag_all: task_diag_all.o task_diag_comm.o
+task_diag: task_diag.o task_diag_comm.o
+fork: fork.c
+task_proc_all: task_proc_all.c
+
+clean:
+	rm -rf task_diag task_diag_all task_diag_comm.o task_diag_all.o task_diag.o fork task_proc_all
diff --git a/tools/testing/selftests/task_diag/fork.c b/tools/testing/selftests/task_diag/fork.c
new file mode 100644
index 0000000..c6e17d1
--- /dev/null
+++ b/tools/testing/selftests/task_diag/fork.c
@@ -0,0 +1,30 @@
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+	int i, n;
+
+	if (argc < 2)
+		return 1;
+
+	n = atoi(argv[1]);
+	for (i = 0; i < n; i++) {
+		pid_t pid;
+
+		pid = fork();
+		if (pid < 0) {
+			printf("Unable to fork: %m\n");
+			return 1;
+		}
+		if (pid == 0) {
+			while (1)
+				sleep(1000);
+			return 0;
+		}
+	}
+
+	return 0;
+}
diff --git a/tools/testing/selftests/task_diag/run.sh b/tools/testing/selftests/task_diag/run.sh
new file mode 100755
index 0000000..62250a5
--- /dev/null
+++ b/tools/testing/selftests/task_diag/run.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+./fork 1000
+nproc=`./task_diag_all A | grep 'pid.*tgid.*ppid.*comm fork$' | wc -l`
+killall -9 fork
+[ "$nproc" -eq 1000 ] && exit 0
+echo "Unexpected number of tasks '$nproc'" 1>&2
diff --git a/tools/testing/selftests/task_diag/task_diag.c b/tools/testing/selftests/task_diag/task_diag.c
new file mode 100644
index 0000000..ff232a1
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <dirent.h>
+
+#include <linux/netlink.h>
+#include <netlink/socket.h>
+#include <linux/genetlink.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/mngt.h>
+
+#include "task_diag.h"
+#include "taskstats.h"
+#include "task_diag_comm.h"
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	int exit_status = 1;
+	int id;
+	struct task_diag_pid req;
+	struct nl_msg *msg;
+	void *hdr;
+	int err;
+
+
+	req.pid = 0;
+	if (argc >= 2)
+		req.pid = atoi(argv[1]);
+	if (req.pid == 0) {
+		pr_err("Usage: %s PID\n", argv[0]);
+		return 1;
+	}
+	req.show_flags = TASK_DIAG_SHOW_BASE | TASK_DIAG_SHOW_CRED |
+				TASK_DIAG_SHOW_VMA | TASK_DIAG_SHOW_VMA_STAT;
+
+	sock = nl_socket_alloc();
+	if (sock == NULL)
+		return -1;
+	nl_connect(sock, NETLINK_GENERIC);
+
+	err = genl_register_family(&ops);
+	if (err < 0) {
+		pr_err("Unable to register Generic Netlink family");
+		return -1;
+	}
+
+	err = genl_ops_resolve(sock, &ops);
+	if (err < 0) {
+		pr_err("Unable to resolve family name");
+		return -1;
+	}
+
+	id = genl_ctrl_resolve(sock, TASKSTATS_GENL_NAME);
+	if (id == GENL_ID_GENERATE)
+		return -1;
+
+	msg = nlmsg_alloc();
+	if (msg == NULL) {
+		pr_err("Unable to allocate netlink message");
+		return -1;
+	}
+
+	hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, id,
+			  0, 0, TASK_DIAG_CMD_GET, 0);
+	if (hdr == NULL) {
+		pr_err("Unable to write genl header");
+		return -1;
+	}
+
+	err = nla_put(msg, TASKSTATS_CMD_GET,
+				sizeof(struct task_diag_pid), &req);
+	if (err < 0) {
+		pr_err("Unable to add attribute: %s", nl_geterror(err));
+		return -1;
+	}
+
+	err = nl_send_auto_complete(sock, msg);
+	if (err < 0) {
+		pr_err("Unable to send message: %s", nl_geterror(err));
+		return -1;
+	}
+
+	nlmsg_free(msg);
+
+	err = nl_socket_modify_cb(sock, NL_CB_VALID,
+				NL_CB_CUSTOM, parse_cb, NULL);
+	if (err < 0) {
+		pr_err("Unable to modify valid message callback");
+		goto err;
+	}
+
+
+	err = nl_recvmsgs_default(sock);
+	if (err < 0) {
+		pr_err("Unable to receive message: %s", nl_geterror(err));
+		goto err;
+	}
+
+	exit_status = 0;
+err:
+	nl_close(sock);
+	nl_socket_free(sock);
+	return exit_status;
+}
diff --git a/tools/testing/selftests/task_diag/task_diag.h b/tools/testing/selftests/task_diag/task_diag.h
new file mode 120000
index 0000000..d20a38c
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag.h
@@ -0,0 +1 @@
+../../../../include/uapi/linux/task_diag.h
\ No newline at end of file
diff --git a/tools/testing/selftests/task_diag/task_diag_all.c b/tools/testing/selftests/task_diag/task_diag_all.c
new file mode 100644
index 0000000..53eb713
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_all.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <dirent.h>
+
+#include <linux/netlink.h>
+#include <netlink/socket.h>
+#include <linux/genetlink.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/mngt.h>
+
+#include "task_diag.h"
+#include "taskstats.h"
+#include "task_diag_comm.h"
+
+int main(int argc, char *argv[])
+{
+	struct nl_sock *sock;
+	int exit_status = 1;
+	int id;
+	struct task_diag_pid req;
+	struct nl_msg *msg;
+	__u32 last_pid = 0;
+	void *hdr;
+	int err;
+
+	req.show_flags = TASK_DIAG_SHOW_BASE | TASK_DIAG_SHOW_CRED |
+				TASK_DIAG_SHOW_VMA | TASK_DIAG_SHOW_VMA_STAT;
+
+	if (argc < 2) {
+		pr_err("Usage: %s type pid", argv[0]);
+		return 1;
+	}
+
+	req.pid = 0; /* dump all tasks by default */
+	if (argc > 2)
+		req.pid = atoi(argv[2]);
+
+	switch (argv[1][0]) {
+	case 'c':
+		req.dump_strategy = TASK_DIAG_DUMP_CHILDREN;
+		break;
+	case 't':
+		req.dump_strategy = TASK_DIAG_DUMP_THREAD;
+		break;
+	case 'o':
+		req.dump_strategy = TASK_DIAG_DUMP_ONE;
+		break;
+	case 'a':
+		req.dump_strategy = TASK_DIAG_DUMP_ALL;
+		req.pid = 0;
+		break;
+	case 'A':
+		req.dump_strategy = TASK_DIAG_DUMP_ALL_THREAD;
+		req.pid = 0;
+		break;
+	default:
+		pr_err("Usage: %s type pid", argv[0]);
+		return 1;
+	}
+
+	sock = nl_socket_alloc();
+	if (sock == NULL)
+		return -1;
+	nl_connect(sock, NETLINK_GENERIC);
+
+	err = genl_register_family(&ops);
+	if (err < 0) {
+		pr_err("Unable to register Generic Netlink family");
+		return -1;
+	}
+
+	err = genl_ops_resolve(sock, &ops);
+	if (err < 0) {
+		pr_err("Unable to resolve family name");
+		return -1;
+	}
+
+	id = genl_ctrl_resolve(sock, TASKSTATS_GENL_NAME);
+	if (id == GENL_ID_GENERATE)
+		return -1;
+
+	msg = nlmsg_alloc();
+	if (msg == NULL) {
+		pr_err("Unable to allocate netlink message");
+		return -1;
+	}
+
+	hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, id,
+			  0, NLM_F_DUMP, TASK_DIAG_CMD_GET, 0);
+	if (hdr == NULL) {
+		pr_err("Unable to write genl header");
+		return -1;
+	}
+
+	err = nla_put(msg, TASKSTATS_CMD_GET, sizeof(req), &req);
+	if (err < 0) {
+		pr_err("Unable to add attribute: %s", nl_geterror(err));
+		return -1;
+	}
+
+	err = nl_send_auto_complete(sock, msg);
+	if (err < 0) {
+		pr_err("Unable to send message: %s", nl_geterror(err));
+		return -1;
+	}
+
+	nlmsg_free(msg);
+
+	err = nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM,
+			parse_cb, &last_pid);
+	if (err < 0) {
+		pr_err("Unable to modify valid message callback");
+		goto err;
+	}
+	err = nl_socket_modify_cb(sock, NL_CB_FINISH, NL_CB_CUSTOM,
+			parse_cb, &last_pid);
+	if (err < 0) {
+		pr_err("Unable to modify valid message callback");
+		goto err;
+	}
+
+
+	err = nl_recvmsgs_default(sock);
+	if (err < 0) {
+		pr_err("Unable to receive message: %s", nl_geterror(err));
+		goto err;
+	}
+
+	exit_status = 0;
+err:
+	nl_close(sock);
+	nl_socket_free(sock);
+	return exit_status;
+}
diff --git a/tools/testing/selftests/task_diag/task_diag_comm.c b/tools/testing/selftests/task_diag/task_diag_comm.c
new file mode 100644
index 0000000..480c7cf
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_comm.c
@@ -0,0 +1,157 @@
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <netlink/cli/utils.h>
+
+#include "task_diag.h"
+#include "taskstats.h"
+#include "task_diag_comm.h"
+
+int quiet;
+
+static struct nla_policy attr_policy[TASK_DIAG_ATTR_MAX + 1] = {
+	[TASK_DIAG_PID] = { .type = NLA_U32},
+	[TASK_DIAG_BASE] = { .minlen = sizeof(struct task_diag_base) },
+	[TASK_DIAG_CRED] = { .minlen = sizeof(struct task_diag_creds) },
+};
+
+#define PSS_SHIFT 12
+static int parse_cmd_new(struct nl_cache_ops *unused, struct genl_cmd *cmd,
+			 struct genl_info *info, void *arg)
+{
+	struct nlattr **attrs;
+
+	attrs = info->attrs;
+	__u32 *last_pid = (__u32 *)arg, pid;
+
+	if (arg) {
+		pid = *((__u32 *)nla_data(attrs[TASK_DIAG_PID]));
+
+		if (pid != *last_pid)
+			pr_info("Start getting information about %d\n", pid);
+		else
+			pr_info("Continue getting information about %d\n", pid);
+
+		*last_pid = pid;
+	}
+
+	if (attrs[TASK_DIAG_BASE]) {
+		struct task_diag_base *msg;
+
+		/* For nested attributes, na follows */
+		msg = nla_data(attrs[TASK_DIAG_BASE]);
+		pr_info("pid %d tgid %d ppid %d comm %s\n",
+			msg->pid, msg->tgid, msg->ppid, msg->comm);
+	}
+
+	if (attrs[TASK_DIAG_CRED]) {
+		struct task_diag_creds *creds;
+
+		creds = nla_data(attrs[TASK_DIAG_CRED]);
+		pr_info("uid: %d %d %d %d\n", creds->uid,
+				creds->euid, creds->suid, creds->fsuid);
+		pr_info("gid: %d %d %d %d\n", creds->uid,
+				creds->euid, creds->suid, creds->fsuid);
+		pr_info("CapInh: %08x%08x\n",
+					creds->cap_inheritable.cap[1],
+					creds->cap_inheritable.cap[0]);
+		pr_info("CapPrm: %08x%08x\n",
+					creds->cap_permitted.cap[1],
+					creds->cap_permitted.cap[0]);
+		pr_info("CapEff: %08x%08x\n",
+					creds->cap_effective.cap[1],
+					creds->cap_effective.cap[0]);
+		pr_info("CapBnd: %08x%08x\n", creds->cap_bset.cap[1],
+					creds->cap_bset.cap[0]);
+	}
+
+	if (attrs[TASK_DIAG_VMA]) {
+		struct task_diag_vma *vma_tmp, vma;
+
+		task_diag_for_each_vma(vma_tmp, attrs[TASK_DIAG_VMA]) {
+			char *name;
+			struct task_diag_vma_stat *stat_tmp, stat;
+
+			name = task_diag_vma_name(vma_tmp);
+			if (name == NULL)
+				name = "";
+
+			memcpy(&vma, vma_tmp, sizeof(vma));
+			pr_info("%016llx-%016llx %016llx %s\n",
+				vma.start, vma.end, vma.vm_flags, name);
+
+			stat_tmp = task_diag_vma_stat(vma_tmp);
+			if (stat_tmp)
+				memcpy(&stat, stat_tmp, sizeof(stat));
+			else
+				memset(&stat, 0, sizeof(stat));
+
+			pr_info(
+				   "Size:           %8llu kB\n"
+				   "Rss:            %8llu kB\n"
+				   "Pss:            %8llu kB\n"
+				   "Shared_Clean:   %8llu kB\n"
+				   "Shared_Dirty:   %8llu kB\n"
+				   "Private_Clean:  %8llu kB\n"
+				   "Private_Dirty:  %8llu kB\n"
+				   "Referenced:     %8llu kB\n"
+				   "Anonymous:      %8llu kB\n"
+				   "AnonHugePages:  %8llu kB\n"
+				   "Swap:           %8llu kB\n",
+				   (vma.end - vma.start) >> 10,
+				   stat.resident >> 10,
+				   (stat.pss >> (10 + PSS_SHIFT)),
+				   stat.shared_clean  >> 10,
+				   stat.shared_dirty  >> 10,
+				   stat.private_clean >> 10,
+				   stat.private_dirty >> 10,
+				   stat.referenced >> 10,
+				   stat.anonymous >> 10,
+				   stat.anonymous_thp >> 10,
+				   stat.swap >> 10);
+		}
+	}
+
+	return 0;
+}
+
+static struct genl_cmd cmds[] = {
+	{
+		.c_id	   = TASK_DIAG_CMD_GET,
+		.c_name	 = "taskstats_new()",
+		.c_maxattr      = TASK_DIAG_ATTR_MAX,
+		.c_attr_policy  = attr_policy,
+		.c_msg_parser   = &parse_cmd_new,
+	},
+};
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+
+struct genl_ops ops = {
+	.o_name = TASKSTATS_GENL_NAME,
+	.o_cmds = cmds,
+	.o_ncmds = ARRAY_SIZE(cmds),
+};
+
+int parse_cb(struct nl_msg *msg, void *arg)
+{
+	struct nlmsghdr *hdr = nlmsg_hdr(msg);
+
+	if (hdr->nlmsg_type == NLMSG_DONE) {
+		int *ret = nlmsg_data(hdr);
+
+		if (*ret < 0) {
+			pr_err("An error message is received: %s\n",
+							strerror(-*ret));
+			return *ret;
+		}
+		return 0;
+	}
+
+	return genl_handle_msg(msg, arg);
+}
diff --git a/tools/testing/selftests/task_diag/task_diag_comm.h b/tools/testing/selftests/task_diag/task_diag_comm.h
new file mode 100644
index 0000000..5f6ba07
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_comm.h
@@ -0,0 +1,33 @@
+#ifndef __TASK_DIAG_COMM__
+#define __TASK_DIAG_COMM__
+
+#include <stdio.h>
+
+#include <linux/genetlink.h>
+#include "task_diag.h"
+
+/*
+ * Generic macros for dealing with netlink sockets. Might be duplicated
+ * elsewhere. It is recommended that commercial grade applications use
+ * libnl or libnetlink and use the interfaces provided by the library
+ */
+#define GENLMSG_DATA(glh)	((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh)	(NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+
+#define pr_err(fmt, ...)				\
+		fprintf(stderr, fmt"\n", ##__VA_ARGS__)
+
+#define pr_perror(fmt, ...)				\
+		fprintf(stderr, fmt " : %m\n", ##__VA_ARGS__)
+
+extern int quiet;
+#define pr_info(fmt, arg...)			\
+	do {					\
+		if (!quiet)			\
+			printf(fmt, ##arg);	\
+	} while (0)				\
+
+struct genl_ops ops;
+int parse_cb(struct nl_msg *msg, void *arg);
+
+#endif /* __TASK_DIAG_COMM__ */
diff --git a/tools/testing/selftests/task_diag/task_proc_all.c b/tools/testing/selftests/task_diag/task_proc_all.c
new file mode 100644
index 0000000..07ee80c
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_proc_all.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+int main(int argc, char **argv)
+{
+	DIR *d;
+	int fd, tasks = 0;
+	struct dirent *de;
+	char buf[4096];
+
+	d = opendir("/proc");
+	if (d == NULL)
+		return 1;
+
+	while ((de = readdir(d))) {
+		if (de->d_name[0] < '0' || de->d_name[0] > '9')
+			continue;
+		snprintf(buf, sizeof(buf), "/proc/%s/stat", de->d_name);
+		fd = open(buf, O_RDONLY);
+		read(fd, buf, sizeof(buf));
+		close(fd);
+		tasks++;
+	}
+
+	closedir(d);
+
+	printf("tasks: %d\n", tasks);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/task_diag/taskstats.h b/tools/testing/selftests/task_diag/taskstats.h
new file mode 120000
index 0000000..fa9523b
--- /dev/null
+++ b/tools/testing/selftests/task_diag/taskstats.h
@@ -0,0 +1 @@
+../../../../include/uapi/linux/taskstats.h
\ No newline at end of file
-- 
2.1.0

^ permalink raw reply related

* [PATCH 22/24] Documentation: add documentation for task_diag
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 Documentation/accounting/task_diag.txt | 53 ++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/accounting/task_diag.txt

diff --git a/Documentation/accounting/task_diag.txt b/Documentation/accounting/task_diag.txt
new file mode 100644
index 0000000..635b322
--- /dev/null
+++ b/Documentation/accounting/task_diag.txt
@@ -0,0 +1,53 @@
+Taskdiag is a netlink interface for getting task properties. Compared to procfs,
+it is faster, more flexible and provides data in a binary format. Taskdiag was
+created using the basic idea of socket_diag.
+
+Interface
+---------
+
+The user-kernel interface is encapsulated in include/uapi/linux/task_diag.h
+
+Request
+-------
+
+A request is described by the task_diag_pid structure.
+
+struct task_diag_pid {
+	__u64	show_flags;	/* TASK_DIAG_SHOW_* */
+	__u64	dump_stratagy;	/* TASK_DIAG_DUMP_* */
+
+	__u32	pid;
+};
+
+dump_stratagy specifies a group of processes:
+/* per-process strategies */
+TASK_DIAG_DUMP_CHILDREN	- all children
+TASK_DIAG_DUMP_THREAD	- all threads
+TASK_DIAG_DUMP_ONE	- one process
+/* system wide strategies (the pid fiel is ignored) */
+TASK_DIAG_DUMP_ALL	  - all processes
+TASK_DIAG_DUMP_ALL_THREAD - all threads
+
+show_flags specifies which information are required.  If we set the
+TASK_DIAG_SHOW_BASE flag, the response message will contain the TASK_DIAG_BASE
+attribute which is described by the task_diag_base structure.
+
+In future, it can be extended by optional attributes. The request describes
+which task properties are required and for which processes they are required
+for.
+
+Response
+--------
+
+A response can be divided into a few netlink packets if the NETLINK_DUMP has
+been set in a request. Each task is described by a message. Each message
+contains the TASK_DIAG_PID attribute and optional attributes which have been
+requested. A message can be divided into a few parts if it doesn’t fit into a
+current netlink packet. In this case, the first message in the next packet
+contains the same PID and attributes which doesn’t  fit into the previous
+message.
+
+Examples
+--------
+
+A few examples can be found in tools/testing/selftests/task_diag/
-- 
2.1.0

^ permalink raw reply related

* [PATCH 21/24] task diag: Add support for TGID attribute
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

From: David Ahern <dsahern@gmail.com>

Add TGID attribute and put in every message. This is need for perf for
example when processing messages with maps.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 include/uapi/linux/task_diag.h | 1 +
 kernel/taskdiag.c              | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/task_diag.h b/include/uapi/linux/task_diag.h
index 19c9579..935502b 100644
--- a/include/uapi/linux/task_diag.h
+++ b/include/uapi/linux/task_diag.h
@@ -15,6 +15,7 @@ enum {
 
 	/* other attributes */
 	TASK_DIAG_PID	= 64,	/* u32 */
+	TASK_DIAG_TGID,		/* u32 */
 
 	__TASK_DIAG_ATTR_MAX
 #define TASK_DIAG_ATTR_MAX (__TASK_DIAG_ATTR_MAX - 1)
diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c
index 6549df3..ccba538 100644
--- a/kernel/taskdiag.c
+++ b/kernel/taskdiag.c
@@ -13,6 +13,7 @@ static size_t taskdiag_packet_size(u64 show_flags, int n_vma)
 	size_t size;
 
 	size = nla_total_size(sizeof(u32)); /* PID */
+	       + nla_total_size(sizeof(u32)); /* TGID */
 
 	if (show_flags & TASK_DIAG_SHOW_BASE)
 		size += nla_total_size(sizeof(struct task_diag_base));
@@ -451,7 +452,7 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb,
 	int err = 0, i = 0, n = 0;
 	bool progress = false;
 	int flags = 0;
-	u32 pid;
+	u32 pid, tgid;
 
 	if (cb) {
 		n = cb->args[2];
@@ -468,6 +469,11 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb,
 	if (err)
 		goto err;
 
+	tgid = task_tgid_vnr(tsk);
+	err = nla_put_u32(skb, TASK_DIAG_TGID, tgid);
+	if (err)
+		goto err;
+
 	if (show_flags & TASK_DIAG_SHOW_BASE) {
 		if (i >= n)
 			err = fill_task_base(tsk, skb);
-- 
2.1.0

^ permalink raw reply related

* [PATCH 20/24] task_diag: Only add VMAs for thread_group leader
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

From: David Ahern <dsahern@gmail.com>

threads of a process share the same VMAs, so when dumping all threads
for all processes only push vma data for group leader.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 kernel/taskdiag.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c
index e5a5eed..6549df3 100644
--- a/kernel/taskdiag.c
+++ b/kernel/taskdiag.c
@@ -443,9 +443,10 @@ err:
 }
 
 static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb,
-				u64 show_flags, u32 portid, u32 seq,
-				struct netlink_callback *cb)
+			  struct task_diag_pid *req, u32 portid, u32 seq,
+			  struct netlink_callback *cb)
 {
+	u64 show_flags = req->show_flags;
 	void *reply;
 	int err = 0, i = 0, n = 0;
 	bool progress = false;
@@ -492,6 +493,13 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb,
 	}
 
 	if (show_flags & TASK_DIAG_SHOW_VMA) {
+		/* if the request is to dump all threads of all processes
+		 * only show VMAs for group leader.
+		 */
+		if (req->dump_strategy == TASK_DIAG_DUMP_ALL_THREAD &&
+		    !thread_group_leader(tsk))
+			goto done;
+
 		if (i >= n)
 			err = fill_vma(tsk, skb, cb, &progress, show_flags);
 		if (err)
@@ -499,6 +507,7 @@ static int task_diag_fill(struct task_struct *tsk, struct sk_buff *skb,
 		i++;
 	}
 
+done:
 	genlmsg_end(skb, reply);
 	if (cb)
 		cb->args[2] = 0;
@@ -696,7 +705,7 @@ int taskdiag_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 	for (; task; task = iter_next(&iter)) {
 		if (!ptrace_may_access(task, PTRACE_MODE_READ))
 			continue;
-		rc = task_diag_fill(task, skb, iter.req.show_flags,
+		rc = task_diag_fill(task, skb, &iter.req,
 				NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb);
 		if (rc < 0) {
 			if (rc != -EMSGSIZE) {
@@ -755,7 +764,7 @@ int taskdiag_doit(struct sk_buff *skb, struct genl_info *info)
 			return -EMSGSIZE;
 		}
 
-		rc = task_diag_fill(tsk, msg, req.show_flags,
+		rc = task_diag_fill(tsk, msg, &req,
 					info->snd_portid, info->snd_seq, NULL);
 		if (rc != -EMSGSIZE)
 			break;
-- 
2.1.0

^ permalink raw reply related

* [PATCH 19/24] task_diag: Add option to dump all threads for all tasks
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

From: David Ahern <dsahern@gmail.com>

New dump strategy to walk all threads of all processes.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 include/uapi/linux/task_diag.h |  7 +++---
 kernel/taskdiag.c              | 55 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/include/uapi/linux/task_diag.h b/include/uapi/linux/task_diag.h
index 4a1cecb..19c9579 100644
--- a/include/uapi/linux/task_diag.h
+++ b/include/uapi/linux/task_diag.h
@@ -149,9 +149,10 @@ static inline struct task_diag_vma_stat *task_diag_vma_stat(struct task_diag_vma
 		vma = (void *) vma + vma->vma_len)
 
 #define TASK_DIAG_DUMP_ALL	0
-#define TASK_DIAG_DUMP_CHILDREN	1
-#define TASK_DIAG_DUMP_THREAD	2
-#define TASK_DIAG_DUMP_ONE	3
+#define TASK_DIAG_DUMP_ALL_THREAD	1
+#define TASK_DIAG_DUMP_CHILDREN	2
+#define TASK_DIAG_DUMP_THREAD	3
+#define TASK_DIAG_DUMP_ONE	4
 
 struct task_diag_pid {
 	__u64	show_flags;
diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c
index 20494ee..e5a5eed 100644
--- a/kernel/taskdiag.c
+++ b/kernel/taskdiag.c
@@ -521,13 +521,9 @@ struct task_iter {
 	struct netlink_callback *cb;
 	struct task_struct *parent;
 
-	union {
-		struct tgid_iter tgid;
-		struct {
-			unsigned int		pos;
-			struct task_struct	*task;
-		};
-	};
+	struct tgid_iter tgid;
+	unsigned int		pos;
+	struct task_struct	*task;
 };
 
 static void iter_stop(struct task_iter *iter)
@@ -541,6 +537,12 @@ static void iter_stop(struct task_iter *iter)
 	case TASK_DIAG_DUMP_ALL:
 		task = iter->tgid.task;
 		break;
+	case TASK_DIAG_DUMP_ALL_THREAD:
+		/* release both tgid task and thread task */
+		if (iter->task)
+			put_task_struct(iter->task);
+		task = iter->tgid.task;
+		break;
 	default:
 		task = iter->task;
 	}
@@ -590,6 +592,25 @@ static struct task_struct *iter_start(struct task_iter *iter)
 		iter->tgid.task = NULL;
 		iter->tgid = next_tgid(iter->ns, iter->tgid);
 		return iter->tgid.task;
+
+	case TASK_DIAG_DUMP_ALL_THREAD:
+		iter->pos = iter->cb->args[1];
+		iter->tgid.tgid = iter->cb->args[0];
+		iter->tgid.task = NULL;
+		iter->tgid = next_tgid(iter->ns, iter->tgid);
+		if (!iter->tgid.task)
+			return NULL;
+
+		iter->task = task_first_tid(iter->tgid.task, 0, iter->pos, iter->ns);
+		if (!iter->task) {
+			iter->pos = 0;
+			iter->tgid.tgid += 1;
+			iter->tgid = next_tgid(iter->ns, iter->tgid);
+			iter->task = iter->tgid.task;
+			if (iter->task)
+				get_task_struct(iter->task);
+		}
+		return iter->task;
 	}
 
 	return ERR_PTR(-EINVAL);
@@ -622,6 +643,24 @@ static struct task_struct *iter_next(struct task_iter *iter)
 		iter->tgid = next_tgid(iter->ns, iter->tgid);
 		iter->cb->args[0] = iter->tgid.tgid;
 		return iter->tgid.task;
+
+	case TASK_DIAG_DUMP_ALL_THREAD:
+		iter->pos++;
+		iter->task = task_next_tid(iter->task);
+		if (!iter->task) {
+			iter->pos = 0;
+			iter->tgid.tgid += 1;
+			iter->tgid = next_tgid(iter->ns, iter->tgid);
+			iter->task = iter->tgid.task;
+			if (iter->task)
+				get_task_struct(iter->task);
+		}
+
+		/* save current position */
+		iter->cb->args[0] = iter->tgid.tgid;
+		iter->cb->args[1] = iter->pos;
+
+		return iter->task;
 	}
 
 	return NULL;
@@ -647,6 +686,8 @@ int taskdiag_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 	iter.ns     = ns;
 	iter.cb     = cb;
 	iter.parent = NULL;
+	iter.pos    = 0;
+	iter.task   = NULL;
 
 	task = iter_start(&iter);
 	if (IS_ERR(task))
-- 
2.1.0

^ permalink raw reply related

* [PATCH 18/24] task_diag: add ability to handle one task in a continious mode
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

If a task has many vma-s, the size of information about them can be too
big to be placed into one skb.

Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 include/uapi/linux/task_diag.h |  1 +
 kernel/taskdiag.c              | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/uapi/linux/task_diag.h b/include/uapi/linux/task_diag.h
index e1d09e6..4a1cecb 100644
--- a/include/uapi/linux/task_diag.h
+++ b/include/uapi/linux/task_diag.h
@@ -151,6 +151,7 @@ static inline struct task_diag_vma_stat *task_diag_vma_stat(struct task_diag_vma
 #define TASK_DIAG_DUMP_ALL	0
 #define TASK_DIAG_DUMP_CHILDREN	1
 #define TASK_DIAG_DUMP_THREAD	2
+#define TASK_DIAG_DUMP_ONE	3
 
 struct task_diag_pid {
 	__u64	show_flags;
diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c
index dc319bf..20494ee 100644
--- a/kernel/taskdiag.c
+++ b/kernel/taskdiag.c
@@ -559,6 +559,16 @@ static struct task_struct *iter_start(struct task_iter *iter)
 	}
 
 	switch (iter->req.dump_strategy) {
+	case TASK_DIAG_DUMP_ONE:
+		if (iter->parent == NULL)
+			return ERR_PTR(-ESRCH);
+		iter->pos = iter->cb->args[0];
+		if (iter->pos == 0) {
+			iter->task = iter->parent;
+			get_task_struct(iter->task);
+		} else
+			iter->task = NULL;
+		return iter->task;
 	case TASK_DIAG_DUMP_THREAD:
 		if (iter->parent == NULL)
 			return ERR_PTR(-ESRCH);
@@ -588,6 +598,13 @@ static struct task_struct *iter_start(struct task_iter *iter)
 static struct task_struct *iter_next(struct task_iter *iter)
 {
 	switch (iter->req.dump_strategy) {
+	case TASK_DIAG_DUMP_ONE:
+		iter->pos++;
+		iter->cb->args[0] = iter->pos;
+		if (iter->task)
+			put_task_struct(iter->task);
+		iter->task = NULL;
+		return NULL;
 	case TASK_DIAG_DUMP_THREAD:
 		iter->pos++;
 		iter->task = task_next_tid(iter->task);
-- 
2.1.0

^ permalink raw reply related

* [PATCH 17/24] task_diag: add ability to dump theads
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-api-u79uwXL29TY76Z2rM5mHXA, Andrey Vagin, Oleg Nesterov,
	Andrew Morton, Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi,
	Arnd Bergmann, Arnaldo Carvalho de Melo, David Ahern,
	Andy Lutomirski, Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>

Signed-off-by: Andrey Vagin <avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
---
 include/uapi/linux/task_diag.h |  1 +
 kernel/taskdiag.c              | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/task_diag.h b/include/uapi/linux/task_diag.h
index 9e4c3c4..e1d09e6 100644
--- a/include/uapi/linux/task_diag.h
+++ b/include/uapi/linux/task_diag.h
@@ -150,6 +150,7 @@ static inline struct task_diag_vma_stat *task_diag_vma_stat(struct task_diag_vma
 
 #define TASK_DIAG_DUMP_ALL	0
 #define TASK_DIAG_DUMP_CHILDREN	1
+#define TASK_DIAG_DUMP_THREAD	2
 
 struct task_diag_pid {
 	__u64	show_flags;
diff --git a/kernel/taskdiag.c b/kernel/taskdiag.c
index 8e00c3e..dc319bf 100644
--- a/kernel/taskdiag.c
+++ b/kernel/taskdiag.c
@@ -559,8 +559,15 @@ static struct task_struct *iter_start(struct task_iter *iter)
 	}
 
 	switch (iter->req.dump_strategy) {
-	case TASK_DIAG_DUMP_CHILDREN:
+	case TASK_DIAG_DUMP_THREAD:
+		if (iter->parent == NULL)
+			return ERR_PTR(-ESRCH);
+
+		iter->pos = iter->cb->args[0];
+		iter->task = task_first_tid(iter->parent, 0, iter->pos, iter->ns);
+		return iter->task;
 
+	case TASK_DIAG_DUMP_CHILDREN:
 		if (iter->parent == NULL)
 			return ERR_PTR(-ESRCH);
 
@@ -581,6 +588,12 @@ static struct task_struct *iter_start(struct task_iter *iter)
 static struct task_struct *iter_next(struct task_iter *iter)
 {
 	switch (iter->req.dump_strategy) {
+	case TASK_DIAG_DUMP_THREAD:
+		iter->pos++;
+		iter->task = task_next_tid(iter->task);
+		iter->cb->args[0] = iter->pos;
+		iter->cb->args[1] = task_pid_nr_ns(iter->task, iter->ns);
+		return iter->task;
 	case TASK_DIAG_DUMP_CHILDREN:
 		iter->pos++;
 		iter->task = task_next_child(iter->parent, iter->task, iter->pos);
-- 
2.1.0

^ permalink raw reply related

* [PATCH 16/24] proc: move first_tid and next_tid out of proc
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

They will be used in task_diag

Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 fs/proc/base.c          | 79 ++-----------------------------------------------
 include/linux/proc_fs.h |  4 +++
 kernel/pid.c            | 76 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 77 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index af797d9..4b72053 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3213,81 +3213,6 @@ out_no_task:
 	return ERR_PTR(result);
 }
 
-/*
- * Find the first tid of a thread group to return to user space.
- *
- * Usually this is just the thread group leader, but if the users
- * buffer was too small or there was a seek into the middle of the
- * directory we have more work todo.
- *
- * In the case of a short read we start with find_task_by_pid.
- *
- * In the case of a seek we start with the leader and walk nr
- * threads past it.
- */
-static struct task_struct *
-first_tid(struct task_struct *task, int tid, loff_t f_pos,
-					struct pid_namespace *ns)
-{
-	struct task_struct *pos;
-	unsigned long nr = f_pos;
-
-	if (nr != f_pos)	/* 32bit overflow? */
-		return NULL;
-
-	rcu_read_lock();
-
-	/* Attempt to start with the tid of a thread */
-	if (tid && nr) {
-		pos = find_task_by_pid_ns(tid, ns);
-		if (pos && same_thread_group(pos, task))
-			goto found;
-	}
-
-	/* If nr exceeds the number of threads there is nothing todo */
-	if (nr >= get_nr_threads(task))
-		goto fail;
-
-	/* If we haven't found our starting place yet start
-	 * with the leader and walk nr threads forward.
-	 */
-	pos = task = task->group_leader;
-	do {
-		if (!nr--)
-			goto found;
-	} while_each_thread(task, pos);
-fail:
-	pos = NULL;
-	goto out;
-found:
-	get_task_struct(pos);
-out:
-	rcu_read_unlock();
-	return pos;
-}
-
-/*
- * Find the next thread in the thread list.
- * Return NULL if there is an error or no next thread.
- *
- * The reference to the input task_struct is released.
- */
-static struct task_struct *next_tid(struct task_struct *start)
-{
-	struct task_struct *pos = NULL;
-	rcu_read_lock();
-	if (pid_alive(start)) {
-		pos = next_thread(start);
-		if (thread_group_leader(pos))
-			pos = NULL;
-		else
-			get_task_struct(pos);
-	}
-	rcu_read_unlock();
-	put_task_struct(start);
-	return pos;
-}
-
 /* for the /proc/TGID/task/ directories */
 static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 {
@@ -3312,9 +3237,9 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 	ns = inode->i_sb->s_fs_info;
 	tid = (int)file->f_version;
 	file->f_version = 0;
-	for (task = first_tid(start, tid, ctx->pos - 2, ns);
+	for (task = task_first_tid(start, tid, ctx->pos - 2, ns);
 	     task;
-	     task = next_tid(task), ctx->pos++) {
+	     task = task_next_tid(task), ctx->pos++) {
 		char name[PROC_NUMBUF];
 		int len;
 		tid = task_pid_nr_ns(task, ns);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 62d0079..178f526 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -92,6 +92,10 @@ struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter);
 struct task_struct *
 task_next_child(struct task_struct *parent, struct task_struct *prev, unsigned int pos);
 
+struct task_struct *task_first_tid(struct task_struct *task, int tid, loff_t f_pos,
+					struct pid_namespace *ns);
+struct task_struct *task_next_tid(struct task_struct *start);
+
 struct mem_size_stats {
 	unsigned long resident;
 	unsigned long shared_clean;
diff --git a/kernel/pid.c b/kernel/pid.c
index 42a6b40..b66f370 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -661,6 +661,82 @@ out:
 }
 
 /*
+ * Find the first tid of a thread group to return to user space.
+ *
+ * Usually this is just the thread group leader, but if the users
+ * buffer was too small or there was a seek into the middle of the
+ * directory we have more work todo.
+ *
+ * In the case of a short read we start with find_task_by_pid.
+ *
+ * In the case of a seek we start with the leader and walk nr
+ * threads past it.
+ */
+struct task_struct *
+task_first_tid(struct task_struct *task, int tid, loff_t f_pos,
+					struct pid_namespace *ns)
+{
+	struct task_struct *pos;
+	unsigned long nr = f_pos;
+
+	if (nr != f_pos)	/* 32bit overflow? */
+		return NULL;
+
+	rcu_read_lock();
+
+	/* Attempt to start with the tid of a thread */
+	if (tid && nr) {
+		pos = find_task_by_pid_ns(tid, ns);
+		if (pos && same_thread_group(pos, task))
+			goto found;
+	}
+
+	/* If nr exceeds the number of threads there is nothing todo */
+	if (nr >= get_nr_threads(task))
+		goto fail;
+
+	/* If we haven't found our starting place yet start
+	 * with the leader and walk nr threads forward.
+	 */
+	pos = task = task->group_leader;
+	do {
+		if (!nr--)
+			goto found;
+	} while_each_thread(task, pos);
+fail:
+	pos = NULL;
+	goto out;
+found:
+	get_task_struct(pos);
+out:
+	rcu_read_unlock();
+	return pos;
+}
+
+/*
+ * Find the next thread in the thread list.
+ * Return NULL if there is an error or no next thread.
+ *
+ * The reference to the input task_struct is released.
+ */
+struct task_struct *task_next_tid(struct task_struct *start)
+{
+	struct task_struct *pos = NULL;
+	rcu_read_lock();
+	if (pid_alive(start)) {
+		pos = next_thread(start);
+		if (thread_group_leader(pos))
+			pos = NULL;
+		else
+			get_task_struct(pos);
+	}
+	rcu_read_unlock();
+	put_task_struct(start);
+	return pos;
+}
+
+
+/*
  * The pid hash table is scaled according to the amount of memory in the
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
  * more.
-- 
2.1.0

^ permalink raw reply related

* [PATCH 15/24] proc: give task_struct instead of pid into first_tid
From: Andrey Vagin @ 2015-07-06  8:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-api, Andrey Vagin, Oleg Nesterov, Andrew Morton,
	Cyrill Gorcunov, Pavel Emelyanov, Roger Luethi, Arnd Bergmann,
	Arnaldo Carvalho de Melo, David Ahern, Andy Lutomirski,
	Pavel Odintsov
In-Reply-To: <1436172445-6979-1-git-send-email-avagin@openvz.org>

It will be more convenient when this function will be used in
task_diag.

Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
 fs/proc/base.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 88cf6ae..af797d9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3225,19 +3225,17 @@ out_no_task:
  * In the case of a seek we start with the leader and walk nr
  * threads past it.
  */
-static struct task_struct *first_tid(struct pid *pid, int tid, loff_t f_pos,
+static struct task_struct *
+first_tid(struct task_struct *task, int tid, loff_t f_pos,
 					struct pid_namespace *ns)
 {
-	struct task_struct *pos, *task;
+	struct task_struct *pos;
 	unsigned long nr = f_pos;
 
 	if (nr != f_pos)	/* 32bit overflow? */
 		return NULL;
 
 	rcu_read_lock();
-	task = pid_task(pid, PIDTYPE_PID);
-	if (!task)
-		goto fail;
 
 	/* Attempt to start with the tid of a thread */
 	if (tid && nr) {
@@ -3294,7 +3292,7 @@ static struct task_struct *next_tid(struct task_struct *start)
 static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct inode *inode = file_inode(file);
-	struct task_struct *task;
+	struct task_struct *start, *task;
 	struct pid_namespace *ns;
 	int tid;
 
@@ -3304,13 +3302,17 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 	if (!dir_emit_dots(file, ctx))
 		return 0;
 
+	start = get_proc_task(inode);
+	if (!start)
+		return 0;
+
 	/* f_version caches the tgid value that the last readdir call couldn't
 	 * return. lseek aka telldir automagically resets f_version to 0.
 	 */
 	ns = inode->i_sb->s_fs_info;
 	tid = (int)file->f_version;
 	file->f_version = 0;
-	for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns);
+	for (task = first_tid(start, tid, ctx->pos - 2, ns);
 	     task;
 	     task = next_tid(task), ctx->pos++) {
 		char name[PROC_NUMBUF];
@@ -3327,6 +3329,8 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 		}
 	}
 
+	put_task_struct(start);
+
 	return 0;
 }
 
-- 
2.1.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox