1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1996-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * 31 * stats_dbm.c 32 * 33 * Routines for dbm access. 34 */ 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <stddef.h> 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <fcntl.h> 42 #include <libintl.h> 43 #include <time.h> 44 #include <string.h> 45 #include <sys/fs/cachefs_fs.h> 46 #include "stats.h" 47 #include <assert.h> 48 #include <ndbm.h> 49 50 void 51 stats_dbm_open(stats_cookie_t *st) 52 { 53 char *tmpdir; 54 pid_t getpid(); 55 56 assert(stats_good(st)); 57 assert(! (st->st_flags & ST_DBMOPEN)); 58 59 if ((tmpdir = getenv("TMPDIR")) == NULL) 60 tmpdir = "/tmp"; 61 62 (void) snprintf(st->st_dbm_name, sizeof (st->st_dbm_name), "%s/%s-%d", 63 tmpdir, st->st_progname, getpid()); 64 st->st_dbm = dbm_open(st->st_dbm_name, O_RDWR | O_CREAT, 0666); 65 if (st->st_dbm == NULL) { 66 stats_perror(st, SE_FILE, 67 gettext("Cannot open dbm file %s"), st->st_dbm_name); 68 return; 69 } 70 71 st->st_flags |= ST_DBMOPEN; 72 } 73 74 void 75 stats_dbm_rm(stats_cookie_t *st) 76 { 77 char buffy[MAXPATHLEN], *eobase; 78 int unlink(), buflen, eobaselen; 79 80 assert(stats_good(st)); 81 82 if (! (st->st_flags & ST_DBMOPEN)) 83 return; 84 85 if (strlcpy(buffy, st->st_dbm_name, sizeof (buffy)) > 86 ((sizeof (buffy)) - (sizeof (".xxx")))) 87 return; /* No space for the file extensions */ 88 buflen = strlen(buffy); 89 eobase = buffy + buflen; 90 eobaselen = (sizeof (buffy)) - buflen; 91 92 (void) strlcpy(eobase, ".dir", eobaselen); 93 (void) unlink(buffy); 94 95 (void) strlcpy(eobase, ".pag", eobaselen); 96 (void) unlink(buffy); 97 } 98 99 void 100 stats_dbm_close(stats_cookie_t *st) 101 { 102 assert(stats_good(st)); 103 104 if (! (st->st_flags & ST_DBMOPEN)) 105 return; 106 107 st->st_flags &= ~ST_DBMOPEN; 108 109 if (st->st_dbm == NULL) 110 return; 111 112 dbm_close(st->st_dbm); 113 } 114 115 fid_info * 116 stats_dbm_fetch_byfid(stats_cookie_t *st, cfs_fid_t *fidp) 117 { 118 datum key, value; 119 fid_info *rc; 120 121 assert(stats_good(st)); 122 assert(st->st_flags & ST_DBMOPEN); 123 124 key.dptr = (char *)fidp; 125 key.dsize = sizeof (*fidp); 126 value = dbm_fetch(st->st_dbm, key); 127 128 assert((value.dptr == NULL) || (value.dsize == sizeof (fid_info))); 129 if (value.dptr == NULL) 130 return (NULL); 131 132 if ((rc = malloc(sizeof (*rc))) == NULL) { 133 stats_perror(st, SE_NOMEM, 134 gettext("Cannot malloc memory for fid_info record")); 135 return (NULL); 136 } 137 138 memcpy(rc, value.dptr, sizeof (*rc)); 139 if (rc->fi_magic != FI_MAGIC) { 140 free(rc); 141 return (NULL); 142 } 143 144 return (rc); 145 } 146 147 void 148 stats_dbm_store_byfid(stats_cookie_t *st, cfs_fid_t *fidp, fid_info *fi) 149 { 150 datum key, value; 151 152 assert(stats_good(st)); 153 assert(st->st_flags & ST_DBMOPEN); 154 155 fi->fi_magic = FI_MAGIC; 156 157 key.dptr = (char *)fidp; 158 key.dsize = sizeof (*fidp); 159 160 value.dptr = (char *)fi; 161 value.dsize = sizeof (*fi); 162 163 if (dbm_store(st->st_dbm, key, value, DBM_REPLACE) != 0) { 164 stats_perror(st, SE_FILE, 165 gettext("Cannot store fid info")); 166 return; 167 } 168 } 169 170 mount_info * 171 stats_dbm_fetch_byvfsp(stats_cookie_t *st, caddr_t vfsp) 172 { 173 mount_info *rc, *mi; 174 int len1, len2, size; 175 176 datum key, value; 177 178 assert(stats_good(st)); 179 assert(st->st_flags & ST_DBMOPEN); 180 181 key.dptr = (char *)&vfsp; 182 key.dsize = sizeof (vfsp); 183 value = dbm_fetch(st->st_dbm, key); 184 185 if (value.dptr == NULL) 186 return (NULL); 187 188 mi = (mount_info *)value.dptr; 189 190 len1 = strlen(mi->mi_path); 191 len2 = strlen(mi->mi_path + len1 + 1); 192 size = sizeof (*rc) + len1 + len2 - CLPAD(mount_info, mi_path); 193 194 if ((rc = malloc(size)) == NULL) { 195 stats_perror(st, SE_NOMEM, 196 gettext("Cannot malloc memory for mountinfo")); 197 return (NULL); 198 } 199 memcpy(rc, mi, size); 200 201 if (rc->mi_magic != MI_MAGIC) { 202 free(rc); 203 return (NULL); 204 } 205 206 return (rc); 207 } 208 209 void 210 stats_dbm_store_byvfsp(stats_cookie_t *st, caddr_t vfsp, mount_info *mi) 211 { 212 datum key, value; 213 int len1, len2; 214 215 assert(stats_good(st)); 216 assert(st->st_flags & ST_DBMOPEN); 217 218 mi->mi_magic = MI_MAGIC; 219 220 key.dptr = (char *)&vfsp; 221 key.dsize = sizeof (vfsp); 222 223 len1 = strlen(mi->mi_path); 224 len2 = strlen(mi->mi_path + len1 + 1); 225 value.dptr = (char *)mi; 226 value.dsize = sizeof (*mi) + 227 len1 + len2 - 228 CLPAD(mount_info, mi_path); 229 230 if (dbm_store(st->st_dbm, key, value, DBM_REPLACE) != 0) { 231 stats_perror(st, SE_FILE, 232 gettext("Cannot store mount info")); 233 return; 234 } 235 } 236 237 void 238 stats_dbm_delete_byvfsp(stats_cookie_t *st, caddr_t vfsp) 239 { 240 datum key; 241 242 assert(stats_good(st)); 243 assert(st->st_flags & ST_DBMOPEN); 244 245 key.dptr = (caddr_t)&vfsp; 246 key.dsize = sizeof (vfsp); 247 248 (void) dbm_delete(st->st_dbm, key); 249 } 250 251 datum 252 stats_dbm_firstkey(stats_cookie_t *st) 253 { 254 assert(stats_good(st)); 255 assert(st->st_flags & ST_DBMOPEN); 256 257 return (dbm_firstkey(st->st_dbm)); 258 } 259 260 datum 261 stats_dbm_nextkey(stats_cookie_t *st) 262 { 263 assert(stats_good(st)); 264 assert(st->st_flags & ST_DBMOPEN); 265 266 return (dbm_nextkey(st->st_dbm)); 267 } 268 269 /* 270 * count var will be non-zero only for the record type CACHEFS_LOG_MDCREATE 271 * and count can't be >2GB because it refers to the number of entries in 272 * the attribute cache file. 273 */ 274 size_t 275 stats_dbm_attrcache_addsize(stats_cookie_t *st, mount_info *mi, 276 ino64_t fileno, uint_t count) 277 { 278 char keystring[BUFSIZ]; 279 datum key, value; 280 char *cacheid; 281 fg_info fg, *fgp = NULL; 282 size_t size = 0, overhead = 0; 283 uchar_t tbits; 284 int i; 285 uint_t gfileno; 286 287 assert(stats_good(st)); 288 assert(st->st_flags & ST_DBMOPEN); 289 290 /* look up any known data about this filegrp */ 291 cacheid = mi->mi_path + strlen(mi->mi_path) + 1; 292 (void) snprintf(keystring, sizeof (keystring), "%s.%lld", cacheid, 293 fileno / (ino64_t)mi->mi_filegrp_size); 294 gfileno = (uint_t)(fileno % (ino64_t)mi->mi_filegrp_size); 295 key.dsize = strlen(keystring); /* no need to null terminate */ 296 key.dptr = keystring; 297 value = dbm_fetch(st->st_dbm, key); 298 299 size = sizeof (struct attrcache_header); 300 size += mi->mi_filegrp_size * sizeof (struct attrcache_index); 301 size += mi->mi_filegrp_size / NBBY; 302 303 if ((value.dptr != NULL) && (value.dsize == sizeof (fg))) { 304 /* align the structure */ 305 memcpy((char *)&fg, value.dptr, sizeof (fg)); 306 fgp = &fg; 307 if (fgp->fg_magic != FG_MAGIC) 308 fgp = NULL; /* oops -- key collision! */ 309 } 310 311 /* if we haven't seen this filegrp yet */ 312 if (fgp == NULL) { 313 memset((char *)&fg, '\0', sizeof (fg)); 314 fgp = &fg; 315 fgp->fg_magic = FG_MAGIC; 316 317 /* filegrp frontfile directory */ 318 overhead += st->st_loghead.lh_maxbsize; 319 } 320 321 /* high-water the given count (if any) with our known count */ 322 if (count > fgp->fg_count) 323 fgp->fg_count = count; 324 325 /* set a bit for this file */ 326 if ((gfileno / NBBY) < sizeof (fgp->fg_bits)) { 327 tbits = 1 << (gfileno % NBBY); 328 if (! (fgp->fg_bits[gfileno / NBBY] & tbits)) 329 fgp->fg_bcount++; 330 fgp->fg_bits[gfileno / NBBY] |= tbits; 331 } 332 333 /* high-water our derived count with our known count */ 334 if (fgp->fg_bcount > fgp->fg_count) 335 fgp->fg_count = fgp->fg_bcount; 336 337 /* account for the size of all known attrcache entries */ 338 size += fgp->fg_count * sizeof (struct cachefs_metadata); 339 340 /* round to the ceiling block boundary */ 341 size += st->st_loghead.lh_maxbsize - 1; 342 size &= ~ (st->st_loghead.lh_maxbsize - 1); 343 344 /* sneaky :-) -- high-water fg_size, and make size the delta */ 345 size -= fgp->fg_size; 346 fgp->fg_size += size; 347 348 value.dptr = (char *)fgp; 349 value.dsize = sizeof (*fgp); 350 if (dbm_store(st->st_dbm, key, value, DBM_REPLACE) != 0) 351 stats_perror(st, SE_FILE, 352 gettext("Cannot store attrcache info")); 353 354 return (size + overhead); 355 }