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