Blame blktrace.c

Packit c4abd9
/*
Packit c4abd9
 * block queue tracing application
Packit c4abd9
 *
Packit c4abd9
 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
Packit c4abd9
 * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
Packit c4abd9
 *
Packit c4abd9
 * Rewrite to have a single thread per CPU (managing all devices on that CPU)
Packit c4abd9
 *	Alan D. Brunelle <alan.brunelle@hp.com> - January 2009
Packit c4abd9
 *
Packit c4abd9
 *  This program is free software; you can redistribute it and/or modify
Packit c4abd9
 *  it under the terms of the GNU General Public License as published by
Packit c4abd9
 *  the Free Software Foundation; either version 2 of the License, or
Packit c4abd9
 *  (at your option) any later version.
Packit c4abd9
 *
Packit c4abd9
 *  This program is distributed in the hope that it will be useful,
Packit c4abd9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit c4abd9
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit c4abd9
 *  GNU General Public License for more details.
Packit c4abd9
 *
Packit c4abd9
 *  You should have received a copy of the GNU General Public License
Packit c4abd9
 *  along with this program; if not, write to the Free Software
Packit c4abd9
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit c4abd9
 *
Packit c4abd9
 */
Packit c4abd9
Packit c4abd9
#include <errno.h>
Packit c4abd9
#include <stdarg.h>
Packit c4abd9
#include <stdio.h>
Packit c4abd9
#include <stdlib.h>
Packit c4abd9
#include <string.h>
Packit c4abd9
#include <fcntl.h>
Packit c4abd9
#include <getopt.h>
Packit c4abd9
#include <sched.h>
Packit c4abd9
#include <unistd.h>
Packit c4abd9
#include <poll.h>
Packit c4abd9
#include <signal.h>
Packit c4abd9
#include <pthread.h>
Packit c4abd9
#include <locale.h>
Packit c4abd9
#include <sys/ioctl.h>
Packit c4abd9
#include <sys/types.h>
Packit c4abd9
#include <sys/stat.h>
Packit c4abd9
#include <sys/vfs.h>
Packit c4abd9
#include <sys/mman.h>
Packit c4abd9
#include <sys/param.h>
Packit c4abd9
#include <sys/time.h>
Packit c4abd9
#include <sys/resource.h>
Packit c4abd9
#include <sys/socket.h>
Packit c4abd9
#include <netinet/in.h>
Packit c4abd9
#include <arpa/inet.h>
Packit c4abd9
#include <netdb.h>
Packit c4abd9
#include <sys/sendfile.h>
Packit c4abd9
Packit c4abd9
#include "btt/list.h"
Packit c4abd9
#include "blktrace.h"
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * You may want to increase this even more, if you are logging at a high
Packit c4abd9
 * rate and see skipped/missed events
Packit c4abd9
 */
Packit c4abd9
#define BUF_SIZE		(512 * 1024)
Packit c4abd9
#define BUF_NR			(4)
Packit c4abd9
Packit c4abd9
#define FILE_VBUF_SIZE		(128 * 1024)
Packit c4abd9
Packit c4abd9
#define DEBUGFS_TYPE		(0x64626720)
Packit c4abd9
#define TRACE_NET_PORT		(8462)
Packit c4abd9
Packit c4abd9
enum {
Packit c4abd9
	Net_none = 0,
Packit c4abd9
	Net_server,
Packit c4abd9
	Net_client,
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
enum thread_status {
Packit c4abd9
	Th_running,
Packit c4abd9
	Th_leaving,
Packit c4abd9
	Th_error
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Generic stats collected: nevents can be _roughly_ estimated by data_read
Packit c4abd9
 * (discounting pdu...)
Packit c4abd9
 *
Packit c4abd9
 * These fields are updated w/ pdc_dr_update & pdc_nev_update below.
Packit c4abd9
 */
Packit c4abd9
struct pdc_stats {
Packit c4abd9
	unsigned long long data_read;
Packit c4abd9
	unsigned long long nevents;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
struct devpath {
Packit c4abd9
	struct list_head head;
Packit c4abd9
	char *path;			/* path to device special file */
Packit c4abd9
	char *buts_name;		/* name returned from bt kernel code */
Packit c4abd9
	struct pdc_stats *stats;
Packit c4abd9
	int fd, ncpus;
Packit c4abd9
	unsigned long long drops;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * For piped output only:
Packit c4abd9
	 *
Packit c4abd9
	 * Each tracer will have a tracer_devpath_head that it will add new
Packit c4abd9
	 * data onto. It's list is protected above (tracer_devpath_head.mutex)
Packit c4abd9
	 * and it will signal the processing thread using the dp_cond,
Packit c4abd9
	 * dp_mutex & dp_entries variables above.
Packit c4abd9
	 */
Packit c4abd9
	struct tracer_devpath_head *heads;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * For network server mode only:
Packit c4abd9
	 */
Packit c4abd9
	struct cl_host *ch;
Packit c4abd9
	u32 cl_id;
Packit c4abd9
	time_t cl_connect_time;
Packit c4abd9
	struct io_info *ios;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * For piped output to stdout we will have each tracer thread (one per dev)
Packit c4abd9
 * tack buffers read from the relay queues on a per-device list.
Packit c4abd9
 *
Packit c4abd9
 * The main thread will then collect trace buffers from each of lists in turn.
Packit c4abd9
 *
Packit c4abd9
 * We will use a mutex to guard each of the trace_buf list. The tracers
Packit c4abd9
 * can then signal the main thread using <dp_cond,dp_mutex> and
Packit c4abd9
 * dp_entries. (When dp_entries is 0, and a tracer adds an entry it will
Packit c4abd9
 * signal. When dp_entries is 0, the main thread will wait for that condition
Packit c4abd9
 * to be signalled.)
Packit c4abd9
 *
Packit c4abd9
 * adb: It may be better just to have a large buffer per tracer per dev,
Packit c4abd9
 * and then use it as a ring-buffer. This would certainly cut down a lot
Packit c4abd9
 * of malloc/free thrashing, at the cost of more memory movements (potentially).
Packit c4abd9
 */
Packit c4abd9
struct trace_buf {
Packit c4abd9
	struct list_head head;
Packit c4abd9
	struct devpath *dpp;
Packit c4abd9
	void *buf;
Packit c4abd9
	int cpu, len;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
struct tracer_devpath_head {
Packit c4abd9
	pthread_mutex_t mutex;
Packit c4abd9
	struct list_head head;
Packit c4abd9
	struct trace_buf *prev;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Used to handle the mmap() interfaces for output file (containing traces)
Packit c4abd9
 */
Packit c4abd9
struct mmap_info {
Packit c4abd9
	void *fs_buf;
Packit c4abd9
	unsigned long long fs_size, fs_max_size, fs_off, fs_buf_len;
Packit c4abd9
	unsigned long buf_size, buf_nr;
Packit c4abd9
	int pagesize;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Each thread doing work on a (client) side of blktrace will have one
Packit c4abd9
 * of these. The ios array contains input/output information, pfds holds
Packit c4abd9
 * poll() data. The volatile's provide flags to/from the main executing
Packit c4abd9
 * thread.
Packit c4abd9
 */
Packit c4abd9
struct tracer {
Packit c4abd9
	struct list_head head;
Packit c4abd9
	struct io_info *ios;
Packit c4abd9
	struct pollfd *pfds;
Packit c4abd9
	pthread_t thread;
Packit c4abd9
	int cpu, nios;
Packit c4abd9
	volatile int status, is_done;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * networking stuff follows. we include a magic number so we know whether
Packit c4abd9
 * to endianness convert or not.
Packit c4abd9
 *
Packit c4abd9
 * The len field is overloaded:
Packit c4abd9
 *	0 - Indicates an "open" - allowing the server to set up for a dev/cpu
Packit c4abd9
 *	1 - Indicates a "close" - Shut down connection orderly
Packit c4abd9
 *
Packit c4abd9
 * The cpu field is overloaded on close: it will contain the number of drops.
Packit c4abd9
 */
Packit c4abd9
struct blktrace_net_hdr {
Packit c4abd9
	u32 magic;		/* same as trace magic */
Packit c4abd9
	char buts_name[32];	/* trace name */
Packit c4abd9
	u32 cpu;		/* for which cpu */
Packit c4abd9
	u32 max_cpus;
Packit c4abd9
	u32 len;		/* length of following trace data */
Packit c4abd9
	u32 cl_id;		/* id for set of client per-cpu connections */
Packit c4abd9
	u32 buf_size;		/* client buf_size for this trace  */
Packit c4abd9
	u32 buf_nr;		/* client buf_nr for this trace  */
Packit c4abd9
	u32 page_size;		/* client page_size for this trace  */
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Each host encountered has one of these. The head is used to link this
Packit c4abd9
 * on to the network server's ch_list. Connections associated with this
Packit c4abd9
 * host are linked on conn_list, and any devices traced on that host
Packit c4abd9
 * are connected on the devpaths list.
Packit c4abd9
 */
Packit c4abd9
struct cl_host {
Packit c4abd9
	struct list_head head;
Packit c4abd9
	struct list_head conn_list;
Packit c4abd9
	struct list_head devpaths;
Packit c4abd9
	struct net_server_s *ns;
Packit c4abd9
	char *hostname;
Packit c4abd9
	struct in_addr cl_in_addr;
Packit c4abd9
	int connects, ndevs, cl_opens;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Each connection (client to server socket ('fd')) has one of these. A
Packit c4abd9
 * back reference to the host ('ch'), and lists headers (for the host
Packit c4abd9
 * list, and the network server conn_list) are also included.
Packit c4abd9
 */
Packit c4abd9
struct cl_conn {
Packit c4abd9
	struct list_head ch_head, ns_head;
Packit c4abd9
	struct cl_host *ch;
Packit c4abd9
	int fd, ncpus;
Packit c4abd9
	time_t connect_time;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * The network server requires some poll structures to be maintained -
Packit c4abd9
 * one per conection currently on conn_list. The nchs/ch_list values
Packit c4abd9
 * are for each host connected to this server. The addr field is used
Packit c4abd9
 * for scratch as new connections are established.
Packit c4abd9
 */
Packit c4abd9
struct net_server_s {
Packit c4abd9
	struct list_head conn_list;
Packit c4abd9
	struct list_head ch_list;
Packit c4abd9
	struct pollfd *pfds;
Packit c4abd9
	int listen_fd, connects, nchs;
Packit c4abd9
	struct sockaddr_in addr;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * This structure is (generically) used to providide information
Packit c4abd9
 * for a read-to-write set of values.
Packit c4abd9
 *
Packit c4abd9
 * ifn & ifd represent input information
Packit c4abd9
 *
Packit c4abd9
 * ofn, ofd, ofp, obuf & mmap_info are used for output file (optionally).
Packit c4abd9
 */
Packit c4abd9
struct io_info {
Packit c4abd9
	struct devpath *dpp;
Packit c4abd9
	FILE *ofp;
Packit c4abd9
	char *obuf;
Packit c4abd9
	struct cl_conn *nc;	/* Server network connection */
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * mmap controlled output files
Packit c4abd9
	 */
Packit c4abd9
	struct mmap_info mmap_info;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Client network fields
Packit c4abd9
	 */
Packit c4abd9
	unsigned int ready;
Packit c4abd9
	unsigned long long data_queued;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Input/output file descriptors & names
Packit c4abd9
	 */
Packit c4abd9
	int ifd, ofd;
Packit c4abd9
	char ifn[MAXPATHLEN + 64];
Packit c4abd9
	char ofn[MAXPATHLEN + 64];
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
static char blktrace_version[] = "2.0.0";
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Linkage to blktrace helper routines (trace conversions)
Packit c4abd9
 */
Packit c4abd9
int data_is_native = -1;
Packit c4abd9
Packit c4abd9
static int ndevs;
Packit c4abd9
static int max_cpus;
Packit c4abd9
static int ncpus;
Packit c4abd9
static cpu_set_t *online_cpus;
Packit c4abd9
static int pagesize;
Packit c4abd9
static int act_mask = ~0U;
Packit c4abd9
static int kill_running_trace;
Packit c4abd9
static int stop_watch;
Packit c4abd9
static int piped_output;
Packit c4abd9
Packit c4abd9
static char *debugfs_path = "/sys/kernel/debug";
Packit c4abd9
static char *output_name;
Packit c4abd9
static char *output_dir;
Packit c4abd9
Packit c4abd9
static unsigned long buf_size = BUF_SIZE;
Packit c4abd9
static unsigned long buf_nr = BUF_NR;
Packit c4abd9
Packit c4abd9
static FILE *pfp;
Packit c4abd9
Packit c4abd9
static LIST_HEAD(devpaths);
Packit c4abd9
static LIST_HEAD(tracers);
Packit c4abd9
Packit c4abd9
static volatile int done;
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * tracer threads add entries, the main thread takes them off and processes
Packit c4abd9
 * them. These protect the dp_entries variable.
Packit c4abd9
 */
Packit c4abd9
static pthread_cond_t dp_cond = PTHREAD_COND_INITIALIZER;
Packit c4abd9
static pthread_mutex_t dp_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit c4abd9
static volatile int dp_entries;
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * These synchronize master / thread interactions.
Packit c4abd9
 */
Packit c4abd9
static pthread_cond_t mt_cond = PTHREAD_COND_INITIALIZER;
Packit c4abd9
static pthread_mutex_t mt_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit c4abd9
static volatile int nthreads_running;
Packit c4abd9
static volatile int nthreads_leaving;
Packit c4abd9
static volatile int nthreads_error;
Packit c4abd9
static volatile int tracers_run;
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * network cmd line params
Packit c4abd9
 */
Packit c4abd9
static struct sockaddr_in hostname_addr;
Packit c4abd9
static char hostname[MAXHOSTNAMELEN];
Packit c4abd9
static int net_port = TRACE_NET_PORT;
Packit c4abd9
static int net_use_sendfile = 1;
Packit c4abd9
static int net_mode;
Packit c4abd9
static int *cl_fds;
Packit c4abd9
Packit c4abd9
static int (*handle_pfds)(struct tracer *, int, int);
Packit c4abd9
static int (*handle_list)(struct tracer_devpath_head *, struct list_head *);
Packit c4abd9
Packit c4abd9
#define S_OPTS	"d:a:A:r:o:kw:vVb:n:D:lh:p:sI:"
Packit c4abd9
static struct option l_opts[] = {
Packit c4abd9
	{
Packit c4abd9
		.name = "dev",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'd'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "input-devs",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'I'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "act-mask",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'a'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "set-mask",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'A'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "relay",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'r'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "output",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'o'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "kill",
Packit c4abd9
		.has_arg = no_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'k'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "stopwatch",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'w'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "version",
Packit c4abd9
		.has_arg = no_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'v'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "version",
Packit c4abd9
		.has_arg = no_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'V'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "buffer-size",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'b'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "num-sub-buffers",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'n'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "output-dir",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'D'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "listen",
Packit c4abd9
		.has_arg = no_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'l'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "host",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'h'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "port",
Packit c4abd9
		.has_arg = required_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 'p'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = "no-sendfile",
Packit c4abd9
		.has_arg = no_argument,
Packit c4abd9
		.flag = NULL,
Packit c4abd9
		.val = 's'
Packit c4abd9
	},
Packit c4abd9
	{
Packit c4abd9
		.name = NULL,
Packit c4abd9
	}
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
static char usage_str[] = "\n\n" \
Packit c4abd9
	"-d <dev>             | --dev=<dev>\n" \
Packit c4abd9
        "[ -r <debugfs path>  | --relay=<debugfs path> ]\n" \
Packit c4abd9
        "[ -o <file>          | --output=<file>]\n" \
Packit c4abd9
        "[ -D <dir>           | --output-dir=<dir>\n" \
Packit c4abd9
        "[ -w <time>          | --stopwatch=<time>]\n" \
Packit c4abd9
        "[ -a <action field>  | --act-mask=<action field>]\n" \
Packit c4abd9
        "[ -A <action mask>   | --set-mask=<action mask>]\n" \
Packit c4abd9
        "[ -b <size>          | --buffer-size]\n" \
Packit c4abd9
        "[ -n <number>        | --num-sub-buffers=<number>]\n" \
Packit c4abd9
        "[ -l                 | --listen]\n" \
Packit c4abd9
        "[ -h <hostname>      | --host=<hostname>]\n" \
Packit c4abd9
        "[ -p <port number>   | --port=<port number>]\n" \
Packit c4abd9
        "[ -s                 | --no-sendfile]\n" \
Packit c4abd9
        "[ -I <devs file>     | --input-devs=<devs file>]\n" \
Packit c4abd9
        "[ -v <version>       | --version]\n" \
Packit c4abd9
        "[ -V <version>       | --version]\n" \
Packit c4abd9
Packit c4abd9
	"\t-d Use specified device. May also be given last after options\n" \
Packit c4abd9
	"\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
Packit c4abd9
	"\t-o File(s) to send output to\n" \
Packit c4abd9
	"\t-D Directory to prepend to output file names\n" \
Packit c4abd9
	"\t-w Stop after defined time, in seconds\n" \
Packit c4abd9
	"\t-a Only trace specified actions. See documentation\n" \
Packit c4abd9
	"\t-A Give trace mask as a single value. See documentation\n" \
Packit c4abd9
	"\t-b Sub buffer size in KiB (default 512)\n" \
Packit c4abd9
	"\t-n Number of sub buffers (default 4)\n" \
Packit c4abd9
	"\t-l Run in network listen mode (blktrace server)\n" \
Packit c4abd9
	"\t-h Run in network client mode, connecting to the given host\n" \
Packit c4abd9
	"\t-p Network port to use (default 8462)\n" \
Packit c4abd9
	"\t-s Make the network client NOT use sendfile() to transfer data\n" \
Packit c4abd9
	"\t-I Add devices found in <devs file>\n" \
Packit c4abd9
	"\t-v Print program version info\n" \
Packit c4abd9
	"\t-V Print program version info\n\n";
Packit c4abd9
Packit c4abd9
static void clear_events(struct pollfd *pfd)
Packit c4abd9
{
Packit c4abd9
	pfd->events = 0;
Packit c4abd9
	pfd->revents = 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline int net_client_use_sendfile(void)
Packit c4abd9
{
Packit c4abd9
	return net_mode == Net_client && net_use_sendfile;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline int net_client_use_send(void)
Packit c4abd9
{
Packit c4abd9
	return net_mode == Net_client && !net_use_sendfile;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline int use_tracer_devpaths(void)
Packit c4abd9
{
Packit c4abd9
	return piped_output || net_client_use_send();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline int in_addr_eq(struct in_addr a, struct in_addr b)
Packit c4abd9
{
Packit c4abd9
	return a.s_addr == b.s_addr;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline void pdc_dr_update(struct devpath *dpp, int cpu, int data_read)
Packit c4abd9
{
Packit c4abd9
	dpp->stats[cpu].data_read += data_read;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline void pdc_nev_update(struct devpath *dpp, int cpu, int nevents)
Packit c4abd9
{
Packit c4abd9
	dpp->stats[cpu].nevents += nevents;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void show_usage(char *prog)
Packit c4abd9
{
Packit c4abd9
	fprintf(stderr, "Usage: %s %s", prog, usage_str);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Create a timespec 'msec' milliseconds into the future
Packit c4abd9
 */
Packit c4abd9
static inline void make_timespec(struct timespec *tsp, long delta_msec)
Packit c4abd9
{
Packit c4abd9
	struct timeval now;
Packit c4abd9
Packit c4abd9
	gettimeofday(&now, NULL);
Packit c4abd9
	tsp->tv_sec = now.tv_sec;
Packit c4abd9
	tsp->tv_nsec = 1000L * now.tv_usec;
Packit c4abd9
Packit c4abd9
	tsp->tv_nsec += (delta_msec * 1000000L);
Packit c4abd9
	if (tsp->tv_nsec > 1000000000L) {
Packit c4abd9
		long secs = tsp->tv_nsec / 1000000000L;
Packit c4abd9
Packit c4abd9
		tsp->tv_sec += secs;
Packit c4abd9
		tsp->tv_nsec -= (secs * 1000000000L);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Add a timer to ensure wait ends
Packit c4abd9
 */
Packit c4abd9
static void t_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Packit c4abd9
{
Packit c4abd9
	struct timespec ts;
Packit c4abd9
Packit c4abd9
	make_timespec(&ts, 50);
Packit c4abd9
	pthread_cond_timedwait(cond, mutex, &ts);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void unblock_tracers(void)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&mt_mutex);
Packit c4abd9
	tracers_run = 1;
Packit c4abd9
	pthread_cond_broadcast(&mt_cond);
Packit c4abd9
	pthread_mutex_unlock(&mt_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void tracer_wait_unblock(struct tracer *tp)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&mt_mutex);
Packit c4abd9
	while (!tp->is_done && !tracers_run)
Packit c4abd9
		pthread_cond_wait(&mt_cond, &mt_mutex);
Packit c4abd9
	pthread_mutex_unlock(&mt_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void tracer_signal_ready(struct tracer *tp,
Packit c4abd9
				enum thread_status th_status,
Packit c4abd9
				int status)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&mt_mutex);
Packit c4abd9
	tp->status = status;
Packit c4abd9
Packit c4abd9
	if (th_status == Th_running)
Packit c4abd9
		nthreads_running++;
Packit c4abd9
	else if (th_status == Th_error)
Packit c4abd9
		nthreads_error++;
Packit c4abd9
	else
Packit c4abd9
		nthreads_leaving++;
Packit c4abd9
Packit c4abd9
	pthread_cond_signal(&mt_cond);
Packit c4abd9
	pthread_mutex_unlock(&mt_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void wait_tracers_ready(int ncpus_started)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&mt_mutex);
Packit c4abd9
	while ((nthreads_running + nthreads_error) < ncpus_started)
Packit c4abd9
		t_pthread_cond_wait(&mt_cond, &mt_mutex);
Packit c4abd9
	pthread_mutex_unlock(&mt_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void wait_tracers_leaving(void)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&mt_mutex);
Packit c4abd9
	while (nthreads_leaving < nthreads_running)
Packit c4abd9
		t_pthread_cond_wait(&mt_cond, &mt_mutex);
Packit c4abd9
	pthread_mutex_unlock(&mt_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void init_mmap_info(struct mmap_info *mip)
Packit c4abd9
{
Packit c4abd9
	mip->buf_size = buf_size;
Packit c4abd9
	mip->buf_nr = buf_nr;
Packit c4abd9
	mip->pagesize = pagesize;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_close_connection(int *fd)
Packit c4abd9
{
Packit c4abd9
	shutdown(*fd, SHUT_RDWR);
Packit c4abd9
	close(*fd);
Packit c4abd9
	*fd = -1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void dpp_free(struct devpath *dpp)
Packit c4abd9
{
Packit c4abd9
	if (dpp->stats)
Packit c4abd9
		free(dpp->stats);
Packit c4abd9
	if (dpp->ios)
Packit c4abd9
		free(dpp->ios);
Packit c4abd9
	if (dpp->path)
Packit c4abd9
		free(dpp->path);
Packit c4abd9
	if (dpp->buts_name)
Packit c4abd9
		free(dpp->buts_name);
Packit c4abd9
	free(dpp);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int lock_on_cpu(int cpu)
Packit c4abd9
{
Packit c4abd9
	cpu_set_t * cpu_mask;
Packit c4abd9
	size_t size;
Packit c4abd9
Packit c4abd9
	cpu_mask = CPU_ALLOC(max_cpus);
Packit c4abd9
	size = CPU_ALLOC_SIZE(max_cpus);
Packit c4abd9
Packit c4abd9
	CPU_ZERO_S(size, cpu_mask);
Packit c4abd9
	CPU_SET_S(cpu, size, cpu_mask);
Packit c4abd9
	if (sched_setaffinity(0, size, cpu_mask) < 0) {
Packit c4abd9
		CPU_FREE(cpu_mask);		
Packit c4abd9
		return errno;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	CPU_FREE(cpu_mask);		
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int increase_limit(int resource, rlim_t increase)
Packit c4abd9
{
Packit c4abd9
	struct rlimit rlim;
Packit c4abd9
	int save_errno = errno;
Packit c4abd9
Packit c4abd9
	if (!getrlimit(resource, &rlim)) {
Packit c4abd9
		rlim.rlim_cur += increase;
Packit c4abd9
		if (rlim.rlim_cur >= rlim.rlim_max)
Packit c4abd9
			rlim.rlim_max = rlim.rlim_cur + increase;
Packit c4abd9
Packit c4abd9
		if (!setrlimit(resource, &rlim))
Packit c4abd9
			return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	errno = save_errno;
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_open_failure(void)
Packit c4abd9
{
Packit c4abd9
	if (errno == ENFILE || errno == EMFILE)
Packit c4abd9
		return increase_limit(RLIMIT_NOFILE, 16);
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_mem_failure(size_t length)
Packit c4abd9
{
Packit c4abd9
	if (errno == ENFILE)
Packit c4abd9
		return handle_open_failure();
Packit c4abd9
	else if (errno == ENOMEM)
Packit c4abd9
		return increase_limit(RLIMIT_MEMLOCK, 2 * length);
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static FILE *my_fopen(const char *path, const char *mode)
Packit c4abd9
{
Packit c4abd9
	FILE *fp;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		fp = fopen(path, mode);
Packit c4abd9
	} while (fp == NULL && handle_open_failure());
Packit c4abd9
Packit c4abd9
	return fp;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int my_open(const char *path, int flags)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		fd = open(path, flags);
Packit c4abd9
	} while (fd < 0 && handle_open_failure());
Packit c4abd9
Packit c4abd9
	return fd;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int my_socket(int domain, int type, int protocol)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		fd = socket(domain, type, protocol);
Packit c4abd9
	} while (fd < 0 && handle_open_failure());
Packit c4abd9
Packit c4abd9
	return fd;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int my_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		fd = accept(sockfd, addr, addrlen);
Packit c4abd9
	} while (fd < 0 && handle_open_failure());
Packit c4abd9
Packit c4abd9
	return fd;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void *my_mmap(void *addr, size_t length, int prot, int flags, int fd,
Packit c4abd9
		     off_t offset)
Packit c4abd9
{
Packit c4abd9
	void *new;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		new = mmap(addr, length, prot, flags, fd, offset);
Packit c4abd9
	} while (new == MAP_FAILED && handle_mem_failure(length));
Packit c4abd9
Packit c4abd9
	return new;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int my_mlock(struct tracer *tp,
Packit c4abd9
		    const void *addr, size_t len)
Packit c4abd9
{
Packit c4abd9
	int ret, retry = 0;
Packit c4abd9
Packit c4abd9
	do {
Packit c4abd9
		ret = mlock(addr, len);
Packit c4abd9
		if ((retry >= 10) && tp && tp->is_done)
Packit c4abd9
			break;
Packit c4abd9
		retry++;
Packit c4abd9
	} while (ret < 0 && handle_mem_failure(len));
Packit c4abd9
Packit c4abd9
	return ret;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int setup_mmap(int fd, unsigned int maxlen,
Packit c4abd9
		      struct mmap_info *mip,
Packit c4abd9
		      struct tracer *tp)
Packit c4abd9
{
Packit c4abd9
	if (mip->fs_off + maxlen > mip->fs_buf_len) {
Packit c4abd9
		unsigned long nr = max(16, mip->buf_nr);
Packit c4abd9
Packit c4abd9
		if (mip->fs_buf) {
Packit c4abd9
			munlock(mip->fs_buf, mip->fs_buf_len);
Packit c4abd9
			munmap(mip->fs_buf, mip->fs_buf_len);
Packit c4abd9
			mip->fs_buf = NULL;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		mip->fs_off = mip->fs_size & (mip->pagesize - 1);
Packit c4abd9
		mip->fs_buf_len = (nr * mip->buf_size) - mip->fs_off;
Packit c4abd9
		mip->fs_max_size += mip->fs_buf_len;
Packit c4abd9
Packit c4abd9
		if (ftruncate(fd, mip->fs_max_size) < 0) {
Packit c4abd9
			perror("setup_mmap: ftruncate");
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		mip->fs_buf = my_mmap(NULL, mip->fs_buf_len, PROT_WRITE,
Packit c4abd9
				      MAP_SHARED, fd,
Packit c4abd9
				      mip->fs_size - mip->fs_off);
Packit c4abd9
		if (mip->fs_buf == MAP_FAILED) {
Packit c4abd9
			perror("setup_mmap: mmap");
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
		if (my_mlock(tp, mip->fs_buf, mip->fs_buf_len) < 0) {
Packit c4abd9
			perror("setup_mlock: mlock");
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int __stop_trace(int fd)
Packit c4abd9
{
Packit c4abd9
	/*
Packit c4abd9
	 * Should be stopped, don't complain if it isn't
Packit c4abd9
	 */
Packit c4abd9
	ioctl(fd, BLKTRACESTOP);
Packit c4abd9
	return ioctl(fd, BLKTRACETEARDOWN);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int write_data(char *buf, int len)
Packit c4abd9
{
Packit c4abd9
	int ret;
Packit c4abd9
Packit c4abd9
rewrite:
Packit c4abd9
	ret = fwrite(buf, len, 1, pfp);
Packit c4abd9
	if (ferror(pfp) || ret != 1) {
Packit c4abd9
		if (errno == EINTR) {
Packit c4abd9
			clearerr(pfp);
Packit c4abd9
			goto rewrite;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		if (!piped_output || (errno != EPIPE && errno != EBADF)) {
Packit c4abd9
			fprintf(stderr, "write(%d) failed: %d/%s\n",
Packit c4abd9
				len, errno, strerror(errno));
Packit c4abd9
		}
Packit c4abd9
		goto err;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	fflush(pfp);
Packit c4abd9
	return 0;
Packit c4abd9
Packit c4abd9
err:
Packit c4abd9
	clearerr(pfp);
Packit c4abd9
	return 1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Returns the number of bytes read (successfully)
Packit c4abd9
 */
Packit c4abd9
static int __net_recv_data(int fd, void *buf, unsigned int len)
Packit c4abd9
{
Packit c4abd9
	unsigned int bytes_left = len;
Packit c4abd9
Packit c4abd9
	while (bytes_left && !done) {
Packit c4abd9
		int ret = recv(fd, buf, bytes_left, MSG_WAITALL);
Packit c4abd9
Packit c4abd9
		if (ret == 0)
Packit c4abd9
			break;
Packit c4abd9
		else if (ret < 0) {
Packit c4abd9
			if (errno == EAGAIN) {
Packit c4abd9
				usleep(50);
Packit c4abd9
				continue;
Packit c4abd9
			}
Packit c4abd9
			perror("server: net_recv_data: recv failed");
Packit c4abd9
			break;
Packit c4abd9
		} else {
Packit c4abd9
			buf += ret;
Packit c4abd9
			bytes_left -= ret;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return len - bytes_left;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_recv_data(int fd, void *buf, unsigned int len)
Packit c4abd9
{
Packit c4abd9
	return __net_recv_data(fd, buf, len);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Returns number of bytes written
Packit c4abd9
 */
Packit c4abd9
static int net_send_data(int fd, void *buf, unsigned int buf_len)
Packit c4abd9
{
Packit c4abd9
	int ret;
Packit c4abd9
	unsigned int bytes_left = buf_len;
Packit c4abd9
Packit c4abd9
	while (bytes_left) {
Packit c4abd9
		ret = send(fd, buf, bytes_left, 0);
Packit c4abd9
		if (ret < 0) {
Packit c4abd9
			perror("send");
Packit c4abd9
			break;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		buf += ret;
Packit c4abd9
		bytes_left -= ret;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return buf_len - bytes_left;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_send_header(int fd, int cpu, char *buts_name, int len)
Packit c4abd9
{
Packit c4abd9
	struct blktrace_net_hdr hdr;
Packit c4abd9
Packit c4abd9
	memset(&hdr, 0, sizeof(hdr));
Packit c4abd9
Packit c4abd9
	hdr.magic = BLK_IO_TRACE_MAGIC;
Packit c4abd9
	memset(hdr.buts_name, 0, sizeof(hdr.buts_name));
Packit c4abd9
	strncpy(hdr.buts_name, buts_name, sizeof(hdr.buts_name));
Packit c4abd9
	hdr.buts_name[sizeof(hdr.buts_name) - 1] = '\0';
Packit c4abd9
	hdr.cpu = cpu;
Packit c4abd9
	hdr.max_cpus = max_cpus;
Packit c4abd9
	hdr.len = len;
Packit c4abd9
	hdr.cl_id = getpid();
Packit c4abd9
	hdr.buf_size = buf_size;
Packit c4abd9
	hdr.buf_nr = buf_nr;
Packit c4abd9
	hdr.page_size = pagesize;
Packit c4abd9
Packit c4abd9
	return net_send_data(fd, &hdr, sizeof(hdr)) != sizeof(hdr);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_send_open_close(int fd, int cpu, char *buts_name, int len)
Packit c4abd9
{
Packit c4abd9
	struct blktrace_net_hdr ret_hdr;
Packit c4abd9
Packit c4abd9
	net_send_header(fd, cpu, buts_name, len);
Packit c4abd9
	net_recv_data(fd, &ret_hdr, sizeof(ret_hdr));
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_send_open(int fd, int cpu, char *buts_name)
Packit c4abd9
{
Packit c4abd9
	net_send_open_close(fd, cpu, buts_name, 0);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_send_close(int fd, char *buts_name, int drops)
Packit c4abd9
{
Packit c4abd9
	/*
Packit c4abd9
	 * Overload CPU w/ number of drops
Packit c4abd9
	 *
Packit c4abd9
	 * XXX: Need to clear/set done around call - done=1 (which
Packit c4abd9
	 * is true here) stops reads from happening... :-(
Packit c4abd9
	 */
Packit c4abd9
	done = 0;
Packit c4abd9
	net_send_open_close(fd, drops, buts_name, 1);
Packit c4abd9
	done = 1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void ack_open_close(int fd, char *buts_name)
Packit c4abd9
{
Packit c4abd9
	net_send_header(fd, 0, buts_name, 2);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_send_drops(int fd)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		net_send_close(fd, dpp->buts_name, dpp->drops);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Returns:
Packit c4abd9
 *	 0: "EOF"
Packit c4abd9
 *	 1: OK
Packit c4abd9
 *	-1: Error
Packit c4abd9
 */
Packit c4abd9
static int net_get_header(struct cl_conn *nc, struct blktrace_net_hdr *bnh)
Packit c4abd9
{
Packit c4abd9
	int bytes_read;
Packit c4abd9
	int fl = fcntl(nc->fd, F_GETFL);
Packit c4abd9
Packit c4abd9
	fcntl(nc->fd, F_SETFL, fl | O_NONBLOCK);
Packit c4abd9
	bytes_read = __net_recv_data(nc->fd, bnh, sizeof(*bnh));
Packit c4abd9
	fcntl(nc->fd, F_SETFL, fl & ~O_NONBLOCK);
Packit c4abd9
Packit c4abd9
	if (bytes_read == sizeof(*bnh))
Packit c4abd9
		return 1;
Packit c4abd9
	else if (bytes_read == 0)
Packit c4abd9
		return 0;
Packit c4abd9
	else
Packit c4abd9
		return -1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_setup_addr(void)
Packit c4abd9
{
Packit c4abd9
	struct sockaddr_in *addr = &hostname_addr;
Packit c4abd9
Packit c4abd9
	memset(addr, 0, sizeof(*addr));
Packit c4abd9
	addr->sin_family = AF_INET;
Packit c4abd9
	addr->sin_port = htons(net_port);
Packit c4abd9
Packit c4abd9
	if (inet_aton(hostname, &addr->sin_addr) != 1) {
Packit c4abd9
		struct hostent *hent;
Packit c4abd9
retry:
Packit c4abd9
		hent = gethostbyname(hostname);
Packit c4abd9
		if (!hent) {
Packit c4abd9
			if (h_errno == TRY_AGAIN) {
Packit c4abd9
				usleep(100);
Packit c4abd9
				goto retry;
Packit c4abd9
			} else if (h_errno == NO_RECOVERY) {
Packit c4abd9
				fprintf(stderr, "gethostbyname(%s)"
Packit c4abd9
					"non-recoverable error encountered\n",
Packit c4abd9
					hostname);
Packit c4abd9
			} else {
Packit c4abd9
				/*
Packit c4abd9
				 * HOST_NOT_FOUND, NO_ADDRESS or NO_DATA
Packit c4abd9
				 */
Packit c4abd9
				fprintf(stderr, "Host %s not found\n",
Packit c4abd9
					hostname);
Packit c4abd9
			}
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		memcpy(&addr->sin_addr, hent->h_addr, 4);
Packit c4abd9
		memset(hostname, 0, sizeof(hostname));
Packit c4abd9
		strncpy(hostname, hent->h_name, sizeof(hostname));
Packit c4abd9
		hostname[sizeof(hostname) - 1] = '\0';
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_setup_client(void)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
	struct sockaddr_in *addr = &hostname_addr;
Packit c4abd9
Packit c4abd9
	fd = my_socket(AF_INET, SOCK_STREAM, 0);
Packit c4abd9
	if (fd < 0) {
Packit c4abd9
		perror("client: socket");
Packit c4abd9
		return -1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (connect(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
Packit c4abd9
		if (errno == ECONNREFUSED)
Packit c4abd9
			fprintf(stderr,
Packit c4abd9
				"\nclient: Connection to %s refused, "
Packit c4abd9
				"perhaps the server is not started?\n\n",
Packit c4abd9
				hostname);
Packit c4abd9
		else
Packit c4abd9
			perror("client: connect");
Packit c4abd9
Packit c4abd9
		close(fd);
Packit c4abd9
		return -1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return fd;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int open_client_connections(void)
Packit c4abd9
{
Packit c4abd9
	int cpu;
Packit c4abd9
	size_t alloc_size = CPU_ALLOC_SIZE(max_cpus);
Packit c4abd9
Packit c4abd9
	cl_fds = calloc(ncpus, sizeof(*cl_fds));
Packit c4abd9
	for (cpu = 0; cpu < max_cpus; cpu++) {
Packit c4abd9
		if (!CPU_ISSET_S(cpu, alloc_size, online_cpus))
Packit c4abd9
			continue;
Packit c4abd9
		cl_fds[cpu] = net_setup_client();
Packit c4abd9
		if (cl_fds[cpu] < 0)
Packit c4abd9
			goto err;
Packit c4abd9
	}
Packit c4abd9
	return 0;
Packit c4abd9
Packit c4abd9
err:
Packit c4abd9
	while (cpu > 0)
Packit c4abd9
		close(cl_fds[cpu--]);
Packit c4abd9
	free(cl_fds);
Packit c4abd9
	return 1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void close_client_connections(void)
Packit c4abd9
{
Packit c4abd9
	if (cl_fds) {
Packit c4abd9
		int cpu, *fdp;
Packit c4abd9
		size_t alloc_size = CPU_ALLOC_SIZE(max_cpus);
Packit c4abd9
Packit c4abd9
		for (cpu = 0, fdp = cl_fds; cpu < max_cpus; cpu++, fdp++) {
Packit c4abd9
			if (!CPU_ISSET_S(cpu, alloc_size, online_cpus))
Packit c4abd9
				continue;
Packit c4abd9
			if (*fdp >= 0) {
Packit c4abd9
				net_send_drops(*fdp);
Packit c4abd9
				net_close_connection(fdp);
Packit c4abd9
			}
Packit c4abd9
		}
Packit c4abd9
		free(cl_fds);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int setup_buts(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	int ret = 0;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct blk_user_trace_setup buts;
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		memset(&buts, 0, sizeof(buts));
Packit c4abd9
		buts.buf_size = buf_size;
Packit c4abd9
		buts.buf_nr = buf_nr;
Packit c4abd9
		buts.act_mask = act_mask;
Packit c4abd9
Packit c4abd9
		if (ioctl(dpp->fd, BLKTRACESETUP, &buts) >= 0) {
Packit c4abd9
			dpp->ncpus = max_cpus;
Packit c4abd9
			dpp->buts_name = strdup(buts.name);
Packit c4abd9
			if (dpp->stats)
Packit c4abd9
				free(dpp->stats);
Packit c4abd9
			dpp->stats = calloc(dpp->ncpus, sizeof(*dpp->stats));
Packit c4abd9
			memset(dpp->stats, 0, dpp->ncpus * sizeof(*dpp->stats));
Packit c4abd9
		} else {
Packit c4abd9
			fprintf(stderr, "BLKTRACESETUP(2) %s failed: %d/%s\n",
Packit c4abd9
				dpp->path, errno, strerror(errno));
Packit c4abd9
			ret++;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return ret;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void start_buts(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		if (ioctl(dpp->fd, BLKTRACESTART) < 0) {
Packit c4abd9
			fprintf(stderr, "BLKTRACESTART %s failed: %d/%s\n",
Packit c4abd9
				dpp->path, errno, strerror(errno));
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int get_drops(struct devpath *dpp)
Packit c4abd9
{
Packit c4abd9
	int fd, drops = 0;
Packit c4abd9
	char fn[MAXPATHLEN + 64], tmp[256];
Packit c4abd9
Packit c4abd9
	snprintf(fn, sizeof(fn), "%s/block/%s/dropped", debugfs_path,
Packit c4abd9
		 dpp->buts_name);
Packit c4abd9
Packit c4abd9
	fd = my_open(fn, O_RDONLY);
Packit c4abd9
	if (fd < 0) {
Packit c4abd9
		/*
Packit c4abd9
		 * This may be ok: the kernel may not support
Packit c4abd9
		 * dropped counts.
Packit c4abd9
		 */
Packit c4abd9
		if (errno != ENOENT)
Packit c4abd9
			fprintf(stderr, "Could not open %s: %d/%s\n",
Packit c4abd9
				fn, errno, strerror(errno));
Packit c4abd9
		return 0;
Packit c4abd9
	} else if (read(fd, tmp, sizeof(tmp)) < 0) {
Packit c4abd9
		fprintf(stderr, "Could not read %s: %d/%s\n",
Packit c4abd9
			fn, errno, strerror(errno));
Packit c4abd9
	} else
Packit c4abd9
		drops = atoi(tmp);
Packit c4abd9
	close(fd);
Packit c4abd9
Packit c4abd9
	return drops;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void get_all_drops(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		dpp->drops = get_drops(dpp);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline struct trace_buf *alloc_trace_buf(int cpu, int bufsize)
Packit c4abd9
{
Packit c4abd9
	struct trace_buf *tbp;
Packit c4abd9
Packit c4abd9
	tbp = malloc(sizeof(*tbp) + bufsize);
Packit c4abd9
	INIT_LIST_HEAD(&tbp->head);
Packit c4abd9
	tbp->len = 0;
Packit c4abd9
	tbp->buf = (void *)(tbp + 1);
Packit c4abd9
	tbp->cpu = cpu;
Packit c4abd9
	tbp->dpp = NULL;	/* Will be set when tbp is added */
Packit c4abd9
Packit c4abd9
	return tbp;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void free_tracer_heads(struct devpath *dpp)
Packit c4abd9
{
Packit c4abd9
	int cpu;
Packit c4abd9
	struct tracer_devpath_head *hd;
Packit c4abd9
Packit c4abd9
	for (cpu = 0, hd = dpp->heads; cpu < max_cpus; cpu++, hd++) {
Packit c4abd9
		if (hd->prev)
Packit c4abd9
			free(hd->prev);
Packit c4abd9
Packit c4abd9
		pthread_mutex_destroy(&hd->mutex);
Packit c4abd9
	}
Packit c4abd9
	free(dpp->heads);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int setup_tracer_devpaths(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	if (net_client_use_send())
Packit c4abd9
		if (open_client_connections())
Packit c4abd9
			return 1;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		int cpu;
Packit c4abd9
		struct tracer_devpath_head *hd;
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		dpp->heads = calloc(max_cpus, sizeof(struct tracer_devpath_head));
Packit c4abd9
		for (cpu = 0, hd = dpp->heads; cpu < max_cpus; cpu++, hd++) {
Packit c4abd9
			INIT_LIST_HEAD(&hd->head);
Packit c4abd9
			pthread_mutex_init(&hd->mutex, NULL);
Packit c4abd9
			hd->prev = NULL;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline void add_trace_buf(struct devpath *dpp, int cpu,
Packit c4abd9
						struct trace_buf **tbpp)
Packit c4abd9
{
Packit c4abd9
	struct trace_buf *tbp = *tbpp;
Packit c4abd9
	struct tracer_devpath_head *hd = &dpp->heads[cpu];
Packit c4abd9
Packit c4abd9
	tbp->dpp = dpp;
Packit c4abd9
Packit c4abd9
	pthread_mutex_lock(&hd->mutex);
Packit c4abd9
	list_add_tail(&tbp->head, &hd->head);
Packit c4abd9
	pthread_mutex_unlock(&hd->mutex);
Packit c4abd9
Packit c4abd9
	*tbpp = alloc_trace_buf(cpu, buf_size);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline void incr_entries(int entries_handled)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&dp_mutex);
Packit c4abd9
	if (dp_entries == 0)
Packit c4abd9
		pthread_cond_signal(&dp_cond);
Packit c4abd9
	dp_entries += entries_handled;
Packit c4abd9
	pthread_mutex_unlock(&dp_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void decr_entries(int handled)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&dp_mutex);
Packit c4abd9
	dp_entries -= handled;
Packit c4abd9
	pthread_mutex_unlock(&dp_mutex);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int wait_empty_entries(void)
Packit c4abd9
{
Packit c4abd9
	pthread_mutex_lock(&dp_mutex);
Packit c4abd9
	while (!done && dp_entries == 0)
Packit c4abd9
		t_pthread_cond_wait(&dp_cond, &dp_mutex);
Packit c4abd9
	pthread_mutex_unlock(&dp_mutex);
Packit c4abd9
Packit c4abd9
	return !done;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int add_devpath(char *path)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
	struct devpath *dpp;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Verify device is not duplicated
Packit c4abd9
	 */
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
	       struct devpath *tmp = list_entry(p, struct devpath, head);
Packit c4abd9
	       if (!strcmp(tmp->path, path))
Packit c4abd9
		        return 0;
Packit c4abd9
	}
Packit c4abd9
	/*
Packit c4abd9
	 * Verify device is valid before going too far
Packit c4abd9
	 */
Packit c4abd9
	fd = my_open(path, O_RDONLY | O_NONBLOCK);
Packit c4abd9
	if (fd < 0) {
Packit c4abd9
		fprintf(stderr, "Invalid path %s specified: %d/%s\n",
Packit c4abd9
			path, errno, strerror(errno));
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	dpp = malloc(sizeof(*dpp));
Packit c4abd9
	memset(dpp, 0, sizeof(*dpp));
Packit c4abd9
	dpp->path = strdup(path);
Packit c4abd9
	dpp->fd = fd;
Packit c4abd9
	ndevs++;
Packit c4abd9
	list_add_tail(&dpp->head, &devpaths);
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void rel_devpaths(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
Packit c4abd9
	list_for_each_safe(p, q, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		list_del(&dpp->head);
Packit c4abd9
		__stop_trace(dpp->fd);
Packit c4abd9
		close(dpp->fd);
Packit c4abd9
Packit c4abd9
		if (dpp->heads)
Packit c4abd9
			free_tracer_heads(dpp);
Packit c4abd9
Packit c4abd9
		dpp_free(dpp);
Packit c4abd9
		ndevs--;
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int flush_subbuf_net(struct trace_buf *tbp)
Packit c4abd9
{
Packit c4abd9
	int fd = cl_fds[tbp->cpu];
Packit c4abd9
	struct devpath *dpp = tbp->dpp;
Packit c4abd9
Packit c4abd9
	if (net_send_header(fd, tbp->cpu, dpp->buts_name, tbp->len))
Packit c4abd9
		return 1;
Packit c4abd9
	else if (net_send_data(fd, tbp->buf, tbp->len) != tbp->len)
Packit c4abd9
		return 1;
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int
Packit c4abd9
handle_list_net(__attribute__((__unused__))struct tracer_devpath_head *hd,
Packit c4abd9
		struct list_head *list)
Packit c4abd9
{
Packit c4abd9
	struct trace_buf *tbp;
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
	int entries_handled = 0;
Packit c4abd9
Packit c4abd9
	list_for_each_safe(p, q, list) {
Packit c4abd9
		tbp = list_entry(p, struct trace_buf, head);
Packit c4abd9
Packit c4abd9
		list_del(&tbp->head);
Packit c4abd9
		entries_handled++;
Packit c4abd9
Packit c4abd9
		if (cl_fds[tbp->cpu] >= 0) {
Packit c4abd9
			if (flush_subbuf_net(tbp)) {
Packit c4abd9
				close(cl_fds[tbp->cpu]);
Packit c4abd9
				cl_fds[tbp->cpu] = -1;
Packit c4abd9
			}
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		free(tbp);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return entries_handled;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Tack 'tbp's buf onto the tail of 'prev's buf
Packit c4abd9
 */
Packit c4abd9
static struct trace_buf *tb_combine(struct trace_buf *prev,
Packit c4abd9
				    struct trace_buf *tbp)
Packit c4abd9
{
Packit c4abd9
	unsigned long tot_len;
Packit c4abd9
Packit c4abd9
	tot_len = prev->len + tbp->len;
Packit c4abd9
	if (tot_len > buf_size) {
Packit c4abd9
		/*
Packit c4abd9
		 * tbp->head isn't connected (it was 'prev'
Packit c4abd9
		 * so it had been taken off of the list
Packit c4abd9
		 * before). Therefore, we can realloc
Packit c4abd9
		 * the whole structures, as the other fields
Packit c4abd9
		 * are "static".
Packit c4abd9
		 */
Packit c4abd9
		prev = realloc(prev, sizeof(*prev) + tot_len);
Packit c4abd9
		prev->buf = (void *)(prev + 1);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	memcpy(prev->buf + prev->len, tbp->buf, tbp->len);
Packit c4abd9
	prev->len = tot_len;
Packit c4abd9
Packit c4abd9
	free(tbp);
Packit c4abd9
	return prev;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_list_file(struct tracer_devpath_head *hd,
Packit c4abd9
			    struct list_head *list)
Packit c4abd9
{
Packit c4abd9
	int off, t_len, nevents;
Packit c4abd9
	struct blk_io_trace *t;
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
	int entries_handled = 0;
Packit c4abd9
	struct trace_buf *tbp, *prev;
Packit c4abd9
Packit c4abd9
	prev = hd->prev;
Packit c4abd9
	list_for_each_safe(p, q, list) {
Packit c4abd9
		tbp = list_entry(p, struct trace_buf, head);
Packit c4abd9
		list_del(&tbp->head);
Packit c4abd9
		entries_handled++;
Packit c4abd9
Packit c4abd9
		/*
Packit c4abd9
		 * If there was some leftover before, tack this new
Packit c4abd9
		 * entry onto the tail of the previous one.
Packit c4abd9
		 */
Packit c4abd9
		if (prev)
Packit c4abd9
			tbp = tb_combine(prev, tbp);
Packit c4abd9
Packit c4abd9
		/*
Packit c4abd9
		 * See how many whole traces there are - send them
Packit c4abd9
		 * all out in one go.
Packit c4abd9
		 */
Packit c4abd9
		off = 0;
Packit c4abd9
		nevents = 0;
Packit c4abd9
		while (off + (int)sizeof(*t) <= tbp->len) {
Packit c4abd9
			t = (struct blk_io_trace *)(tbp->buf + off);
Packit c4abd9
			t_len = sizeof(*t) + t->pdu_len;
Packit c4abd9
			if (off + t_len > tbp->len)
Packit c4abd9
				break;
Packit c4abd9
Packit c4abd9
			off += t_len;
Packit c4abd9
			nevents++;
Packit c4abd9
		}
Packit c4abd9
		if (nevents)
Packit c4abd9
			pdc_nev_update(tbp->dpp, tbp->cpu, nevents);
Packit c4abd9
Packit c4abd9
		/*
Packit c4abd9
		 * Write any full set of traces, any remaining data is kept
Packit c4abd9
		 * for the next pass.
Packit c4abd9
		 */
Packit c4abd9
		if (off) {
Packit c4abd9
			if (write_data(tbp->buf, off) || off == tbp->len) {
Packit c4abd9
				free(tbp);
Packit c4abd9
				prev = NULL;
Packit c4abd9
			}
Packit c4abd9
			else {
Packit c4abd9
				/*
Packit c4abd9
				 * Move valid data to beginning of buffer
Packit c4abd9
				 */
Packit c4abd9
				tbp->len -= off;
Packit c4abd9
				memmove(tbp->buf, tbp->buf + off, tbp->len);
Packit c4abd9
				prev = tbp;
Packit c4abd9
			}
Packit c4abd9
		} else
Packit c4abd9
			prev = tbp;
Packit c4abd9
	}
Packit c4abd9
	hd->prev = prev;
Packit c4abd9
Packit c4abd9
	return entries_handled;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void __process_trace_bufs(void)
Packit c4abd9
{
Packit c4abd9
	int cpu;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	struct list_head list;
Packit c4abd9
	int handled = 0;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
		struct tracer_devpath_head *hd = dpp->heads;
Packit c4abd9
Packit c4abd9
		for (cpu = 0; cpu < max_cpus; cpu++, hd++) {
Packit c4abd9
			pthread_mutex_lock(&hd->mutex);
Packit c4abd9
			if (list_empty(&hd->head)) {
Packit c4abd9
				pthread_mutex_unlock(&hd->mutex);
Packit c4abd9
				continue;
Packit c4abd9
			}
Packit c4abd9
Packit c4abd9
			list_replace_init(&hd->head, &list);
Packit c4abd9
			pthread_mutex_unlock(&hd->mutex);
Packit c4abd9
Packit c4abd9
			handled += handle_list(hd, &list);
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (handled)
Packit c4abd9
		decr_entries(handled);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void process_trace_bufs(void)
Packit c4abd9
{
Packit c4abd9
	while (wait_empty_entries())
Packit c4abd9
		__process_trace_bufs();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void clean_trace_bufs(void)
Packit c4abd9
{
Packit c4abd9
	/*
Packit c4abd9
	 * No mutex needed here: we're only reading from the lists,
Packit c4abd9
	 * tracers are done
Packit c4abd9
	 */
Packit c4abd9
	while (dp_entries)
Packit c4abd9
		__process_trace_bufs();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline void read_err(int cpu, char *ifn)
Packit c4abd9
{
Packit c4abd9
	if (errno != EAGAIN)
Packit c4abd9
		fprintf(stderr, "Thread %d failed read of %s: %d/%s\n",
Packit c4abd9
			cpu, ifn, errno, strerror(errno));
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_sendfile(struct io_info *iop)
Packit c4abd9
{
Packit c4abd9
	int ret;
Packit c4abd9
Packit c4abd9
	ret = sendfile(iop->ofd, iop->ifd, NULL, iop->ready);
Packit c4abd9
	if (ret < 0) {
Packit c4abd9
		perror("sendfile");
Packit c4abd9
		return 1;
Packit c4abd9
	} else if (ret < (int)iop->ready) {
Packit c4abd9
		fprintf(stderr, "short sendfile send (%d of %d)\n",
Packit c4abd9
			ret, iop->ready);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline int net_sendfile_data(struct tracer *tp, struct io_info *iop)
Packit c4abd9
{
Packit c4abd9
	struct devpath *dpp = iop->dpp;
Packit c4abd9
Packit c4abd9
	if (net_send_header(iop->ofd, tp->cpu, dpp->buts_name, iop->ready))
Packit c4abd9
		return 1;
Packit c4abd9
	return net_sendfile(iop);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int fill_ofname(char *dst, int dstlen, char *subdir, char *buts_name,
Packit c4abd9
		       int cpu)
Packit c4abd9
{
Packit c4abd9
	int len;
Packit c4abd9
	struct stat sb;
Packit c4abd9
Packit c4abd9
	if (output_dir)
Packit c4abd9
		len = snprintf(dst, dstlen, "%s/", output_dir);
Packit c4abd9
	else
Packit c4abd9
		len = snprintf(dst, dstlen, "./");
Packit c4abd9
Packit c4abd9
	if (subdir)
Packit c4abd9
		len += snprintf(dst + len, dstlen - len, "%s", subdir);
Packit c4abd9
Packit c4abd9
	if (stat(dst, &sb) < 0) {
Packit c4abd9
		if (errno != ENOENT) {
Packit c4abd9
			fprintf(stderr,
Packit c4abd9
				"Destination dir %s stat failed: %d/%s\n",
Packit c4abd9
				dst, errno, strerror(errno));
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
		/*
Packit c4abd9
		 * There is no synchronization between multiple threads
Packit c4abd9
		 * trying to create the directory at once.  It's harmless
Packit c4abd9
		 * to let them try, so just detect the problem and move on.
Packit c4abd9
		 */
Packit c4abd9
		if (mkdir(dst, 0755) < 0 && errno != EEXIST) {
Packit c4abd9
			fprintf(stderr,
Packit c4abd9
				"Destination dir %s can't be made: %d/%s\n",
Packit c4abd9
				dst, errno, strerror(errno));
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (output_name)
Packit c4abd9
		snprintf(dst + len, dstlen - len, "%s.blktrace.%d",
Packit c4abd9
			 output_name, cpu);
Packit c4abd9
	else
Packit c4abd9
		snprintf(dst + len, dstlen - len, "%s.blktrace.%d",
Packit c4abd9
			 buts_name, cpu);
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int set_vbuf(struct io_info *iop, int mode, size_t size)
Packit c4abd9
{
Packit c4abd9
	iop->obuf = malloc(size);
Packit c4abd9
	if (setvbuf(iop->ofp, iop->obuf, mode, size) < 0) {
Packit c4abd9
		fprintf(stderr, "setvbuf(%s, %d) failed: %d/%s\n",
Packit c4abd9
			iop->dpp->path, (int)size, errno,
Packit c4abd9
			strerror(errno));
Packit c4abd9
		free(iop->obuf);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int iop_open(struct io_info *iop, int cpu)
Packit c4abd9
{
Packit c4abd9
	char hostdir[MAXPATHLEN + 64];
Packit c4abd9
Packit c4abd9
	iop->ofd = -1;
Packit c4abd9
	if (net_mode == Net_server) {
Packit c4abd9
		struct cl_conn *nc = iop->nc;
Packit c4abd9
		int len;
Packit c4abd9
Packit c4abd9
		len = snprintf(hostdir, sizeof(hostdir), "%s-",
Packit c4abd9
			       nc->ch->hostname);
Packit c4abd9
		len += strftime(hostdir + len, sizeof(hostdir) - len, "%F-%T/",
Packit c4abd9
				gmtime(&iop->dpp->cl_connect_time));
Packit c4abd9
	} else {
Packit c4abd9
		hostdir[0] = 0;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (fill_ofname(iop->ofn, sizeof(iop->ofn), hostdir,
Packit c4abd9
			iop->dpp->buts_name, cpu))
Packit c4abd9
		return 1;
Packit c4abd9
Packit c4abd9
	iop->ofp = my_fopen(iop->ofn, "w+");
Packit c4abd9
	if (iop->ofp == NULL) {
Packit c4abd9
		fprintf(stderr, "Open output file %s failed: %d/%s\n",
Packit c4abd9
			iop->ofn, errno, strerror(errno));
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (set_vbuf(iop, _IOLBF, FILE_VBUF_SIZE)) {
Packit c4abd9
		fprintf(stderr, "set_vbuf for file %s failed: %d/%s\n",
Packit c4abd9
			iop->ofn, errno, strerror(errno));
Packit c4abd9
		fclose(iop->ofp);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	iop->ofd = fileno(iop->ofp);
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void close_iop(struct io_info *iop)
Packit c4abd9
{
Packit c4abd9
	struct mmap_info *mip = &iop->mmap_info;
Packit c4abd9
Packit c4abd9
	if (mip->fs_buf)
Packit c4abd9
		munmap(mip->fs_buf, mip->fs_buf_len);
Packit c4abd9
Packit c4abd9
	if (!piped_output) {
Packit c4abd9
		if (ftruncate(fileno(iop->ofp), mip->fs_size) < 0) {
Packit c4abd9
			fprintf(stderr,
Packit c4abd9
				"Ignoring err: ftruncate(%s): %d/%s\n",
Packit c4abd9
				iop->ofn, errno, strerror(errno));
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (iop->ofp)
Packit c4abd9
		fclose(iop->ofp);
Packit c4abd9
	if (iop->obuf)
Packit c4abd9
		free(iop->obuf);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void close_ios(struct tracer *tp)
Packit c4abd9
{
Packit c4abd9
	while (tp->nios > 0) {
Packit c4abd9
		struct io_info *iop = &tp->ios[--tp->nios];
Packit c4abd9
Packit c4abd9
		iop->dpp->drops = get_drops(iop->dpp);
Packit c4abd9
		if (iop->ifd >= 0)
Packit c4abd9
			close(iop->ifd);
Packit c4abd9
Packit c4abd9
		if (iop->ofp)
Packit c4abd9
			close_iop(iop);
Packit c4abd9
		else if (iop->ofd >= 0) {
Packit c4abd9
			struct devpath *dpp = iop->dpp;
Packit c4abd9
Packit c4abd9
			net_send_close(iop->ofd, dpp->buts_name, dpp->drops);
Packit c4abd9
			net_close_connection(&iop->ofd);
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	free(tp->ios);
Packit c4abd9
	free(tp->pfds);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int open_ios(struct tracer *tp)
Packit c4abd9
{
Packit c4abd9
	struct pollfd *pfd;
Packit c4abd9
	struct io_info *iop;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	tp->ios = calloc(ndevs, sizeof(struct io_info));
Packit c4abd9
	memset(tp->ios, 0, ndevs * sizeof(struct io_info));
Packit c4abd9
Packit c4abd9
	tp->pfds = calloc(ndevs, sizeof(struct pollfd));
Packit c4abd9
	memset(tp->pfds, 0, ndevs * sizeof(struct pollfd));
Packit c4abd9
Packit c4abd9
	tp->nios = 0;
Packit c4abd9
	iop = tp->ios;
Packit c4abd9
	pfd = tp->pfds;
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		iop->dpp = dpp;
Packit c4abd9
		iop->ofd = -1;
Packit c4abd9
		snprintf(iop->ifn, sizeof(iop->ifn), "%s/block/%s/trace%d",
Packit c4abd9
			debugfs_path, dpp->buts_name, tp->cpu);
Packit c4abd9
Packit c4abd9
		iop->ifd = my_open(iop->ifn, O_RDONLY | O_NONBLOCK);
Packit c4abd9
		if (iop->ifd < 0) {
Packit c4abd9
			fprintf(stderr, "Thread %d failed open %s: %d/%s\n",
Packit c4abd9
				tp->cpu, iop->ifn, errno, strerror(errno));
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		init_mmap_info(&iop->mmap_info);
Packit c4abd9
Packit c4abd9
		pfd->fd = iop->ifd;
Packit c4abd9
		pfd->events = POLLIN;
Packit c4abd9
Packit c4abd9
		if (piped_output)
Packit c4abd9
			;
Packit c4abd9
		else if (net_client_use_sendfile()) {
Packit c4abd9
			iop->ofd = net_setup_client();
Packit c4abd9
			if (iop->ofd < 0)
Packit c4abd9
				goto err;
Packit c4abd9
			net_send_open(iop->ofd, tp->cpu, dpp->buts_name);
Packit c4abd9
		} else if (net_mode == Net_none) {
Packit c4abd9
			if (iop_open(iop, tp->cpu))
Packit c4abd9
				goto err;
Packit c4abd9
		} else {
Packit c4abd9
			/*
Packit c4abd9
			 * This ensures that the server knows about all
Packit c4abd9
			 * connections & devices before _any_ closes
Packit c4abd9
			 */
Packit c4abd9
			net_send_open(cl_fds[tp->cpu], tp->cpu, dpp->buts_name);
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		pfd++;
Packit c4abd9
		iop++;
Packit c4abd9
		tp->nios++;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
Packit c4abd9
err:
Packit c4abd9
	close(iop->ifd);	/* tp->nios _not_ bumped */
Packit c4abd9
	close_ios(tp);
Packit c4abd9
	return 1;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_pfds_file(struct tracer *tp, int nevs, int force_read)
Packit c4abd9
{
Packit c4abd9
	struct mmap_info *mip;
Packit c4abd9
	int i, ret, nentries = 0;
Packit c4abd9
	struct pollfd *pfd = tp->pfds;
Packit c4abd9
	struct io_info *iop = tp->ios;
Packit c4abd9
Packit c4abd9
	for (i = 0; nevs > 0 && i < ndevs; i++, pfd++, iop++) {
Packit c4abd9
		if (pfd->revents & POLLIN || force_read) {
Packit c4abd9
			mip = &iop->mmap_info;
Packit c4abd9
Packit c4abd9
			ret = setup_mmap(iop->ofd, buf_size, mip, tp);
Packit c4abd9
			if (ret < 0) {
Packit c4abd9
				pfd->events = 0;
Packit c4abd9
				break;
Packit c4abd9
			}
Packit c4abd9
Packit c4abd9
			ret = read(iop->ifd, mip->fs_buf + mip->fs_off,
Packit c4abd9
				   buf_size);
Packit c4abd9
			if (ret > 0) {
Packit c4abd9
				pdc_dr_update(iop->dpp, tp->cpu, ret);
Packit c4abd9
				mip->fs_size += ret;
Packit c4abd9
				mip->fs_off += ret;
Packit c4abd9
				nentries++;
Packit c4abd9
			} else if (ret == 0) {
Packit c4abd9
				/*
Packit c4abd9
				 * Short reads after we're done stop us
Packit c4abd9
				 * from trying reads.
Packit c4abd9
				 */
Packit c4abd9
				if (tp->is_done)
Packit c4abd9
					clear_events(pfd);
Packit c4abd9
			} else {
Packit c4abd9
				read_err(tp->cpu, iop->ifn);
Packit c4abd9
				if (errno != EAGAIN || tp->is_done)
Packit c4abd9
					clear_events(pfd);
Packit c4abd9
			}
Packit c4abd9
			nevs--;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return nentries;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_pfds_netclient(struct tracer *tp, int nevs, int force_read)
Packit c4abd9
{
Packit c4abd9
	struct stat sb;
Packit c4abd9
	int i, nentries = 0;
Packit c4abd9
	struct pollfd *pfd = tp->pfds;
Packit c4abd9
	struct io_info *iop = tp->ios;
Packit c4abd9
Packit c4abd9
	for (i = 0; i < ndevs; i++, pfd++, iop++) {
Packit c4abd9
		if (pfd->revents & POLLIN || force_read) {
Packit c4abd9
			if (fstat(iop->ifd, &sb) < 0) {
Packit c4abd9
				perror(iop->ifn);
Packit c4abd9
				pfd->events = 0;
Packit c4abd9
			} else if (sb.st_size > (off_t)iop->data_queued) {
Packit c4abd9
				iop->ready = sb.st_size - iop->data_queued;
Packit c4abd9
				iop->data_queued = sb.st_size;
Packit c4abd9
Packit c4abd9
				if (!net_sendfile_data(tp, iop)) {
Packit c4abd9
					pdc_dr_update(iop->dpp, tp->cpu,
Packit c4abd9
						      iop->ready);
Packit c4abd9
					nentries++;
Packit c4abd9
				} else
Packit c4abd9
					clear_events(pfd);
Packit c4abd9
			}
Packit c4abd9
			if (--nevs == 0)
Packit c4abd9
				break;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (nentries)
Packit c4abd9
		incr_entries(nentries);
Packit c4abd9
Packit c4abd9
	return nentries;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_pfds_entries(struct tracer *tp, int nevs, int force_read)
Packit c4abd9
{
Packit c4abd9
	int i, nentries = 0;
Packit c4abd9
	struct trace_buf *tbp;
Packit c4abd9
	struct pollfd *pfd = tp->pfds;
Packit c4abd9
	struct io_info *iop = tp->ios;
Packit c4abd9
Packit c4abd9
	tbp = alloc_trace_buf(tp->cpu, buf_size);
Packit c4abd9
	for (i = 0; i < ndevs; i++, pfd++, iop++) {
Packit c4abd9
		if (pfd->revents & POLLIN || force_read) {
Packit c4abd9
			tbp->len = read(iop->ifd, tbp->buf, buf_size);
Packit c4abd9
			if (tbp->len > 0) {
Packit c4abd9
				pdc_dr_update(iop->dpp, tp->cpu, tbp->len);
Packit c4abd9
				add_trace_buf(iop->dpp, tp->cpu, &tbp;;
Packit c4abd9
				nentries++;
Packit c4abd9
			} else if (tbp->len == 0) {
Packit c4abd9
				/*
Packit c4abd9
				 * Short reads after we're done stop us
Packit c4abd9
				 * from trying reads.
Packit c4abd9
				 */
Packit c4abd9
				if (tp->is_done)
Packit c4abd9
					clear_events(pfd);
Packit c4abd9
			} else {
Packit c4abd9
				read_err(tp->cpu, iop->ifn);
Packit c4abd9
				if (errno != EAGAIN || tp->is_done)
Packit c4abd9
					clear_events(pfd);
Packit c4abd9
			}
Packit c4abd9
			if (!piped_output && --nevs == 0)
Packit c4abd9
				break;
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
	free(tbp);
Packit c4abd9
Packit c4abd9
	if (nentries)
Packit c4abd9
		incr_entries(nentries);
Packit c4abd9
Packit c4abd9
	return nentries;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void *thread_main(void *arg)
Packit c4abd9
{
Packit c4abd9
	int ret, ndone, to_val;
Packit c4abd9
	struct tracer *tp = arg;
Packit c4abd9
Packit c4abd9
	ret = lock_on_cpu(tp->cpu);
Packit c4abd9
	if (ret)
Packit c4abd9
		goto err;
Packit c4abd9
Packit c4abd9
	ret = open_ios(tp);
Packit c4abd9
	if (ret)
Packit c4abd9
		goto err;
Packit c4abd9
Packit c4abd9
	if (piped_output)
Packit c4abd9
		to_val = 50;		/* Frequent partial handles */
Packit c4abd9
	else
Packit c4abd9
		to_val = 500;		/* 1/2 second intervals */
Packit c4abd9
Packit c4abd9
Packit c4abd9
	tracer_signal_ready(tp, Th_running, 0);
Packit c4abd9
	tracer_wait_unblock(tp);
Packit c4abd9
Packit c4abd9
	while (!tp->is_done) {
Packit c4abd9
		ndone = poll(tp->pfds, ndevs, to_val);
Packit c4abd9
		if (ndone || piped_output)
Packit c4abd9
			(void)handle_pfds(tp, ndone, piped_output);
Packit c4abd9
		else if (ndone < 0 && errno != EINTR)
Packit c4abd9
			fprintf(stderr, "Thread %d poll failed: %d/%s\n",
Packit c4abd9
				tp->cpu, errno, strerror(errno));
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Trace is stopped, pull data until we get a short read
Packit c4abd9
	 */
Packit c4abd9
	while (handle_pfds(tp, ndevs, 1) > 0)
Packit c4abd9
		;
Packit c4abd9
Packit c4abd9
	close_ios(tp);
Packit c4abd9
	tracer_signal_ready(tp, Th_leaving, 0);
Packit c4abd9
	return NULL;
Packit c4abd9
Packit c4abd9
err:
Packit c4abd9
	tracer_signal_ready(tp, Th_error, ret);
Packit c4abd9
	return NULL;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int start_tracer(int cpu)
Packit c4abd9
{
Packit c4abd9
	struct tracer *tp;
Packit c4abd9
Packit c4abd9
	tp = malloc(sizeof(*tp));
Packit c4abd9
	memset(tp, 0, sizeof(*tp));
Packit c4abd9
Packit c4abd9
	INIT_LIST_HEAD(&tp->head);
Packit c4abd9
	tp->status = 0;
Packit c4abd9
	tp->cpu = cpu;
Packit c4abd9
Packit c4abd9
	if (pthread_create(&tp->thread, NULL, thread_main, tp)) {
Packit c4abd9
		fprintf(stderr, "FAILED to start thread on CPU %d: %d/%s\n",
Packit c4abd9
			cpu, errno, strerror(errno));
Packit c4abd9
		free(tp);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	list_add_tail(&tp->head, &tracers);
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int create_output_files(int cpu)
Packit c4abd9
{
Packit c4abd9
	char fname[MAXPATHLEN + 64];
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	FILE *f;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		if (fill_ofname(fname, sizeof(fname), NULL, dpp->buts_name,
Packit c4abd9
				cpu))
Packit c4abd9
			return 1;
Packit c4abd9
		f = my_fopen(fname, "w+");
Packit c4abd9
		if (!f)
Packit c4abd9
			return 1;
Packit c4abd9
		fclose(f);
Packit c4abd9
	}
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void start_tracers(void)
Packit c4abd9
{
Packit c4abd9
	int cpu, started = 0;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	size_t alloc_size = CPU_ALLOC_SIZE(max_cpus);
Packit c4abd9
Packit c4abd9
	for (cpu = 0; cpu < max_cpus; cpu++) {
Packit c4abd9
		if (!CPU_ISSET_S(cpu, alloc_size, online_cpus)) {
Packit c4abd9
			/*
Packit c4abd9
			 * Create fake empty output files so that other tools
Packit c4abd9
			 * like blkparse don't have to bother with sparse CPU
Packit c4abd9
			 * number space.
Packit c4abd9
			 */
Packit c4abd9
			if (create_output_files(cpu))
Packit c4abd9
				break;
Packit c4abd9
			continue;
Packit c4abd9
		}
Packit c4abd9
		if (start_tracer(cpu))
Packit c4abd9
			break;
Packit c4abd9
		started++;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	wait_tracers_ready(started);
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &tracers) {
Packit c4abd9
		struct tracer *tp = list_entry(p, struct tracer, head);
Packit c4abd9
		if (tp->status)
Packit c4abd9
			fprintf(stderr,
Packit c4abd9
				"FAILED to start thread on CPU %d: %d/%s\n",
Packit c4abd9
				tp->cpu, tp->status, strerror(tp->status));
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void stop_tracers(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Stop the tracing - makes the tracer threads clean up quicker.
Packit c4abd9
	 */
Packit c4abd9
	__list_for_each(p, &devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
		(void)ioctl(dpp->fd, BLKTRACESTOP);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Tell each tracer to quit
Packit c4abd9
	 */
Packit c4abd9
	__list_for_each(p, &tracers) {
Packit c4abd9
		struct tracer *tp = list_entry(p, struct tracer, head);
Packit c4abd9
		tp->is_done = 1;
Packit c4abd9
	}
Packit c4abd9
	pthread_cond_broadcast(&mt_cond);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void del_tracers(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
Packit c4abd9
	list_for_each_safe(p, q, &tracers) {
Packit c4abd9
		struct tracer *tp = list_entry(p, struct tracer, head);
Packit c4abd9
Packit c4abd9
		list_del(&tp->head);
Packit c4abd9
		free(tp);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void wait_tracers(void)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	if (use_tracer_devpaths())
Packit c4abd9
		process_trace_bufs();
Packit c4abd9
Packit c4abd9
	wait_tracers_leaving();
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &tracers) {
Packit c4abd9
		int ret;
Packit c4abd9
		struct tracer *tp = list_entry(p, struct tracer, head);
Packit c4abd9
Packit c4abd9
		ret = pthread_join(tp->thread, NULL);
Packit c4abd9
		if (ret)
Packit c4abd9
			fprintf(stderr, "Thread join %d failed %d\n",
Packit c4abd9
				tp->cpu, ret);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (use_tracer_devpaths())
Packit c4abd9
		clean_trace_bufs();
Packit c4abd9
Packit c4abd9
	get_all_drops();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void exit_tracing(void)
Packit c4abd9
{
Packit c4abd9
	signal(SIGINT, SIG_IGN);
Packit c4abd9
	signal(SIGHUP, SIG_IGN);
Packit c4abd9
	signal(SIGTERM, SIG_IGN);
Packit c4abd9
	signal(SIGALRM, SIG_IGN);
Packit c4abd9
Packit c4abd9
	stop_tracers();
Packit c4abd9
	wait_tracers();
Packit c4abd9
	del_tracers();
Packit c4abd9
	rel_devpaths();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void handle_sigint(__attribute__((__unused__)) int sig)
Packit c4abd9
{
Packit c4abd9
	done = 1;
Packit c4abd9
	stop_tracers();
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void show_stats(struct list_head *devpaths)
Packit c4abd9
{
Packit c4abd9
	FILE *ofp;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	unsigned long long nevents, data_read;
Packit c4abd9
	unsigned long long total_drops = 0;
Packit c4abd9
	unsigned long long total_events = 0;
Packit c4abd9
Packit c4abd9
	if (piped_output)
Packit c4abd9
		ofp = my_fopen("/dev/null", "w");
Packit c4abd9
	else
Packit c4abd9
		ofp = stdout;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, devpaths) {
Packit c4abd9
		int cpu;
Packit c4abd9
		struct pdc_stats *sp;
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		if (net_mode == Net_server)
Packit c4abd9
			printf("server: end of run for %s:%s\n",
Packit c4abd9
				dpp->ch->hostname, dpp->buts_name);
Packit c4abd9
Packit c4abd9
		data_read = 0;
Packit c4abd9
		nevents = 0;
Packit c4abd9
Packit c4abd9
		fprintf(ofp, "=== %s ===\n", dpp->buts_name);
Packit c4abd9
		for (cpu = 0, sp = dpp->stats; cpu < dpp->ncpus; cpu++, sp++) {
Packit c4abd9
			/*
Packit c4abd9
			 * Estimate events if not known...
Packit c4abd9
			 */
Packit c4abd9
			if (sp->nevents == 0) {
Packit c4abd9
				sp->nevents = sp->data_read /
Packit c4abd9
						sizeof(struct blk_io_trace);
Packit c4abd9
			}
Packit c4abd9
Packit c4abd9
			fprintf(ofp,
Packit c4abd9
				"  CPU%3d: %20llu events, %8llu KiB data\n",
Packit c4abd9
				cpu, sp->nevents, (sp->data_read + 1023) >> 10);
Packit c4abd9
Packit c4abd9
			data_read += sp->data_read;
Packit c4abd9
			nevents += sp->nevents;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		fprintf(ofp, "  Total:  %20llu events (dropped %llu),"
Packit c4abd9
			     " %8llu KiB data\n", nevents,
Packit c4abd9
			     dpp->drops, (data_read + 1024) >> 10);
Packit c4abd9
Packit c4abd9
		total_drops += dpp->drops;
Packit c4abd9
		total_events += (nevents + dpp->drops);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	fflush(ofp);
Packit c4abd9
	if (piped_output)
Packit c4abd9
		fclose(ofp);
Packit c4abd9
Packit c4abd9
	if (total_drops) {
Packit c4abd9
		double drops_ratio = 1.0;
Packit c4abd9
Packit c4abd9
		if (total_events)
Packit c4abd9
			drops_ratio = (double)total_drops/(double)total_events;
Packit c4abd9
Packit c4abd9
		fprintf(stderr, "\nYou have %llu (%5.1lf%%) dropped events\n"
Packit c4abd9
				"Consider using a larger buffer size (-b) "
Packit c4abd9
				"and/or more buffers (-n)\n",
Packit c4abd9
			total_drops, 100.0 * drops_ratio);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int handle_args(int argc, char *argv[])
Packit c4abd9
{
Packit c4abd9
	int c, i;
Packit c4abd9
	struct statfs st;
Packit c4abd9
	int act_mask_tmp = 0;
Packit c4abd9
Packit c4abd9
	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
Packit c4abd9
		switch (c) {
Packit c4abd9
		case 'a':
Packit c4abd9
			i = find_mask_map(optarg);
Packit c4abd9
			if (i < 0) {
Packit c4abd9
				fprintf(stderr, "Invalid action mask %s\n",
Packit c4abd9
					optarg);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
			act_mask_tmp |= i;
Packit c4abd9
			break;
Packit c4abd9
Packit c4abd9
		case 'A':
Packit c4abd9
			if ((sscanf(optarg, "%x", &i) != 1) ||
Packit c4abd9
							!valid_act_opt(i)) {
Packit c4abd9
				fprintf(stderr,
Packit c4abd9
					"Invalid set action mask %s/0x%x\n",
Packit c4abd9
					optarg, i);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
			act_mask_tmp = i;
Packit c4abd9
			break;
Packit c4abd9
Packit c4abd9
		case 'd':
Packit c4abd9
			if (add_devpath(optarg) != 0)
Packit c4abd9
				return 1;
Packit c4abd9
			break;
Packit c4abd9
Packit c4abd9
		case 'I': {
Packit c4abd9
			char dev_line[256];
Packit c4abd9
			FILE *ifp = my_fopen(optarg, "r");
Packit c4abd9
Packit c4abd9
			if (!ifp) {
Packit c4abd9
				fprintf(stderr,
Packit c4abd9
					"Invalid file for devices %s\n",
Packit c4abd9
					optarg);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
Packit c4abd9
			while (fscanf(ifp, "%s\n", dev_line) == 1) {
Packit c4abd9
				if (add_devpath(dev_line) != 0) {
Packit c4abd9
					fclose(ifp);
Packit c4abd9
					return 1;
Packit c4abd9
				}
Packit c4abd9
			}
Packit c4abd9
			fclose(ifp);
Packit c4abd9
			break;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		case 'r':
Packit c4abd9
			debugfs_path = optarg;
Packit c4abd9
			break;
Packit c4abd9
Packit c4abd9
		case 'o':
Packit c4abd9
			output_name = optarg;
Packit c4abd9
			break;
Packit c4abd9
		case 'k':
Packit c4abd9
			kill_running_trace = 1;
Packit c4abd9
			break;
Packit c4abd9
		case 'w':
Packit c4abd9
			stop_watch = atoi(optarg);
Packit c4abd9
			if (stop_watch <= 0) {
Packit c4abd9
				fprintf(stderr,
Packit c4abd9
					"Invalid stopwatch value (%d secs)\n",
Packit c4abd9
					stop_watch);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
			break;
Packit c4abd9
		case 'V':
Packit c4abd9
		case 'v':
Packit c4abd9
			printf("%s version %s\n", argv[0], blktrace_version);
Packit c4abd9
			exit(0);
Packit c4abd9
			/*NOTREACHED*/
Packit c4abd9
		case 'b':
Packit c4abd9
			buf_size = strtoul(optarg, NULL, 10);
Packit c4abd9
			if (buf_size <= 0 || buf_size > 16*1024) {
Packit c4abd9
				fprintf(stderr, "Invalid buffer size (%lu)\n",
Packit c4abd9
					buf_size);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
			buf_size <<= 10;
Packit c4abd9
			break;
Packit c4abd9
		case 'n':
Packit c4abd9
			buf_nr = strtoul(optarg, NULL, 10);
Packit c4abd9
			if (buf_nr <= 0) {
Packit c4abd9
				fprintf(stderr,
Packit c4abd9
					"Invalid buffer nr (%lu)\n", buf_nr);
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
			break;
Packit c4abd9
		case 'D':
Packit c4abd9
			output_dir = optarg;
Packit c4abd9
			break;
Packit c4abd9
		case 'h':
Packit c4abd9
			net_mode = Net_client;
Packit c4abd9
			memset(hostname, 0, sizeof(hostname));
Packit c4abd9
			strncpy(hostname, optarg, sizeof(hostname));
Packit c4abd9
			hostname[sizeof(hostname) - 1] = '\0';
Packit c4abd9
			break;
Packit c4abd9
		case 'l':
Packit c4abd9
			net_mode = Net_server;
Packit c4abd9
			break;
Packit c4abd9
		case 'p':
Packit c4abd9
			net_port = atoi(optarg);
Packit c4abd9
			break;
Packit c4abd9
		case 's':
Packit c4abd9
			net_use_sendfile = 0;
Packit c4abd9
			break;
Packit c4abd9
		default:
Packit c4abd9
			show_usage(argv[0]);
Packit c4abd9
			exit(1);
Packit c4abd9
			/*NOTREACHED*/
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	while (optind < argc)
Packit c4abd9
		if (add_devpath(argv[optind++]) != 0)
Packit c4abd9
			return 1;
Packit c4abd9
Packit c4abd9
	if (net_mode != Net_server && ndevs == 0) {
Packit c4abd9
		show_usage(argv[0]);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (statfs(debugfs_path, &st) < 0) {
Packit c4abd9
		fprintf(stderr, "Invalid debug path %s: %d/%s\n",
Packit c4abd9
			debugfs_path, errno, strerror(errno));
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (st.f_type != (long)DEBUGFS_TYPE) {
Packit c4abd9
		fprintf(stderr, "Debugfs is not mounted at %s\n", debugfs_path);
Packit c4abd9
		return 1;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (act_mask_tmp != 0)
Packit c4abd9
		act_mask = act_mask_tmp;
Packit c4abd9
Packit c4abd9
	if (net_mode == Net_client && net_setup_addr())
Packit c4abd9
		return 1;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Set up for appropriate PFD handler based upon output name.
Packit c4abd9
	 */
Packit c4abd9
	if (net_client_use_sendfile())
Packit c4abd9
		handle_pfds = handle_pfds_netclient;
Packit c4abd9
	else if (net_client_use_send())
Packit c4abd9
		handle_pfds = handle_pfds_entries;
Packit c4abd9
	else if (output_name && (strcmp(output_name, "-") == 0)) {
Packit c4abd9
		piped_output = 1;
Packit c4abd9
		handle_pfds = handle_pfds_entries;
Packit c4abd9
		pfp = stdout;
Packit c4abd9
		if (setvbuf(pfp, NULL, _IONBF, 0)) {
Packit c4abd9
			perror("setvbuf stdout");
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
	} else
Packit c4abd9
		handle_pfds = handle_pfds_file;
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void ch_add_connection(struct net_server_s *ns, struct cl_host *ch,
Packit c4abd9
			      int fd)
Packit c4abd9
{
Packit c4abd9
	struct cl_conn *nc;
Packit c4abd9
Packit c4abd9
	nc = malloc(sizeof(*nc));
Packit c4abd9
	memset(nc, 0, sizeof(*nc));
Packit c4abd9
Packit c4abd9
	time(&nc->connect_time);
Packit c4abd9
	nc->ch = ch;
Packit c4abd9
	nc->fd = fd;
Packit c4abd9
	nc->ncpus = -1;
Packit c4abd9
Packit c4abd9
	list_add_tail(&nc->ch_head, &ch->conn_list);
Packit c4abd9
	ch->connects++;
Packit c4abd9
Packit c4abd9
	list_add_tail(&nc->ns_head, &ns->conn_list);
Packit c4abd9
	ns->connects++;
Packit c4abd9
	ns->pfds = realloc(ns->pfds, (ns->connects+1) * sizeof(struct pollfd));
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void ch_rem_connection(struct net_server_s *ns, struct cl_host *ch,
Packit c4abd9
			      struct cl_conn *nc)
Packit c4abd9
{
Packit c4abd9
	net_close_connection(&nc->fd);
Packit c4abd9
Packit c4abd9
	list_del(&nc->ch_head);
Packit c4abd9
	ch->connects--;
Packit c4abd9
Packit c4abd9
	list_del(&nc->ns_head);
Packit c4abd9
	ns->connects--;
Packit c4abd9
	ns->pfds = realloc(ns->pfds, (ns->connects+1) * sizeof(struct pollfd));
Packit c4abd9
Packit c4abd9
	free(nc);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static struct cl_host *net_find_client_host(struct net_server_s *ns,
Packit c4abd9
					    struct in_addr cl_in_addr)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &ns->ch_list) {
Packit c4abd9
		struct cl_host *ch = list_entry(p, struct cl_host, head);
Packit c4abd9
Packit c4abd9
		if (in_addr_eq(ch->cl_in_addr, cl_in_addr))
Packit c4abd9
			return ch;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return NULL;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static struct cl_host *net_add_client_host(struct net_server_s *ns,
Packit c4abd9
					   struct sockaddr_in *addr)
Packit c4abd9
{
Packit c4abd9
	struct cl_host *ch;
Packit c4abd9
Packit c4abd9
	ch = malloc(sizeof(*ch));
Packit c4abd9
	memset(ch, 0, sizeof(*ch));
Packit c4abd9
Packit c4abd9
	ch->ns = ns;
Packit c4abd9
	ch->cl_in_addr = addr->sin_addr;
Packit c4abd9
	list_add_tail(&ch->head, &ns->ch_list);
Packit c4abd9
	ns->nchs++;
Packit c4abd9
Packit c4abd9
	ch->hostname = strdup(inet_ntoa(addr->sin_addr));
Packit c4abd9
	printf("server: connection from %s\n", ch->hostname);
Packit c4abd9
Packit c4abd9
	INIT_LIST_HEAD(&ch->conn_list);
Packit c4abd9
	INIT_LIST_HEAD(&ch->devpaths);
Packit c4abd9
Packit c4abd9
	return ch;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void device_done(struct devpath *dpp, int ncpus)
Packit c4abd9
{
Packit c4abd9
	int cpu;
Packit c4abd9
	struct io_info *iop;
Packit c4abd9
Packit c4abd9
	for (cpu = 0, iop = dpp->ios; cpu < ncpus; cpu++, iop++)
Packit c4abd9
		close_iop(iop);
Packit c4abd9
Packit c4abd9
	list_del(&dpp->head);
Packit c4abd9
	dpp_free(dpp);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_ch_remove(struct cl_host *ch, int ncpus)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
	struct net_server_s *ns = ch->ns;
Packit c4abd9
Packit c4abd9
	list_for_each_safe(p, q, &ch->devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
		device_done(dpp, ncpus);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	list_for_each_safe(p, q, &ch->conn_list) {
Packit c4abd9
		struct cl_conn *nc = list_entry(p, struct cl_conn, ch_head);
Packit c4abd9
Packit c4abd9
		ch_rem_connection(ns, ch, nc);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	list_del(&ch->head);
Packit c4abd9
	ns->nchs--;
Packit c4abd9
Packit c4abd9
	if (ch->hostname)
Packit c4abd9
		free(ch->hostname);
Packit c4abd9
	free(ch);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_add_connection(struct net_server_s *ns)
Packit c4abd9
{
Packit c4abd9
	int fd;
Packit c4abd9
	struct cl_host *ch;
Packit c4abd9
	socklen_t socklen = sizeof(ns->addr);
Packit c4abd9
Packit c4abd9
	fd = my_accept(ns->listen_fd, (struct sockaddr *)&ns->addr, &socklen);
Packit c4abd9
	if (fd < 0) {
Packit c4abd9
		/*
Packit c4abd9
		 * This is OK: we just won't accept this connection,
Packit c4abd9
		 * nothing fatal.
Packit c4abd9
		 */
Packit c4abd9
		perror("accept");
Packit c4abd9
	} else {
Packit c4abd9
		ch = net_find_client_host(ns, ns->addr.sin_addr);
Packit c4abd9
		if (!ch)
Packit c4abd9
			ch = net_add_client_host(ns, &ns->addr);
Packit c4abd9
Packit c4abd9
		ch_add_connection(ns, ch, fd);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static struct devpath *nc_add_dpp(struct cl_conn *nc,
Packit c4abd9
				  struct blktrace_net_hdr *bnh,
Packit c4abd9
				  time_t connect_time)
Packit c4abd9
{
Packit c4abd9
	int cpu;
Packit c4abd9
	struct io_info *iop;
Packit c4abd9
	struct devpath *dpp;
Packit c4abd9
Packit c4abd9
	dpp = malloc(sizeof(*dpp));
Packit c4abd9
	memset(dpp, 0, sizeof(*dpp));
Packit c4abd9
Packit c4abd9
	dpp->buts_name = strdup(bnh->buts_name);
Packit c4abd9
	dpp->path = strdup(bnh->buts_name);
Packit c4abd9
	dpp->fd = -1;
Packit c4abd9
	dpp->ch = nc->ch;
Packit c4abd9
	dpp->cl_id = bnh->cl_id;
Packit c4abd9
	dpp->cl_connect_time = connect_time;
Packit c4abd9
	dpp->ncpus = nc->ncpus;
Packit c4abd9
	dpp->stats = calloc(dpp->ncpus, sizeof(*dpp->stats));
Packit c4abd9
	memset(dpp->stats, 0, dpp->ncpus * sizeof(*dpp->stats));
Packit c4abd9
Packit c4abd9
	list_add_tail(&dpp->head, &nc->ch->devpaths);
Packit c4abd9
	nc->ch->ndevs++;
Packit c4abd9
Packit c4abd9
	dpp->ios = calloc(nc->ncpus, sizeof(*iop));
Packit c4abd9
	memset(dpp->ios, 0, ndevs * sizeof(*iop));
Packit c4abd9
Packit c4abd9
	for (cpu = 0, iop = dpp->ios; cpu < nc->ncpus; cpu++, iop++) {
Packit c4abd9
		iop->dpp = dpp;
Packit c4abd9
		iop->nc = nc;
Packit c4abd9
		init_mmap_info(&iop->mmap_info);
Packit c4abd9
Packit c4abd9
		if (iop_open(iop, cpu))
Packit c4abd9
			goto err;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return dpp;
Packit c4abd9
Packit c4abd9
err:
Packit c4abd9
	/*
Packit c4abd9
	 * Need to unravel what's been done...
Packit c4abd9
	 */
Packit c4abd9
	while (cpu >= 0)
Packit c4abd9
		close_iop(&dpp->ios[cpu--]);
Packit c4abd9
	dpp_free(dpp);
Packit c4abd9
Packit c4abd9
	return NULL;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static struct devpath *nc_find_dpp(struct cl_conn *nc,
Packit c4abd9
				   struct blktrace_net_hdr *bnh)
Packit c4abd9
{
Packit c4abd9
	struct list_head *p;
Packit c4abd9
	time_t connect_time = nc->connect_time;
Packit c4abd9
Packit c4abd9
	__list_for_each(p, &nc->ch->devpaths) {
Packit c4abd9
		struct devpath *dpp = list_entry(p, struct devpath, head);
Packit c4abd9
Packit c4abd9
		if (!strcmp(dpp->buts_name, bnh->buts_name))
Packit c4abd9
			return dpp;
Packit c4abd9
Packit c4abd9
		if (dpp->cl_id == bnh->cl_id)
Packit c4abd9
			connect_time = dpp->cl_connect_time;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return nc_add_dpp(nc, bnh, connect_time);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_client_read_data(struct cl_conn *nc, struct devpath *dpp,
Packit c4abd9
				 struct blktrace_net_hdr *bnh)
Packit c4abd9
{
Packit c4abd9
	int ret;
Packit c4abd9
	struct io_info *iop = &dpp->ios[bnh->cpu];
Packit c4abd9
	struct mmap_info *mip = &iop->mmap_info;
Packit c4abd9
Packit c4abd9
	if (setup_mmap(iop->ofd, bnh->len, &iop->mmap_info, NULL)) {
Packit c4abd9
		fprintf(stderr, "ncd(%s:%d): mmap failed\n",
Packit c4abd9
			nc->ch->hostname, nc->fd);
Packit c4abd9
		exit(1);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	ret = net_recv_data(nc->fd, mip->fs_buf + mip->fs_off, bnh->len);
Packit c4abd9
	if (ret > 0) {
Packit c4abd9
		pdc_dr_update(dpp, bnh->cpu, ret);
Packit c4abd9
		mip->fs_size += ret;
Packit c4abd9
		mip->fs_off += ret;
Packit c4abd9
	} else if (ret < 0)
Packit c4abd9
		exit(1);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
/*
Packit c4abd9
 * Returns 1 if we closed a host - invalidates other polling information
Packit c4abd9
 * that may be present.
Packit c4abd9
 */
Packit c4abd9
static int net_client_data(struct cl_conn *nc)
Packit c4abd9
{
Packit c4abd9
	int ret;
Packit c4abd9
	struct devpath *dpp;
Packit c4abd9
	struct blktrace_net_hdr bnh;
Packit c4abd9
Packit c4abd9
	ret = net_get_header(nc, &bnh;;
Packit c4abd9
	if (ret == 0)
Packit c4abd9
		return 0;
Packit c4abd9
Packit c4abd9
	if (ret < 0) {
Packit c4abd9
		fprintf(stderr, "ncd(%d): header read failed\n", nc->fd);
Packit c4abd9
		exit(1);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (data_is_native == -1 && check_data_endianness(bnh.magic)) {
Packit c4abd9
		fprintf(stderr, "ncd(%d): received data is bad\n", nc->fd);
Packit c4abd9
		exit(1);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (!data_is_native) {
Packit c4abd9
		bnh.magic = be32_to_cpu(bnh.magic);
Packit c4abd9
		bnh.cpu = be32_to_cpu(bnh.cpu);
Packit c4abd9
		bnh.max_cpus = be32_to_cpu(bnh.max_cpus);
Packit c4abd9
		bnh.len = be32_to_cpu(bnh.len);
Packit c4abd9
		bnh.cl_id = be32_to_cpu(bnh.cl_id);
Packit c4abd9
		bnh.buf_size = be32_to_cpu(bnh.buf_size);
Packit c4abd9
		bnh.buf_nr = be32_to_cpu(bnh.buf_nr);
Packit c4abd9
		bnh.page_size = be32_to_cpu(bnh.page_size);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if ((bnh.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
Packit c4abd9
		fprintf(stderr, "ncd(%s:%d): bad data magic\n",
Packit c4abd9
			nc->ch->hostname, nc->fd);
Packit c4abd9
		exit(1);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (nc->ncpus == -1)
Packit c4abd9
		nc->ncpus = bnh.max_cpus;
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * len == 0 means the other end is sending us a new connection/dpp
Packit c4abd9
	 * len == 1 means that the other end signalled end-of-run
Packit c4abd9
	 */
Packit c4abd9
	dpp = nc_find_dpp(nc, &bnh;;
Packit c4abd9
	if (bnh.len == 0) {
Packit c4abd9
		/*
Packit c4abd9
		 * Just adding in the dpp above is enough
Packit c4abd9
		 */
Packit c4abd9
		ack_open_close(nc->fd, dpp->buts_name);
Packit c4abd9
		nc->ch->cl_opens++;
Packit c4abd9
	} else if (bnh.len == 1) {
Packit c4abd9
		/*
Packit c4abd9
		 * overload cpu count with dropped events
Packit c4abd9
		 */
Packit c4abd9
		dpp->drops = bnh.cpu;
Packit c4abd9
Packit c4abd9
		ack_open_close(nc->fd, dpp->buts_name);
Packit c4abd9
		if (--nc->ch->cl_opens == 0) {
Packit c4abd9
			show_stats(&nc->ch->devpaths);
Packit c4abd9
			net_ch_remove(nc->ch, nc->ncpus);
Packit c4abd9
			return 1;
Packit c4abd9
		}
Packit c4abd9
	} else
Packit c4abd9
		net_client_read_data(nc, dpp, &bnh;;
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void handle_client_data(struct net_server_s *ns, int events)
Packit c4abd9
{
Packit c4abd9
	struct cl_conn *nc;
Packit c4abd9
	struct pollfd *pfd;
Packit c4abd9
	struct list_head *p, *q;
Packit c4abd9
Packit c4abd9
	pfd = &ns->pfds[1];
Packit c4abd9
	list_for_each_safe(p, q, &ns->conn_list) {
Packit c4abd9
		if (pfd->revents & POLLIN) {
Packit c4abd9
			nc = list_entry(p, struct cl_conn, ns_head);
Packit c4abd9
Packit c4abd9
			if (net_client_data(nc) || --events == 0)
Packit c4abd9
				break;
Packit c4abd9
		}
Packit c4abd9
		pfd++;
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void net_setup_pfds(struct net_server_s *ns)
Packit c4abd9
{
Packit c4abd9
	struct pollfd *pfd;
Packit c4abd9
	struct list_head *p;
Packit c4abd9
Packit c4abd9
	ns->pfds[0].fd = ns->listen_fd;
Packit c4abd9
	ns->pfds[0].events = POLLIN;
Packit c4abd9
Packit c4abd9
	pfd = &ns->pfds[1];
Packit c4abd9
	__list_for_each(p, &ns->conn_list) {
Packit c4abd9
		struct cl_conn *nc = list_entry(p, struct cl_conn, ns_head);
Packit c4abd9
Packit c4abd9
		pfd->fd = nc->fd;
Packit c4abd9
		pfd->events = POLLIN;
Packit c4abd9
		pfd++;
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_server_handle_connections(struct net_server_s *ns)
Packit c4abd9
{
Packit c4abd9
	int events;
Packit c4abd9
Packit c4abd9
	printf("server: waiting for connections...\n");
Packit c4abd9
Packit c4abd9
	while (!done) {
Packit c4abd9
		net_setup_pfds(ns);
Packit c4abd9
		events = poll(ns->pfds, ns->connects + 1, -1);
Packit c4abd9
		if (events < 0) {
Packit c4abd9
			if (errno != EINTR) {
Packit c4abd9
				perror("FATAL: poll error");
Packit c4abd9
				return 1;
Packit c4abd9
			}
Packit c4abd9
		} else if (events > 0) {
Packit c4abd9
			if (ns->pfds[0].revents & POLLIN) {
Packit c4abd9
				net_add_connection(ns);
Packit c4abd9
				events--;
Packit c4abd9
			}
Packit c4abd9
Packit c4abd9
			if (events)
Packit c4abd9
				handle_client_data(ns, events);
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int net_server(void)
Packit c4abd9
{
Packit c4abd9
	int fd, opt;
Packit c4abd9
	int ret = 1;
Packit c4abd9
	struct net_server_s net_server;
Packit c4abd9
	struct net_server_s *ns = &net_server;
Packit c4abd9
Packit c4abd9
	memset(ns, 0, sizeof(*ns));
Packit c4abd9
	INIT_LIST_HEAD(&ns->ch_list);
Packit c4abd9
	INIT_LIST_HEAD(&ns->conn_list);
Packit c4abd9
	ns->pfds = malloc(sizeof(struct pollfd));
Packit c4abd9
Packit c4abd9
	fd = my_socket(AF_INET, SOCK_STREAM, 0);
Packit c4abd9
	if (fd < 0) {
Packit c4abd9
		perror("server: socket");
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	opt = 1;
Packit c4abd9
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
Packit c4abd9
		perror("setsockopt");
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	memset(&ns->addr, 0, sizeof(ns->addr));
Packit c4abd9
	ns->addr.sin_family = AF_INET;
Packit c4abd9
	ns->addr.sin_addr.s_addr = htonl(INADDR_ANY);
Packit c4abd9
	ns->addr.sin_port = htons(net_port);
Packit c4abd9
Packit c4abd9
	if (bind(fd, (struct sockaddr *) &ns->addr, sizeof(ns->addr)) < 0) {
Packit c4abd9
		perror("bind");
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	if (listen(fd, 1) < 0) {
Packit c4abd9
		perror("listen");
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * The actual server looping is done here:
Packit c4abd9
	 */
Packit c4abd9
	ns->listen_fd = fd;
Packit c4abd9
	ret = net_server_handle_connections(ns);
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * Clean up and return...
Packit c4abd9
	 */
Packit c4abd9
out:
Packit c4abd9
	free(ns->pfds);
Packit c4abd9
	return ret;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static int run_tracers(void)
Packit c4abd9
{
Packit c4abd9
	atexit(exit_tracing);
Packit c4abd9
	if (net_mode == Net_client)
Packit c4abd9
		printf("blktrace: connecting to %s\n", hostname);
Packit c4abd9
Packit c4abd9
	if (setup_buts())
Packit c4abd9
		return 1;
Packit c4abd9
Packit c4abd9
	if (use_tracer_devpaths()) {
Packit c4abd9
		if (setup_tracer_devpaths())
Packit c4abd9
			return 1;
Packit c4abd9
Packit c4abd9
		if (piped_output)
Packit c4abd9
			handle_list = handle_list_file;
Packit c4abd9
		else
Packit c4abd9
			handle_list = handle_list_net;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	start_tracers();
Packit c4abd9
	if (nthreads_running == ncpus) {
Packit c4abd9
		unblock_tracers();
Packit c4abd9
		start_buts();
Packit c4abd9
		if (net_mode == Net_client)
Packit c4abd9
			printf("blktrace: connected!\n");
Packit c4abd9
		if (stop_watch)
Packit c4abd9
			alarm(stop_watch);
Packit c4abd9
	} else
Packit c4abd9
		stop_tracers();
Packit c4abd9
Packit c4abd9
	wait_tracers();
Packit c4abd9
	if (nthreads_running == ncpus)
Packit c4abd9
		show_stats(&devpaths);
Packit c4abd9
	if (net_client_use_send())
Packit c4abd9
		close_client_connections();
Packit c4abd9
	del_tracers();
Packit c4abd9
Packit c4abd9
	return 0;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static cpu_set_t *get_online_cpus(void)
Packit c4abd9
{
Packit c4abd9
	FILE *cpus;
Packit c4abd9
	cpu_set_t *set;
Packit c4abd9
	size_t alloc_size;
Packit c4abd9
	int cpuid, prevcpuid = -1;
Packit c4abd9
	char nextch;
Packit c4abd9
	int n, ncpu, curcpu = 0;
Packit c4abd9
	int *cpu_nums;
Packit c4abd9
Packit c4abd9
	ncpu = sysconf(_SC_NPROCESSORS_CONF);
Packit c4abd9
	if (ncpu < 0)
Packit c4abd9
		return NULL;
Packit c4abd9
Packit c4abd9
	cpu_nums = malloc(sizeof(int)*ncpu);
Packit c4abd9
	if (!cpu_nums) {
Packit c4abd9
		errno = ENOMEM;
Packit c4abd9
		return NULL;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	/*
Packit c4abd9
	 * There is no way to easily get maximum CPU number. So we have to
Packit c4abd9
	 * parse the file first to find it out and then create appropriate
Packit c4abd9
	 * cpuset
Packit c4abd9
	 */
Packit c4abd9
	cpus = my_fopen("/sys/devices/system/cpu/online", "r");
Packit c4abd9
	for (;;) {
Packit c4abd9
		n = fscanf(cpus, "%d%c", &cpuid, &nextch);
Packit c4abd9
		if (n <= 0)
Packit c4abd9
			break;
Packit c4abd9
		if (n == 2 && nextch == '-') {
Packit c4abd9
			prevcpuid = cpuid;
Packit c4abd9
			continue;
Packit c4abd9
		}
Packit c4abd9
		if (prevcpuid == -1)
Packit c4abd9
			prevcpuid = cpuid;
Packit c4abd9
		while (prevcpuid <= cpuid) {
Packit c4abd9
			/* More CPUs listed than configured? */
Packit c4abd9
			if (curcpu >= ncpu) {
Packit c4abd9
				errno = EINVAL;
Packit c4abd9
				return NULL;
Packit c4abd9
			}
Packit c4abd9
			cpu_nums[curcpu++] = prevcpuid++;
Packit c4abd9
		}
Packit c4abd9
		prevcpuid = -1;
Packit c4abd9
	}
Packit c4abd9
	fclose(cpus);
Packit c4abd9
Packit c4abd9
	ncpu = curcpu;
Packit c4abd9
	max_cpus = cpu_nums[ncpu - 1] + 1;
Packit c4abd9
Packit c4abd9
	/* Now that we have maximum cpu number, create a cpuset */
Packit c4abd9
	set = CPU_ALLOC(max_cpus);
Packit c4abd9
	if (!set) {
Packit c4abd9
		errno = ENOMEM;
Packit c4abd9
		return NULL;
Packit c4abd9
	}
Packit c4abd9
	alloc_size = CPU_ALLOC_SIZE(max_cpus);
Packit c4abd9
	CPU_ZERO_S(alloc_size, set);
Packit c4abd9
Packit c4abd9
	for (curcpu = 0; curcpu < ncpu; curcpu++)
Packit c4abd9
		CPU_SET_S(cpu_nums[curcpu], alloc_size, set);
Packit c4abd9
Packit c4abd9
	free(cpu_nums);
Packit c4abd9
Packit c4abd9
	return set;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
int main(int argc, char *argv[])
Packit c4abd9
{
Packit c4abd9
	int ret = 0;
Packit c4abd9
Packit c4abd9
	setlocale(LC_NUMERIC, "en_US");
Packit c4abd9
	pagesize = getpagesize();
Packit c4abd9
	online_cpus = get_online_cpus();
Packit c4abd9
	if (!online_cpus) {
Packit c4abd9
		fprintf(stderr, "cannot get online cpus %d/%s\n",
Packit c4abd9
			errno, strerror(errno));
Packit c4abd9
		ret = 1;
Packit c4abd9
		goto out;
Packit c4abd9
	} else if (handle_args(argc, argv)) {
Packit c4abd9
		ret = 1;
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	ncpus = CPU_COUNT_S(CPU_ALLOC_SIZE(max_cpus), online_cpus);
Packit c4abd9
	if (ndevs > 1 && output_name && strcmp(output_name, "-") != 0) {
Packit c4abd9
		fprintf(stderr, "-o not supported with multiple devices\n");
Packit c4abd9
		ret = 1;
Packit c4abd9
		goto out;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	signal(SIGINT, handle_sigint);
Packit c4abd9
	signal(SIGHUP, handle_sigint);
Packit c4abd9
	signal(SIGTERM, handle_sigint);
Packit c4abd9
	signal(SIGALRM, handle_sigint);
Packit c4abd9
	signal(SIGPIPE, SIG_IGN);
Packit c4abd9
Packit c4abd9
	if (kill_running_trace) {
Packit c4abd9
		struct devpath *dpp;
Packit c4abd9
		struct list_head *p;
Packit c4abd9
Packit c4abd9
		__list_for_each(p, &devpaths) {
Packit c4abd9
			dpp = list_entry(p, struct devpath, head);
Packit c4abd9
			if (__stop_trace(dpp->fd)) {
Packit c4abd9
				fprintf(stderr,
Packit c4abd9
					"BLKTRACETEARDOWN %s failed: %d/%s\n",
Packit c4abd9
					dpp->path, errno, strerror(errno));
Packit c4abd9
			}
Packit c4abd9
		}
Packit c4abd9
	} else if (net_mode == Net_server) {
Packit c4abd9
		if (output_name) {
Packit c4abd9
			fprintf(stderr, "-o ignored in server mode\n");
Packit c4abd9
			output_name = NULL;
Packit c4abd9
		}
Packit c4abd9
		ret = net_server();
Packit c4abd9
	} else
Packit c4abd9
		ret = run_tracers();
Packit c4abd9
Packit c4abd9
out:
Packit c4abd9
	if (pfp)
Packit c4abd9
		fclose(pfp);
Packit c4abd9
	rel_devpaths();
Packit c4abd9
	return ret;
Packit c4abd9
}