Check setvbuf return value
[blktrace.git] / blktrace.c
index 656ab7a811ad8575f357c69d8d200cb7e982bd34..49cfca61352ddca5233f669e76edb1bea54f84e2 100644 (file)
@@ -93,7 +93,7 @@ struct devpath {
        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;
 
        /*
@@ -435,24 +435,39 @@ static struct option l_opts[] = {
        }
 };
 
-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)
@@ -493,7 +508,7 @@ static inline void pdc_nev_update(struct devpath *dpp, int cpu, int nevents)
 
 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);
 }
 
 /*
@@ -706,18 +721,24 @@ static void *my_mmap(void *addr, size_t length, int prot, int flags, int fd,
        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);
@@ -744,7 +765,10 @@ static int setup_mmap(int fd, unsigned int maxlen, struct mmap_info *mip)
                        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;
@@ -1200,7 +1224,16 @@ static int add_devpath(char *path)
 {
        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
         */
@@ -1215,7 +1248,7 @@ static int add_devpath(char *path)
        memset(dpp, 0, sizeof(*dpp));
        dpp->path = strdup(path);
        dpp->fd = fd;
-       dpp->idx = ndevs++;
+       ndevs++;
        list_add_tail(&dpp->head, &devpaths);
 
        return 0;
@@ -1297,7 +1330,7 @@ static struct trace_buf *tb_combine(struct trace_buf *prev,
                 * 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);
        }
 
@@ -1477,7 +1510,12 @@ static int fill_ofname(struct io_info *iop, int cpu)
                                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));
@@ -1654,7 +1692,7 @@ static int handle_pfds_file(struct tracer *tp, int nevs, int force_read)
                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;
@@ -2117,12 +2155,17 @@ static int handle_args(int argc, char *argv[])
                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;
 
@@ -2140,7 +2183,10 @@ static int handle_args(int argc, char *argv[])
                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;
@@ -2352,7 +2398,7 @@ static void net_client_read_data(struct cl_conn *nc, struct devpath *dpp,
        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);
@@ -2613,6 +2659,12 @@ int main(int argc, char *argv[])
                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);