Jesper Derehag | 18 Apr 23:55 2014
Picon

[PATCH v2 babeltrace] Added fallback for betoh/htobe if they do not exist

For older systems endian.h may not contain the betoh/htobe macros.
If they are missing, add them and make sure that any user of
htobe/betoh uses include/babeltrace/endian.h and not system endian.h

Signed-off-by: Jesper Derehag <jderehag <at> hotmail.com>
Tested-by: Jesper Derehag <jderehag <at> hotmail.com>
---
Fixed the commit author email to jderehag <at> hotmail.com

 formats/lttng-live/lttng-live-comm.c |  1 +
 include/babeltrace/endian.h          | 91 +++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/formats/lttng-live/lttng-live-comm.c b/formats/lttng-live/lttng-live-comm.c
index 9feb718..3aad981 100644
--- a/formats/lttng-live/lttng-live-comm.c
+++ b/formats/lttng-live/lttng-live-comm.c
 <at>  <at>  -50,6 +50,7  <at>  <at> 
 #include <babeltrace/ctf/events-internal.h>
 #include <formats/ctf/events-private.h>

+#include <babeltrace/endian.h>
 #include <babeltrace/compat/memstream.h>

 #include "lttng-live.h"
diff --git a/include/babeltrace/endian.h b/include/babeltrace/endian.h
index f15a44f..e39e599 100644
--- a/include/babeltrace/endian.h
+++ b/include/babeltrace/endian.h
 <at>  <at>  -47,7 +47,96  <at>  <at> 
(Continue reading)

Jesper Derehag | 18 Apr 23:48 2014
Picon

[PATCH babeltrace] Added fallback for betoh/htobe if they do not exist

From: Jesper Derehag <jesper.derehag <at> ericsson.com>

For older systems endian.h may not contain the betoh/htobe macros.
If they are missing, add them and make sure that any user of
htobe/betoh uses include/babeltrace/endian.h and not system endian.h

Signed-off-by: Jesper Derehag <jderehag <at> hotmail.com>
Tested-by: Jesper Derehag <jderehag <at> hotmail.com>
---
 formats/lttng-live/lttng-live-comm.c |  1 +
 include/babeltrace/endian.h          | 91 +++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/formats/lttng-live/lttng-live-comm.c b/formats/lttng-live/lttng-live-comm.c
index 9feb718..3aad981 100644
--- a/formats/lttng-live/lttng-live-comm.c
+++ b/formats/lttng-live/lttng-live-comm.c
 <at>  <at>  -50,6 +50,7  <at>  <at> 
 #include <babeltrace/ctf/events-internal.h>
 #include <formats/ctf/events-private.h>

+#include <babeltrace/endian.h>
 #include <babeltrace/compat/memstream.h>

 #include "lttng-live.h"
diff --git a/include/babeltrace/endian.h b/include/babeltrace/endian.h
index f15a44f..e39e599 100644
--- a/include/babeltrace/endian.h
+++ b/include/babeltrace/endian.h
 <at>  <at>  -47,7 +47,96  <at>  <at> 
(Continue reading)

Yao Qi | 18 Apr 12:07 2014

Access metadata via libbabeltrace

Hi,
I have a metadata like this:

event {
        name = "register";
        id = 0;
        fields := struct {
                ascii contents[440];
        };
};

and I can get the length of the array if I have an event,

	  const struct bt_definition *scope
	    = bt_ctf_get_top_level_scope (event,
					  BT_EVENT_FIELDS);
	  const struct bt_definition *array
	    = bt_ctf_get_field (event, scope, "contents");

	  block_size
	    = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));

block_size is what I want.  However, how can I get the array length
without an event?  I looked into babeltrace source for a while, but
don't see any API on metadata.

--

-- 
Yao (齐尧)

_______________________________________________
(Continue reading)

Mathieu Desnoyers | 16 Apr 22:56 2014

[PATCH lttng-modules] Statedump event for block devices

From: Houssem Daoud <houssemmh <at> gmail.com>

[ Edited by Mathieu Desnoyers. ]
Signed-off-by: Houssem Daoud <houssemmh <at> gmail.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers <at> efficios.com>
---
 README                                             |    2 +
 .../events/lttng-module/lttng-statedump.h          |   16 +++
 lttng-statedump-impl.c                             |   46 ++++++++
 wrapper/genhd.h                                    |  113 ++++++++++++++++++++
 4 files changed, 177 insertions(+)
 create mode 100644 wrapper/genhd.h

diff --git a/README b/README
index 9aa5b93..119bfa8 100644
--- a/README
+++ b/README
 <at>  <at>  -83,6 +83,8  <at>  <at>  CONFIG_KPROBES:
 CONFIG_KRETPROBES:
             Dynamic function entry/return probe.
                lttng enable-event -k --function ...
+CONFIG_KALLSYMS_ALL:
+            State dump of mapping between block device number and name.

 
 * Note about Perf PMU counters support
diff --git a/instrumentation/events/lttng-module/lttng-statedump.h b/instrumentation/events/lttng-module/lttng-statedump.h
index e4c86d6..efd22d7 100644
--- a/instrumentation/events/lttng-module/lttng-statedump.h
+++ b/instrumentation/events/lttng-module/lttng-statedump.h
(Continue reading)

Jessica Foest | 16 Apr 22:31 2014
Picon

babeltrace

Hi all

i know that the default output format of babeltrace is text .
what are the others output format supported by babeltrace ?

in my case , i need to convert the CTF log file of lttng to a CSV file , did tou have any idea about how can i do it ?

thanks
_______________________________________________
lttng-dev mailing list
lttng-dev <at> lists.lttng.org
http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
Christian Babeux | 16 Apr 18:26 2014

[PATCH] Clarify limitations of the --syscall flag with enable-event command

Signed-off-by: Christian Babeux <christian.babeux <at> efficios.com>
---
 doc/man/lttng.1 | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/doc/man/lttng.1 b/doc/man/lttng.1
index 972f71c..9882083 100644
--- a/doc/man/lttng.1
+++ b/doc/man/lttng.1
 <at>  <at>  -541,7 +541,9  <at>  <at>  Dynamic function entry/return probe. Addr and offset can be octal
 .BR "\-\-syscall"
 System call event. Enabling syscalls tracing (kernel tracer), you will
 not be able to disable them with disable-event. This is a known
-limitation. You can disable the entire channel to do the trick.
+limitation. You can disable the entire channel to do the trick. Also note
+that per-syscall selection is not supported yet. Use with "-a" to enable
+all syscalls.
 .TP
 .BR "\-\-filter 'expression'"
 Set a filter on a newly enabled event. Filter expression on event
--

-- 
1.9.2
Sébastien Barthélémy | 16 Apr 18:22 2014

memory usage depending on number and size of subbuffers

Hi all,

LTTng uses more memory than I expected. On the simple experiment below one can see that the "cached" memory increases by

subbuf_size*num_cpu*(num_subbuf+1)

That's not a big deal, but I did not expect the "+1".

Does somebody know where it comes from?


-- Regards, Sebastien


12M == 2M*2*(2+1)
24M == 4M*2*(2+1)
20M == 2M*2*(4+1)
40M == 4M*2*(4+1)

# grep processor /proc/cpuinfo
processor       : 0
processor       : 1

# lttng create
Session auto-20140416-180246 created.
Traces will be written in /root/lttng-traces/auto-20140416-180246

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        670        332          0         22        250
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng enable-channel channel0 --num-subbuf 2 --subbuf-size 2M -u
UST channel channel0 enabled for session auto-20140416-180246

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        682        320          0         22        262
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng destroy
Session auto-20140416-180246 destroyed

# lttng create
Session auto-20140416-180317 created.
Traces will be written in /root/lttng-traces/auto-20140416-180317

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        670        332          0         22        250
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng enable-channel channel0 --num-subbuf 2 --subbuf-size 4M -u
UST channel channel0 enabled for session auto-20140416-180317

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        694        307          0         22        274
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng destroy
Session auto-20140416-180317 destroyed

# lttng create
Session auto-20140416-180339 created.
Traces will be written in /root/lttng-traces/auto-20140416-180339

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        670        332          0         22        250
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng enable-channel channel0 --num-subbuf 4 --subbuf-size 2M -u
UST channel channel0 enabled for session auto-20140416-180339

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        690        311          0         22        270
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng destroy
Session auto-20140416-180339 destroyed

# lttng create
Session auto-20140416-180406 created.
Traces will be written in /root/lttng-traces/auto-20140416-180406

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        670        332          0         22        250
-/+ buffers/cache:        397        605
Swap:            0          0          0

# lttng enable-channel channel0 --num-subbuf 4 --subbuf-size 4M -u
UST channel channel0 enabled for session auto-20140416-180406

# free -m
             total       used       free     shared    buffers     cached
Mem:          1002        710        292          0         22        290
-/+ buffers/cache:        397        605

_______________________________________________
lttng-dev mailing list
lttng-dev <at> lists.lttng.org
http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
Houssem Daoud | 15 Apr 18:06 2014
Picon

[Patch][Lttng Modules] Statedump event for block devices

Signed-off-by: Houssem Daoud <houssemmh <at> gmail.com>
---
 .../events/lttng-module/lttng-statedump.h          | 15 ++++++
 lttng-statedump-impl.c                             | 60 ++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/instrumentation/events/lttng-module/lttng-statedump.h b/instrumentation/events/lttng-module/lttng-statedump.h
index e4c86d6..07afdd0 100644
--- a/instrumentation/events/lttng-module/lttng-statedump.h
+++ b/instrumentation/events/lttng-module/lttng-statedump.h
 <at>  <at>  -141,6 +141,21  <at>  <at>  TRACE_EVENT(lttng_statedump_network_interface,
 	TP_printk("")
 )

+TRACE_EVENT(lttng_statedump_block_device,
+	TP_PROTO(struct lttng_session *session,
+		int dev, const char *diskname),
+	TP_ARGS(session, dev, diskname),
+	TP_STRUCT__entry(
+		__field(int, dev)
+		__string(diskname, diskname)
+	),
+	TP_fast_assign(
+		tp_assign(dev, dev)
+		tp_strcpy(diskname, diskname)
+	),
+	TP_printk("")
+)
+
 /* Called with desc->lock held */
 TRACE_EVENT(lttng_statedump_interrupt,
 	TP_PROTO(struct lttng_session *session,
diff --git a/lttng-statedump-impl.c b/lttng-statedump-impl.c
index 40eab8e..fd0063e 100644
--- a/lttng-statedump-impl.c
+++ b/lttng-statedump-impl.c
 <at>  <at>  -26,6 +26,10  <at>  <at> 
  *	                                Various updates
  */

+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/genhd.h>
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/netlink.h>
 <at>  <at>  -54,6 +58,7  <at>  <at> 
 #include "wrapper/nsproxy.h"
 #include "wrapper/irq.h"
 #include "wrapper/tracepoint.h"
+#include "wrapper/kallsyms.h"

 #ifdef CONFIG_LTTNG_HAS_LIST_IRQ
 #include <linux/irq.h>
 <at>  <at>  -108,7 +113,61  <at>  <at>  enum lttng_process_status {
 	LTTNG_DEAD = 7,
 };

+
+char *disk_name(struct gendisk *hd, int partno, char *buf)
+{
+	if (!partno)
+		snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
+	else if (isdigit(hd->disk_name[strlen(hd->disk_name) - 1]))
+		snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
+	else
+		snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
+
+	return buf;
+}
+
+static
+int lttng_enumerate_block_devices(struct lttng_session *session) {
+	struct class *ptr_block_class;
+	struct device_type *ptr_disk_type;
+	struct class_dev_iter iter;
+	struct device *dev;
+	struct gendisk *disk;
+	struct disk_part_iter piter;
+	struct hd_struct *part;
+	char name_buf[BDEVNAME_SIZE];
+	int device_devt;
+
+	ptr_block_class = (struct class *) kallsyms_lookup_dataptr("block_class");
+	if (!ptr_block_class){
+		printk( KERN_WARNING "Lttng: block_class symbol lookup failed.\n");
+		return 0;
+	}
+
+	ptr_disk_type = (struct device_type*) kallsyms_lookup_dataptr("disk_type");
+	if (!ptr_disk_type){
+		printk( KERN_WARNING "Lttng: disk_type symbol lookup failed.\n");
+		return 0;
+	}
+
+	class_dev_iter_init(&iter, ptr_block_class, NULL, ptr_disk_type);
+	while ((dev = class_dev_iter_next(&iter))) {
+		disk = dev_to_disk(dev);
+		disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+		while ((part = disk_part_iter_next(&piter))) {
+			disk_name(disk, part->partno, name_buf);
+			device_devt = (int) part_devt(part);
+			trace_lttng_statedump_block_device(session, device_devt, name_buf);
+		}
+		disk_part_iter_exit(&piter);
+	}
+	class_dev_iter_exit(&iter);
+
+	return 0;
+}
+
 #ifdef CONFIG_INET
+
 static
 void lttng_enumerate_device(struct lttng_session *session,
 		struct net_device *dev)
 <at>  <at>  -390,6 +449,7  <at>  <at>  int do_lttng_statedump(struct lttng_session *session)
 	/* FIXME lttng_enumerate_vm_maps(session); */
 	lttng_list_interrupts(session);
 	lttng_enumerate_network_ip_interface(session);
+	lttng_enumerate_block_devices(session);

 	/* TODO lttng_dump_idt_table(session); */
 	/* TODO lttng_dump_softirq_vec(session); */
--

-- 
1.8.3.2
Picon

Need help on LTTNG

Hello,

 

I am trying to use LTTNG on centos (2.6.32). I have applied the given patch and rebuilt a kernel.

Still I am unable to build the lltng-modules.

 

[root <at> million lttng-modules-2.4.0]# uname -r

2.6.32-431.5.1.el6.hpsp.centos.LTTNG.18852.x86_64

 

Below is the compiler error I am getting,

 

[root <at> million lttng-modules-2.4.0]# make

make -C /lib/modules/2.6.32-431.5.1.el6.hpsp.centos.LTTNG.18852.x86_64/build M=/root/LTTNG/lttng-modules-2.4.0 modules

make[1]: Entering directory `/usr/src/kernels/2.6.32-431.5.1.el6.hpsp.centos.LTTNG.18852.x86_64'

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-client-discard.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-client-overwrite.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-metadata-client.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-client-mmap-discard.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-client-mmap-overwrite.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-ring-buffer-metadata-mmap-client.o

  CC [M]  /root/LTTNG/lttng-modules-2.4.0/lttng-statedump-impl.o

In file included from /root/LTTNG/lttng-modules-2.4.0/lttng-statedump-impl.c:55:

/root/LTTNG/lttng-modules-2.4.0/wrapper/tracepoint.h: In function âwrapper_lttng_fixup_sigâ:

/root/LTTNG/lttng-modules-2.4.0/wrapper/tracepoint.h:76: error: âstruct moduleâ has no member named âsig_okâ

make[2]: *** [/root/LTTNG/lttng-modules-2.4.0/lttng-statedump-impl.o] Error 1

make[1]: *** [_module_/root/LTTNG/lttng-modules-2.4.0] Error 2

make[1]: Leaving directory `/usr/src/kernels/2.6.32-431.5.1.el6.hpsp.centos.LTTNG.18852.x86_64'

make: *** [default] Error 2

[root <at> million lttng-modules-2.4.0]#

 

Patches provided In lttng-modules/linux-patches/

backport-kallsym-sym-2.6.32.patch               ß got easily applied with patch command

backport-splice-sym-2.6.32-34.patch             ß got easily applied with patch command

backport-tracepoint-data-2.6.32-33.patch     ß  Conflicts were found, and I manually edited tracepoint.h file.

 

Kernel was built by disabling “CONFIG_MODULE_SIG”.  

 

Could you please kindly guide me on this issue. Appreciate your help very much.

Please do let me know, if I need to provide any more info on this.

 

 

Thanks and regards,

Shilpa Kumari.P.V

 

_______________________________________________
lttng-dev mailing list
lttng-dev <at> lists.lttng.org
http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
Jérémie Galarneau | 15 Apr 16:32 2014

[PATCH lttng-tools] Better error reporting when a snapshot record size is too small

Print an error message when a snapshot record is made with a
max size smaller than the subbuffers. This limitation is now
documented in the man page.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau <at> efficios.com>
---
 doc/man/lttng.1                   |  4 ++-
 src/bin/lttng/commands/snapshot.c | 59 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/doc/man/lttng.1 b/doc/man/lttng.1
index 972f71c..bf1b67e 100644
--- a/doc/man/lttng.1
+++ b/doc/man/lttng.1
 <at>  <at>  -787,7 +787,9  <at>  <at>  List the output of a session. Attributes of the output are printed.
 Snapshot a session's buffer(s) for all domains. If an URL is specified, it is
 used instead of a previously added output. Specifying only a name or/and a max
 size will override the current output values. For instance, you can record a
-snapshot with a custom maximum size or with a different name.
+snapshot with a custom maximum size or with a different name. However, the
+max size must be high enough to contain a complete subbuffer. See the
+--subbuf-size switch for default subbuffer sizes.

 .nf
 $ lttng snapshot add-output -n mysnapshot file:///data/snapshot
diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c
index c704eee..7fda949 100644
--- a/src/bin/lttng/commands/snapshot.c
+++ b/src/bin/lttng/commands/snapshot.c
 <at>  <at>  -125,6 +125,56  <at>  <at>  static int count_arguments(const char **argv)
 	return i;
 }

+static uint64_t get_largest_subbuf()
+{
+	int domain_count;
+	int channel_count;
+	int domain_idx;
+	int channel_idx;
+	struct lttng_domain *domains;
+	uint64_t largest_subbuf = 0;
+
+	domain_count = lttng_list_domains(current_session_name, &domains);
+	if (domain_count < 0) {
+		ERR("Unable to list session %s's domains",
+			current_session_name);
+		goto end;
+	}
+
+	for (domain_idx = 0; domain_idx < domain_count; domain_idx++) {
+		struct lttng_channel *channels;
+		struct lttng_handle *handle = lttng_create_handle(
+			current_session_name, &domains[domain_idx]);
+
+		if (!handle) {
+			ERR("Unable to create handle for session %s",
+				current_session_name);
+			goto end;
+		}
+
+		channel_count = lttng_list_channels(handle, &channels);
+		if (channel_count < 0) {
+			ERR("Unable to list channels for session %s",
+				current_session_name);
+			goto end;
+		}
+
+		for (channel_idx = 0; channel_idx < channel_count;
+			channel_idx++) {
+			if (channels[channel_idx].attr.subbuf_size >
+				largest_subbuf) {
+				largest_subbuf =
+					channels[channel_idx].attr.subbuf_size;
+			}
+		}
+		free(channels);
+		lttng_destroy_handle(handle);
+	}
+end:
+	free(domains);
+	return largest_subbuf;
+}
+
 /*
  * Create a snapshot output object from arguments using the given URL.
  *
 <at>  <at>  -160,6 +210,15  <at>  <at>  static struct lttng_snapshot_output *create_output_from_args(const char *url)
 	}

 	if (opt_max_size) {
+		/* Validate that the max size can contain one subbuffer. */
+		uint64_t largest_subbuf = get_largest_subbuf();
+		if (largest_subbuf == 0) {
+			goto error;
+		} else if (largest_subbuf > opt_max_size) {
+			ERR("Snapshot size must be greater or equal to the largest subbuffer's size (%zu).",
+				largest_subbuf);
+			goto error;
+		}
 		ret = lttng_snapshot_output_set_size(opt_max_size, output);
 		if (ret < 0) {
 			goto error;
--

-- 
1.9.1

_______________________________________________
lttng-dev mailing list
lttng-dev <at> lists.lttng.org
http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
Mathieu Desnoyers | 14 Apr 21:25 2014

[PATCH lttng-modules] Fix: allow racy tracepoint string input from kernel and userspace

Fixes #781

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers <at> efficios.com>
---
 lib/ringbuffer/backend.h             |  215 ++++++++++++++++++++++++++++++++++
 lib/ringbuffer/backend_internal.h    |    6 +
 lib/ringbuffer/ring_buffer_backend.c |  166 ++++++++++++++++++++++++++
 lttng-events.h                       |    4 +
 lttng-ring-buffer-client.h           |   17 +++
 lttng-ring-buffer-metadata-client.h  |    8 ++
 probes/lttng-events.h                |   28 ++---
 7 files changed, 429 insertions(+), 15 deletions(-)

diff --git a/lib/ringbuffer/backend.h b/lib/ringbuffer/backend.h
index bbbc80d..7246ec4 100644
--- a/lib/ringbuffer/backend.h
+++ b/lib/ringbuffer/backend.h
 <at>  <at>  -165,6 +165,128  <at>  <at>  void lib_ring_buffer_memset(const struct lib_ring_buffer_config *config,
 	ctx->buf_offset += len;
 }

+/*
+ * Copy up to  <at> len string bytes from  <at> src to  <at> dest. Stop whenever a NULL
+ * terminating character is found in  <at> src. Returns the number of bytes
+ * copied. Does *not* terminate  <at> dest with NULL terminating character.
+ */
+static inline
+size_t lib_ring_buffer_do_strcpy(const struct lib_ring_buffer_config *config,
+		char *dest, const char *src, size_t len)
+{
+	size_t count;
+
+	for (count = 0; count < len; count++) {
+		char c;
+
+		/*
+		 * Only read source character once, in case it is
+		 * modified concurrently.
+		 */
+		c = ACCESS_ONCE(src[count]);
+		if (!c)
+			break;
+		lib_ring_buffer_do_copy(config, &dest[count], &c, 1);
+	}
+	return count;
+}
+
+/*
+ * Copy up to  <at> len string bytes from  <at> src to  <at> dest. Stop whenever a NULL
+ * terminating character is found in  <at> src, or when a fault occurs.
+ * Returns the number of bytes copied. Does *not* terminate  <at> dest with
+ * NULL terminating character.
+ *
+ * This function deals with userspace pointers, it should never be called
+ * directly without having the src pointer checked with access_ok()
+ * previously.
+ */
+static inline
+size_t lib_ring_buffer_do_strcpy_from_user_inatomic(const struct lib_ring_buffer_config *config,
+		char *dest, const char __user *src, size_t len)
+{
+	size_t count;
+
+	for (count = 0; count < len; count++) {
+		int ret;
+		char c;
+
+		ret = __get_user(c, &src[count]);
+		if (ret || !c)
+			break;
+		lib_ring_buffer_do_copy(config, &dest[count], &c, 1);
+	}
+	return count;
+}
+
+/**
+ * lib_ring_buffer_strcpy - write string data to a buffer backend
+ *  <at> config : ring buffer instance configuration
+ *  <at> ctx: ring buffer context. (input arguments only)
+ *  <at> src : source pointer to copy from
+ *  <at> len : length of data to copy
+ *  <at> pad : character to use for padding
+ *
+ * This function copies  <at> len - 1 bytes of string data from a source
+ * pointer to a buffer backend, followed by a terminating '\0'
+ * character, at the current context offset. This is more or less a
+ * buffer backend-specific strncpy() operation. If a terminating '\0'
+ * character is found in  <at> src before  <at> len - 1 characters are copied, pad
+ * the buffer with  <at> pad characters (e.g. '#'). Calls the slow path
+ * (_ring_buffer_strcpy) if copy is crossing a page boundary.
+ */
+static inline
+void lib_ring_buffer_strcpy(const struct lib_ring_buffer_config *config,
+			   struct lib_ring_buffer_ctx *ctx,
+			   const char *src, size_t len, int pad)
+{
+	struct lib_ring_buffer_backend *bufb = &ctx->buf->backend;
+	struct channel_backend *chanb = &ctx->chan->backend;
+	size_t sbidx, index;
+	size_t offset = ctx->buf_offset;
+	ssize_t pagecpy;
+	struct lib_ring_buffer_backend_pages *rpages;
+	unsigned long sb_bindex, id;
+
+	if (unlikely(!len))
+		return;
+	offset &= chanb->buf_size - 1;
+	sbidx = offset >> chanb->subbuf_size_order;
+	index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT;
+	pagecpy = min_t(size_t, len, (-offset) & ~PAGE_MASK);
+	id = bufb->buf_wsb[sbidx].id;
+	sb_bindex = subbuffer_id_get_index(config, id);
+	rpages = bufb->array[sb_bindex];
+	CHAN_WARN_ON(ctx->chan,
+		     config->mode == RING_BUFFER_OVERWRITE
+		     && subbuffer_id_is_noref(config, id));
+	if (likely(pagecpy == len)) {
+		size_t count;
+
+		count = lib_ring_buffer_do_strcpy(config,
+					rpages->p[index].virt
+					    + (offset & ~PAGE_MASK),
+					src, len - 1);
+		offset += count;
+		/* Padding */
+		if (unlikely(count < len - 1)) {
+			size_t pad_len = len - 1 - count;
+
+			lib_ring_buffer_do_memset(rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					pad, pad_len);
+			offset += pad_len;
+		}
+		/* Ending '\0' */
+		lib_ring_buffer_do_memset(rpages->p[index].virt
+					+ (offset & ~PAGE_MASK),
+				'\0', 1);
+	} else {
+		_lib_ring_buffer_strcpy(bufb, offset, src, len, 0, pad);
+	}
+	ctx->buf_offset += len;
+}
+
 /**
  * lib_ring_buffer_copy_from_user_inatomic - write userspace data to a buffer backend
  *  <at> config : ring buffer instance configuration
 <at>  <at>  -239,6 +361,99  <at>  <at>  fill_buffer:
 	_lib_ring_buffer_memset(bufb, offset, 0, len, 0);
 }

+/**
+ * lib_ring_buffer_strcpy_from_user_inatomic - write userspace string data to a buffer backend
+ *  <at> config : ring buffer instance configuration
+ *  <at> ctx: ring buffer context (input arguments only)
+ *  <at> src : userspace source pointer to copy from
+ *  <at> len : length of data to copy
+ *  <at> pad : character to use for padding
+ *
+ * This function copies  <at> len - 1 bytes of string data from a userspace
+ * source pointer to a buffer backend, followed by a terminating '\0'
+ * character, at the current context offset. This is more or less a
+ * buffer backend-specific strncpy() operation. If a terminating '\0'
+ * character is found in  <at> src before  <at> len - 1 characters are copied, pad
+ * the buffer with  <at> pad characters (e.g. '#'). Calls the slow path
+ * (_ring_buffer_strcpy_from_user_inatomic) if copy is crossing a page
+ * boundary. Disable the page fault handler to ensure we never try to
+ * take the mmap_sem.
+ */
+static inline
+void lib_ring_buffer_strcpy_from_user_inatomic(const struct lib_ring_buffer_config *config,
+		struct lib_ring_buffer_ctx *ctx,
+		const void __user *src, size_t len, int pad)
+{
+	struct lib_ring_buffer_backend *bufb = &ctx->buf->backend;
+	struct channel_backend *chanb = &ctx->chan->backend;
+	size_t sbidx, index;
+	size_t offset = ctx->buf_offset;
+	ssize_t pagecpy;
+	struct lib_ring_buffer_backend_pages *rpages;
+	unsigned long sb_bindex, id;
+	mm_segment_t old_fs = get_fs();
+
+	if (unlikely(!len))
+		return;
+	offset &= chanb->buf_size - 1;
+	sbidx = offset >> chanb->subbuf_size_order;
+	index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT;
+	pagecpy = min_t(size_t, len, (-offset) & ~PAGE_MASK);
+	id = bufb->buf_wsb[sbidx].id;
+	sb_bindex = subbuffer_id_get_index(config, id);
+	rpages = bufb->array[sb_bindex];
+	CHAN_WARN_ON(ctx->chan,
+		     config->mode == RING_BUFFER_OVERWRITE
+		     && subbuffer_id_is_noref(config, id));
+
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+	if (unlikely(!access_ok(VERIFY_READ, src, len)))
+		goto fill_buffer;
+
+	if (likely(pagecpy == len)) {
+		size_t count;
+
+		count = lib_ring_buffer_do_strcpy_from_user_inatomic(config,
+					rpages->p[index].virt
+					    + (offset & ~PAGE_MASK),
+					src, len - 1);
+		offset += count;
+		/* Padding */
+		if (unlikely(count < len - 1)) {
+			size_t pad_len = len - 1 - count;
+
+			lib_ring_buffer_do_memset(rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					pad, pad_len);
+			offset += pad_len;
+		}
+		/* Ending '\0' */
+		lib_ring_buffer_do_memset(rpages->p[index].virt
+					+ (offset & ~PAGE_MASK),
+				'\0', 1);
+	} else {
+		_lib_ring_buffer_strcpy_from_user_inatomic(bufb, offset, src,
+					len, 0, pad);
+	}
+	pagefault_enable();
+	set_fs(old_fs);
+	ctx->buf_offset += len;
+
+	return;
+
+fill_buffer:
+	pagefault_enable();
+	set_fs(old_fs);
+	/*
+	 * In the error path we call the slow path version to avoid
+	 * the pollution of static inline code.
+	 */
+	_lib_ring_buffer_memset(bufb, offset, pad, len - 1, 0);
+	offset += len - 1;
+	_lib_ring_buffer_memset(bufb, offset, '\0', 1, 0);
+}
+
 /*
  * This accessor counts the number of unread records in a buffer.
  * It only provides a consistent value if no reads not writes are performed
diff --git a/lib/ringbuffer/backend_internal.h b/lib/ringbuffer/backend_internal.h
index 9682c5b..e4df3b9 100644
--- a/lib/ringbuffer/backend_internal.h
+++ b/lib/ringbuffer/backend_internal.h
 <at>  <at>  -56,9 +56,15  <at>  <at>  extern void _lib_ring_buffer_write(struct lib_ring_buffer_backend *bufb,
 extern void _lib_ring_buffer_memset(struct lib_ring_buffer_backend *bufb,
 				    size_t offset, int c, size_t len,
 				    ssize_t pagecpy);
+extern void _lib_ring_buffer_strcpy(struct lib_ring_buffer_backend *bufb,
+				   size_t offset, const char *src, size_t len,
+				   ssize_t pagecpy, int pad);
 extern void _lib_ring_buffer_copy_from_user_inatomic(struct lib_ring_buffer_backend *bufb,
 					    size_t offset, const void *src,
 					    size_t len, ssize_t pagecpy);
+extern void _lib_ring_buffer_strcpy_from_user_inatomic(struct lib_ring_buffer_backend *bufb,
+		size_t offset, const char __user *src, size_t len,
+		ssize_t pagecpy, int pad);

 /*
  * Subbuffer ID bits for overwrite mode. Need to fit within a single word to be
diff --git a/lib/ringbuffer/ring_buffer_backend.c b/lib/ringbuffer/ring_buffer_backend.c
index 32accf3..550fad3 100644
--- a/lib/ringbuffer/ring_buffer_backend.c
+++ b/lib/ringbuffer/ring_buffer_backend.c
 <at>  <at>  -557,6 +557,87  <at>  <at>  void _lib_ring_buffer_memset(struct lib_ring_buffer_backend *bufb,
 }
 EXPORT_SYMBOL_GPL(_lib_ring_buffer_memset);

+/**
+ * lib_ring_buffer_strcpy - write string data to a ring_buffer buffer.
+ *  <at> bufb : buffer backend
+ *  <at> offset : offset within the buffer
+ *  <at> src : source address
+ *  <at> len : length to write
+ *  <at> pagecpy : page size copied so far
+ *  <at> pad : character to use for padding
+ */
+void _lib_ring_buffer_strcpy(struct lib_ring_buffer_backend *bufb,
+			size_t offset, const char *src, size_t len,
+			ssize_t pagecpy, int pad)
+{
+	struct channel_backend *chanb = &bufb->chan->backend;
+	const struct lib_ring_buffer_config *config = &chanb->config;
+	size_t sbidx, index;
+	struct lib_ring_buffer_backend_pages *rpages;
+	unsigned long sb_bindex, id;
+	int src_terminated = 0;
+
+	CHAN_WARN_ON(chanb, !len);
+	offset += pagecpy;
+	do {
+		len -= pagecpy;
+		if (!src_terminated)
+			src += pagecpy;
+		sbidx = offset >> chanb->subbuf_size_order;
+		index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT;
+
+		/*
+		 * Underlying layer should never ask for writes across
+		 * subbuffers.
+		 */
+		CHAN_WARN_ON(chanb, offset >= chanb->buf_size);
+
+		pagecpy = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK));
+		id = bufb->buf_wsb[sbidx].id;
+		sb_bindex = subbuffer_id_get_index(config, id);
+		rpages = bufb->array[sb_bindex];
+		CHAN_WARN_ON(chanb, config->mode == RING_BUFFER_OVERWRITE
+			     && subbuffer_id_is_noref(config, id));
+
+		if (likely(!src_terminated)) {
+			size_t count, to_copy;
+
+			to_copy = pagecpy;
+			if (pagecpy == len)
+				to_copy--;	/* Final '\0' */
+			count = lib_ring_buffer_do_strcpy(config,
+					rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					src, to_copy);
+			offset += count;
+			/* Padding */
+			if (unlikely(count < to_copy)) {
+				size_t pad_len = to_copy - count;
+
+				/* Next pages will have padding */
+				src_terminated = 1;
+				lib_ring_buffer_do_memset(rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					pad, pad_len);
+				offset += pad_len;
+			}
+		} else {
+			size_t pad_len;
+
+			pad_len = pagecpy;
+			if (pagecpy == len)
+				pad_len--;	/* Final '\0' */
+			lib_ring_buffer_do_memset(rpages->p[index].virt
+					+ (offset & ~PAGE_MASK),
+				pad, pad_len);
+			offset += pad_len;
+		}
+	} while (unlikely(len != pagecpy));
+	/* Ending '\0' */
+	lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK),
+			'\0', 1);
+}
+EXPORT_SYMBOL_GPL(_lib_ring_buffer_strcpy);

 /**
  * lib_ring_buffer_copy_from_user_inatomic - write user data to a ring_buffer buffer.
 <at>  <at>  -615,6 +696,91  <at>  <at>  void _lib_ring_buffer_copy_from_user_inatomic(struct
lib_ring_buffer_backend *bu
 EXPORT_SYMBOL_GPL(_lib_ring_buffer_copy_from_user_inatomic);

 /**
+ * lib_ring_buffer_strcpy_from_user_inatomic - write userspace string data to a ring_buffer buffer.
+ *  <at> bufb : buffer backend
+ *  <at> offset : offset within the buffer
+ *  <at> src : source address
+ *  <at> len : length to write
+ *  <at> pagecpy : page size copied so far
+ *  <at> pad : character to use for padding
+ *
+ * This function deals with userspace pointers, it should never be called
+ * directly without having the src pointer checked with access_ok()
+ * previously.
+ */
+void _lib_ring_buffer_strcpy_from_user_inatomic(struct lib_ring_buffer_backend *bufb,
+		size_t offset, const char __user *src, size_t len,
+		ssize_t pagecpy, int pad)
+{
+	struct channel_backend *chanb = &bufb->chan->backend;
+	const struct lib_ring_buffer_config *config = &chanb->config;
+	size_t sbidx, index;
+	struct lib_ring_buffer_backend_pages *rpages;
+	unsigned long sb_bindex, id;
+	int src_terminated = 0;
+
+	offset += pagecpy;
+	do {
+		len -= pagecpy;
+		if (!src_terminated)
+			src += pagecpy;
+		sbidx = offset >> chanb->subbuf_size_order;
+		index = (offset & (chanb->subbuf_size - 1)) >> PAGE_SHIFT;
+
+		/*
+		 * Underlying layer should never ask for writes across
+		 * subbuffers.
+		 */
+		CHAN_WARN_ON(chanb, offset >= chanb->buf_size);
+
+		pagecpy = min_t(size_t, len, PAGE_SIZE - (offset & ~PAGE_MASK));
+		id = bufb->buf_wsb[sbidx].id;
+		sb_bindex = subbuffer_id_get_index(config, id);
+		rpages = bufb->array[sb_bindex];
+		CHAN_WARN_ON(chanb, config->mode == RING_BUFFER_OVERWRITE
+				&& subbuffer_id_is_noref(config, id));
+
+		if (likely(!src_terminated)) {
+			size_t count, to_copy;
+
+			to_copy = pagecpy;
+			if (pagecpy == len)
+				to_copy--;	/* Final '\0' */
+			count = lib_ring_buffer_do_strcpy_from_user_inatomic(config,
+					rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					src, to_copy);
+			offset += count;
+			/* Padding */
+			if (unlikely(count < to_copy)) {
+				size_t pad_len = to_copy - count;
+
+				/* Next pages will have padding */
+				src_terminated = 1;
+				lib_ring_buffer_do_memset(rpages->p[index].virt
+						+ (offset & ~PAGE_MASK),
+					pad, pad_len);
+				offset += pad_len;
+			}
+		} else {
+			size_t pad_len;
+
+			pad_len = pagecpy;
+			if (pagecpy == len)
+				pad_len--;	/* Final '\0' */
+			lib_ring_buffer_do_memset(rpages->p[index].virt
+					+ (offset & ~PAGE_MASK),
+				pad, pad_len);
+			offset += pad_len;
+		}
+	} while (unlikely(len != pagecpy));
+	/* Ending '\0' */
+	lib_ring_buffer_do_memset(rpages->p[index].virt + (offset & ~PAGE_MASK),
+			'\0', 1);
+}
+EXPORT_SYMBOL_GPL(_lib_ring_buffer_strcpy_from_user_inatomic);
+
+/**
  * lib_ring_buffer_read - read data from ring_buffer_buffer.
  *  <at> bufb : buffer backend
  *  <at> offset : offset within the buffer
diff --git a/lttng-events.h b/lttng-events.h
index aeb2a6b..e1de1af 100644
--- a/lttng-events.h
+++ b/lttng-events.h
 <at>  <at>  -236,6 +236,10  <at>  <at>  struct lttng_channel_ops {
 				      const void *src, size_t len);
 	void (*event_memset)(struct lib_ring_buffer_ctx *ctx,
 			     int c, size_t len);
+	void (*event_strcpy)(struct lib_ring_buffer_ctx *ctx, const char *src,
+			     size_t len);
+	void (*event_strcpy_from_user)(struct lib_ring_buffer_ctx *ctx,
+				       const char __user *src, size_t len);
 	/*
 	 * packet_avail_size returns the available size in the current
 	 * packet. Note that the size returned is only a hint, since it
diff --git a/lttng-ring-buffer-client.h b/lttng-ring-buffer-client.h
index 288cc32..9872ea4 100644
--- a/lttng-ring-buffer-client.h
+++ b/lttng-ring-buffer-client.h
 <at>  <at>  -629,6 +629,21  <at>  <at>  void lttng_event_memset(struct lib_ring_buffer_ctx *ctx,
 }

 static
+void lttng_event_strcpy(struct lib_ring_buffer_ctx *ctx, const char *src,
+		size_t len)
+{
+	lib_ring_buffer_strcpy(&client_config, ctx, src, len, '#');
+}
+
+static
+void lttng_event_strcpy_from_user(struct lib_ring_buffer_ctx *ctx,
+		const char __user *src, size_t len)
+{
+	lib_ring_buffer_strcpy_from_user_inatomic(&client_config, ctx, src,
+			len, '#');
+}
+
+static
 wait_queue_head_t *lttng_get_writer_buf_wait_queue(struct channel *chan, int cpu)
 {
 	struct lib_ring_buffer *buf = channel_get_ring_buffer(&client_config,
 <at>  <at>  -669,6 +684,8  <at>  <at>  static struct lttng_transport lttng_relay_transport = {
 		.event_write = lttng_event_write,
 		.event_write_from_user = lttng_event_write_from_user,
 		.event_memset = lttng_event_memset,
+		.event_strcpy = lttng_event_strcpy,
+		.event_strcpy_from_user = lttng_event_strcpy_from_user,
 		.packet_avail_size = NULL,	/* Would be racy anyway */
 		.get_writer_buf_wait_queue = lttng_get_writer_buf_wait_queue,
 		.get_hp_wait_queue = lttng_get_hp_wait_queue,
diff --git a/lttng-ring-buffer-metadata-client.h b/lttng-ring-buffer-metadata-client.h
index 5c8a1df..f077f4f 100644
--- a/lttng-ring-buffer-metadata-client.h
+++ b/lttng-ring-buffer-metadata-client.h
 <at>  <at>  -326,6 +326,13  <at>  <at>  void lttng_event_memset(struct lib_ring_buffer_ctx *ctx,
 }

 static
+void lttng_event_strcpy(struct lib_ring_buffer_ctx *ctx, const char *src,
+		size_t len)
+{
+	lib_ring_buffer_strcpy(&client_config, ctx, src, len, '#');
+}
+
+static
 size_t lttng_packet_avail_size(struct channel *chan)
 			     
 {
 <at>  <at>  -383,6 +390,7  <at>  <at>  static struct lttng_transport lttng_relay_transport = {
 		.event_write_from_user = lttng_event_write_from_user,
 		.event_memset = lttng_event_memset,
 		.event_write = lttng_event_write,
+		.event_strcpy = lttng_event_strcpy,
 		.packet_avail_size = lttng_packet_avail_size,
 		.get_writer_buf_wait_queue = lttng_get_writer_buf_wait_queue,
 		.get_hp_wait_queue = lttng_get_hp_wait_queue,
diff --git a/probes/lttng-events.h b/probes/lttng-events.h
index 680f466..ab6f342 100644
--- a/probes/lttng-events.h
+++ b/probes/lttng-events.h
 <at>  <at>  -691,24 +691,22  <at>  <at>  __assign_##dest##_3:							\
  */
 #undef tp_copy_string_from_user
 #define tp_copy_string_from_user(dest, src)				\
-	__assign_##dest:						\
-	{								\
-		size_t __ustrlen;					\
-									\
-		if (0)							\
-			(void) __typemap.dest;				\
-		lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__typemap.dest));\
-		__ustrlen = __get_dynamic_array_len(dest);		\
-		if (likely(__ustrlen > 1)) {				\
-			__chan->ops->event_write_from_user(&__ctx, src,	\
-				__ustrlen - 1);				\
-		}							\
-		__chan->ops->event_memset(&__ctx, 0, 1);		\
-	}								\
+__assign_##dest:							\
+	if (0)								\
+		(void) __typemap.dest;					\
+	lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__typemap.dest)); \
+	__chan->ops->event_strcpy_from_user(&__ctx, src,		\
+		__get_dynamic_array_len(dest));				\
 	goto __end_field_##dest;
+
 #undef tp_strcpy
 #define tp_strcpy(dest, src)						\
-	tp_memcpy(dest, src, __get_dynamic_array_len(dest))
+__assign_##dest:							\
+	if (0)								\
+		(void) __typemap.dest;					\
+	lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__typemap.dest)); \
+	__chan->ops->event_strcpy(&__ctx, src, __get_dynamic_array_len(dest)); \
+	goto __end_field_##dest;

 /* Named field types must be defined in lttng-types.h */

--

-- 
1.7.10.4

Gmane