Home | History | Annotate | Download | only in btt
      1 /*
      2  * blktrace output analysis: generate a timeline & gather statistics
      3  *
      4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle (at) hp.com>
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19  *
     20  */
     21 #include <errno.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <sys/time.h>
     28 #include <sys/resource.h>
     29 #include <fcntl.h>
     30 
     31 #define INLINE_DECLARE
     32 #include "globals.h"
     33 
     34 struct file_info {
     35 	struct list_head head;
     36 	FILE *ofp;
     37 	char *oname;
     38 };
     39 
     40 struct buf_info {
     41 	struct list_head head;
     42 	void *buf;
     43 };
     44 
     45 LIST_HEAD(files_to_clean);
     46 LIST_HEAD(all_bufs);
     47 
     48 static void clean_files(void)
     49 {
     50 	struct list_head *p, *q;
     51 
     52 	list_for_each_safe(p, q, &files_to_clean) {
     53 		struct stat buf;
     54 		struct file_info *fip = list_entry(p, struct file_info, head);
     55 
     56 		fclose(fip->ofp);
     57 		if (!stat(fip->oname, &buf) && (buf.st_size == 0))
     58 			unlink(fip->oname);
     59 
     60 		list_del(&fip->head);
     61 		free(fip->oname);
     62 		free(fip);
     63 	}
     64 }
     65 
     66 static void clean_bufs(void)
     67 {
     68 	struct list_head *p, *q;
     69 
     70 	list_for_each_safe(p, q, &all_bufs) {
     71 		struct buf_info *bip = list_entry(p, struct buf_info, head);
     72 
     73 		list_del(&bip->head);
     74 		free(bip->buf);
     75 		free(bip);
     76 	}
     77 }
     78 
     79 /*
     80  * Due to the N(devs) parts of a lot of the output features provided
     81  * by btt, it will fail opens on large(ish) systems. Here we try to
     82  * keep bumping our open file limits, and if those fail, we return NULL.
     83  *
     84  * Root users will probably be OK with this, others...
     85  */
     86 static int increase_limit(int resource, rlim_t increase)
     87 {
     88 	struct rlimit rlim;
     89 	int save_errno = errno;
     90 
     91 	if (!getrlimit(resource, &rlim)) {
     92 		rlim.rlim_cur += increase;
     93 		if (rlim.rlim_cur >= rlim.rlim_max)
     94 			rlim.rlim_max = rlim.rlim_cur + increase;
     95 
     96 		if (!setrlimit(resource, &rlim))
     97 			return 1;
     98 	}
     99 
    100 	errno = save_errno;
    101 	return 0;
    102 }
    103 
    104 static int handle_open_failure(void)
    105 {
    106 	if (errno == ENFILE || errno == EMFILE)
    107 		return increase_limit(RLIMIT_NOFILE, 16);
    108 
    109 	return 0;
    110 }
    111 
    112 void add_file(FILE *fp, char *oname)
    113 {
    114 	struct file_info *fip = malloc(sizeof(*fip));
    115 
    116 	fip->ofp = fp;
    117 	fip->oname = oname;
    118 	list_add_tail(&fip->head, &files_to_clean);
    119 }
    120 
    121 void add_buf(void *buf)
    122 {
    123 	struct buf_info *bip = malloc(sizeof(*bip));
    124 
    125 	bip->buf = buf;
    126 	list_add_tail(&bip->head, &all_bufs);
    127 }
    128 
    129 void clean_allocs(void)
    130 {
    131 	clean_files();
    132 	clean_bufs();
    133 }
    134 
    135 char *make_dev_hdr(char *pad, size_t len, struct d_info *dip, int add_parens)
    136 {
    137 	if (dip->devmap)
    138 		snprintf(pad, len, "%s", dip->devmap);
    139 	else if (add_parens)
    140 		snprintf(pad, len, "(%3d,%3d)",
    141 			 MAJOR(dip->device), MINOR(dip->device));
    142 	else
    143 		snprintf(pad, len, "%d,%d",
    144 			 MAJOR(dip->device), MINOR(dip->device));
    145 
    146 	return pad;
    147 }
    148 
    149 char *mkhandle(struct d_info *dip, char *str, size_t len)
    150 {
    151 	return make_dev_hdr(str, len, dip, 0);
    152 }
    153 
    154 FILE *my_fopen(const char *path, const char *mode)
    155 {
    156 	FILE *fp;
    157 
    158 	do {
    159 		fp = fopen(path, mode);
    160 	} while (fp == NULL && handle_open_failure());
    161 
    162 	return fp;
    163 }
    164 
    165 int my_open(const char *path, int flags)
    166 {
    167 	int fd;
    168 
    169 	do {
    170 		fd = open(path, flags);
    171 	} while (fd < 0 && handle_open_failure());
    172 
    173 	return fd;
    174 }
    175 
    176 void dbg_ping(void) {}
    177