char *path; /* path to device special file */
char *buts_name; /* name returned from bt kernel code */
struct pdc_stats *stats;
- int fd, idx, ncpus;
+ int fd, ncpus;
unsigned long long drops;
/*
}
};
-static char usage_str[] = \
- "-d <dev> [ -r debugfs path ] [ -o <output> ] [-k ] [ -w time ]\n" \
- "[ -a action ] [ -A action mask ] [ -I <devs file> ] [ -v ]\n\n" \
+static char usage_str[] = "\n\n" \
+ "-d <dev> | --dev=<dev>\n" \
+ "[ -r <debugfs path> | --relay=<debugfs path> ]\n" \
+ "[ -o <file> | --output=<file>]\n" \
+ "[ -D <dir> | --output-dir=<dir>\n" \
+ "[ -w <time> | --stopwatch=<time>]\n" \
+ "[ -a <action field> | --act-mask=<action field>]\n" \
+ "[ -A <action mask> | --set-mask=<action mask>]\n" \
+ "[ -b <size> | --buffer-size]\n" \
+ "[ -n <number> | --num-sub-buffers=<number>]\n" \
+ "[ -l | --listen]\n" \
+ "[ -h <hostname> | --host=<hostname>]\n" \
+ "[ -p <port number> | --port=<port number>]\n" \
+ "[ -s | --no-sendfile]\n" \
+ "[ -I <devs file> | --input-devs=<devs file>]\n" \
+ "[ -v <version> | --version]\n" \
+ "[ -V <version> | --version]\n" \
+
"\t-d Use specified device. May also be given last after options\n" \
"\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
"\t-o File(s) to send output to\n" \
"\t-D Directory to prepend to output file names\n" \
- "\t-k Kill a running trace\n" \
"\t-w Stop after defined time, in seconds\n" \
"\t-a Only trace specified actions. See documentation\n" \
"\t-A Give trace mask as a single value. See documentation\n" \
- "\t-b Sub buffer size in KiB\n" \
- "\t-n Number of sub buffers\n" \
+ "\t-b Sub buffer size in KiB (default 512)\n" \
+ "\t-n Number of sub buffers (default 4)\n" \
"\t-l Run in network listen mode (blktrace server)\n" \
"\t-h Run in network client mode, connecting to the given host\n" \
"\t-p Network port to use (default 8462)\n" \
"\t-s Make the network client NOT use sendfile() to transfer data\n" \
"\t-I Add devices found in <devs file>\n" \
+ "\t-v Print program version info\n" \
"\t-V Print program version info\n\n";
static void clear_events(struct pollfd *pfd)
static void show_usage(char *prog)
{
- fprintf(stderr, "Usage: %s %s %s", prog, blktrace_version, usage_str);
+ fprintf(stderr, "Usage: %s %s", prog, usage_str);
}
/*
static int lock_on_cpu(int cpu)
{
- cpu_set_t cpu_mask;
+ cpu_set_t * cpu_mask;
+ size_t size;
+ cpu_mask = CPU_ALLOC(ncpus);
+ size = CPU_ALLOC_SIZE(ncpus);
- CPU_ZERO(&cpu_mask);
- CPU_SET(cpu, &cpu_mask);
- if (sched_setaffinity(getpid(), sizeof(cpu_mask), &cpu_mask) < 0)
+ CPU_ZERO_S(size, cpu_mask);
+ CPU_SET_S(cpu, size, cpu_mask);
+ if (sched_setaffinity(0, size, cpu_mask) < 0) {
+ CPU_FREE(cpu_mask);
return errno;
+ }
+ CPU_FREE(cpu_mask);
return 0;
}
return new;
}
-static int my_mlock(const void *addr, size_t len)
+static int my_mlock(struct tracer *tp,
+ const void *addr, size_t len)
{
- int ret;
+ int ret, retry = 0;
do {
ret = mlock(addr, len);
+ if ((retry >= 10) && tp && tp->is_done)
+ break;
+ retry++;
} while (ret < 0 && handle_mem_failure(len));
return ret;
}
-static int setup_mmap(int fd, unsigned int maxlen, struct mmap_info *mip)
+static int setup_mmap(int fd, unsigned int maxlen,
+ struct mmap_info *mip,
+ struct tracer *tp)
{
if (mip->fs_off + maxlen > mip->fs_buf_len) {
unsigned long nr = max(16, mip->buf_nr);
perror("setup_mmap: mmap");
return 1;
}
- my_mlock(mip->fs_buf, mip->fs_buf_len);
+ if (my_mlock(tp, mip->fs_buf, mip->fs_buf_len) < 0) {
+ perror("setup_mlock: mlock");
+ return 1;
+ }
}
return 0;
memset(&hdr, 0, sizeof(hdr));
hdr.magic = BLK_IO_TRACE_MAGIC;
+ memset(hdr.buts_name, 0, sizeof(hdr.buts_name));
strncpy(hdr.buts_name, buts_name, sizeof(hdr.buts_name));
- hdr.buts_name[sizeof(hdr.buts_name)-1] = '\0';
+ hdr.buts_name[sizeof(hdr.buts_name) - 1] = '\0';
hdr.cpu = cpu;
hdr.max_cpus = ncpus;
hdr.len = len;
}
memcpy(&addr->sin_addr, hent->h_addr, 4);
- strcpy(hostname, hent->h_name);
+ memset(hostname, 0, sizeof(hostname));
+ strncpy(hostname, hent->h_name, sizeof(hostname));
+ hostname[sizeof(hostname) - 1] = '\0';
}
return 0;
{
int fd;
struct devpath *dpp;
+ struct list_head *p;
+ /*
+ * Verify device is not duplicated
+ */
+ __list_for_each(p, &devpaths) {
+ struct devpath *tmp = list_entry(p, struct devpath, head);
+ if (!strcmp(tmp->path, path))
+ return 0;
+ }
/*
* Verify device is valid before going too far
*/
memset(dpp, 0, sizeof(*dpp));
dpp->path = strdup(path);
dpp->fd = fd;
- dpp->idx = ndevs++;
+ ndevs++;
list_add_tail(&dpp->head, &devpaths);
return 0;
* the whole structures, as the other fields
* are "static".
*/
- prev = realloc(prev->buf, sizeof(*prev) + tot_len);
+ prev = realloc(prev, sizeof(*prev) + tot_len);
prev->buf = (void *)(prev + 1);
}
iop->ofn, errno, strerror(errno));
return 1;
}
- if (mkdir(iop->ofn, 0755) < 0) {
+ /*
+ * There is no synchronization between multiple threads
+ * trying to create the directory at once. It's harmless
+ * to let them try, so just detect the problem and move on.
+ */
+ if (mkdir(iop->ofn, 0755) < 0 && errno != EEXIST) {
fprintf(stderr,
"Destination dir %s can't be made: %d/%s\n",
iop->ofn, errno, strerror(errno));
if (pfd->revents & POLLIN || force_read) {
mip = &iop->mmap_info;
- ret = setup_mmap(iop->ofd, buf_size, mip);
+ ret = setup_mmap(iop->ofd, buf_size, mip, tp);
if (ret < 0) {
pfd->events = 0;
break;
{
struct stat sb;
int i, nentries = 0;
- struct pdc_stats *sp;
struct pollfd *pfd = tp->pfds;
struct io_info *iop = tp->ios;
- for (i = 0; i < ndevs; i++, pfd++, iop++, sp++) {
+ for (i = 0; i < ndevs; i++, pfd++, iop++) {
if (pfd->revents & POLLIN || force_read) {
if (fstat(iop->ifd, &sb) < 0) {
perror(iop->ifn);
struct tracer *tp = list_entry(p, struct tracer, head);
tp->is_done = 1;
}
+ pthread_cond_broadcast(&mt_cond);
}
static void del_tracers(void)
return 1;
}
- while (fscanf(ifp, "%s\n", dev_line) == 1)
- if (add_devpath(dev_line) != 0)
+ while (fscanf(ifp, "%s\n", dev_line) == 1) {
+ if (add_devpath(dev_line) != 0) {
+ fclose(ifp);
return 1;
+ }
+ }
+ fclose(ifp);
break;
}
break;
case 'h':
net_mode = Net_client;
- strcpy(hostname, optarg);
+ memset(hostname, 0, sizeof(hostname));
+ strncpy(hostname, optarg, sizeof(hostname));
+ hostname[sizeof(hostname) - 1] = '\0';
break;
case 'l':
net_mode = Net_server;
return 1;
}
- if (statfs(debugfs_path, &st) < 0 || st.f_type != (long)DEBUGFS_TYPE) {
+ if (statfs(debugfs_path, &st) < 0) {
fprintf(stderr, "Invalid debug path %s: %d/%s\n",
debugfs_path, errno, strerror(errno));
return 1;
}
+ if (st.f_type != (long)DEBUGFS_TYPE) {
+ fprintf(stderr, "Debugfs is not mounted at %s\n", debugfs_path);
+ return 1;
+ }
+
if (act_mask_tmp != 0)
act_mask = act_mask_tmp;
piped_output = 1;
handle_pfds = handle_pfds_entries;
pfp = stdout;
- setvbuf(pfp, NULL, _IONBF, 0);
+ if (setvbuf(pfp, NULL, _IONBF, 0)) {
+ perror("setvbuf stdout");
+ return 1;
+ }
} else
handle_pfds = handle_pfds_file;
return 0;
struct io_info *iop = &dpp->ios[bnh->cpu];
struct mmap_info *mip = &iop->mmap_info;
- if (setup_mmap(iop->ofd, bnh->len, &iop->mmap_info)) {
+ if (setup_mmap(iop->ofd, bnh->len, &iop->mmap_info, NULL)) {
fprintf(stderr, "ncd(%s:%d): mmap failed\n",
nc->ch->hostname, nc->fd);
exit(1);
goto out;
}
+ if (ndevs > 1 && output_name && strcmp(output_name, "-") != 0) {
+ fprintf(stderr, "-o not supported with multiple devices\n");
+ ret = 1;
+ goto out;
+ }
+
signal(SIGINT, handle_sigint);
signal(SIGHUP, handle_sigint);
signal(SIGTERM, handle_sigint);