Home | History | Annotate | Download | only in common
      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 }
    356