1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/dbm/src/hash_buf.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,410 @@ 1.4 +/*- 1.5 + * Copyright (c) 1990, 1993, 1994 1.6 + * The Regents of the University of California. All rights reserved. 1.7 + * 1.8 + * This code is derived from software contributed to Berkeley by 1.9 + * Margo Seltzer. 1.10 + * 1.11 + * Redistribution and use in source and binary forms, with or without 1.12 + * modification, are permitted provided that the following conditions 1.13 + * are met: 1.14 + * 1. Redistributions of source code must retain the above copyright 1.15 + * notice, this list of conditions and the following disclaimer. 1.16 + * 2. Redistributions in binary form must reproduce the above copyright 1.17 + * notice, this list of conditions and the following disclaimer in the 1.18 + * documentation and/or other materials provided with the distribution. 1.19 + * 3. ***REMOVED*** - see 1.20 + * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change 1.21 + * 4. Neither the name of the University nor the names of its contributors 1.22 + * may be used to endorse or promote products derived from this software 1.23 + * without specific prior written permission. 1.24 + * 1.25 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1.26 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.27 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.28 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1.29 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1.30 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1.31 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1.32 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1.33 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1.34 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.35 + * SUCH DAMAGE. 1.36 + */ 1.37 + 1.38 +#if defined(LIBC_SCCS) && !defined(lint) 1.39 +static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94"; 1.40 +#endif /* LIBC_SCCS and not lint */ 1.41 + 1.42 +/* 1.43 + * PACKAGE: hash 1.44 + * 1.45 + * DESCRIPTION: 1.46 + * Contains buffer management 1.47 + * 1.48 + * ROUTINES: 1.49 + * External 1.50 + * __buf_init 1.51 + * __get_buf 1.52 + * __buf_free 1.53 + * __reclaim_buf 1.54 + * Internal 1.55 + * newbuf 1.56 + */ 1.57 +#if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) 1.58 +#include <sys/param.h> 1.59 +#endif 1.60 + 1.61 +#include <errno.h> 1.62 +#include <stddef.h> 1.63 +#include <stdio.h> 1.64 +#include <stdlib.h> 1.65 +#include <string.h> 1.66 + 1.67 +#ifdef DEBUG 1.68 +#include <assert.h> 1.69 +#endif 1.70 + 1.71 +#include "mcom_db.h" 1.72 +#include "hash.h" 1.73 +#include "page.h" 1.74 +/* #include "extern.h" */ 1.75 + 1.76 +static BUFHEAD *newbuf __P((HTAB *, uint32, BUFHEAD *)); 1.77 + 1.78 +/* Unlink B from its place in the lru */ 1.79 +#define BUF_REMOVE(B) { \ 1.80 + (B)->prev->next = (B)->next; \ 1.81 + (B)->next->prev = (B)->prev; \ 1.82 +} 1.83 + 1.84 +/* Insert B after P */ 1.85 +#define BUF_INSERT(B, P) { \ 1.86 + (B)->next = (P)->next; \ 1.87 + (B)->prev = (P); \ 1.88 + (P)->next = (B); \ 1.89 + (B)->next->prev = (B); \ 1.90 +} 1.91 + 1.92 +#define MRU hashp->bufhead.next 1.93 +#define LRU hashp->bufhead.prev 1.94 + 1.95 +#define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead) 1.96 +#define LRU_INSERT(B) BUF_INSERT((B), LRU) 1.97 + 1.98 +/* 1.99 + * We are looking for a buffer with address "addr". If prev_bp is NULL, then 1.100 + * address is a bucket index. If prev_bp is not NULL, then it points to the 1.101 + * page previous to an overflow page that we are trying to find. 1.102 + * 1.103 + * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer 1.104 + * be valid. Therefore, you must always verify that its address matches the 1.105 + * address you are seeking. 1.106 + */ 1.107 +extern BUFHEAD * 1.108 +__get_buf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp, int newpage) 1.109 +/* If prev_bp set, indicates a new overflow page. */ 1.110 +{ 1.111 + register BUFHEAD *bp; 1.112 + register uint32 is_disk_mask; 1.113 + register int is_disk, segment_ndx = 0; 1.114 + SEGMENT segp = 0; 1.115 + 1.116 + is_disk = 0; 1.117 + is_disk_mask = 0; 1.118 + if (prev_bp) { 1.119 + bp = prev_bp->ovfl; 1.120 + if (!bp || (bp->addr != addr)) 1.121 + bp = NULL; 1.122 + if (!newpage) 1.123 + is_disk = BUF_DISK; 1.124 + } else { 1.125 + /* Grab buffer out of directory */ 1.126 + segment_ndx = addr & (hashp->SGSIZE - 1); 1.127 + 1.128 + /* valid segment ensured by __call_hash() */ 1.129 + segp = hashp->dir[addr >> hashp->SSHIFT]; 1.130 +#ifdef DEBUG 1.131 + assert(segp != NULL); 1.132 +#endif 1.133 + 1.134 + bp = PTROF(segp[segment_ndx]); 1.135 + 1.136 + is_disk_mask = ISDISK(segp[segment_ndx]); 1.137 + is_disk = is_disk_mask || !hashp->new_file; 1.138 + } 1.139 + 1.140 + if (!bp) { 1.141 + bp = newbuf(hashp, addr, prev_bp); 1.142 + if (!bp) 1.143 + return(NULL); 1.144 + if(__get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0)) 1.145 + { 1.146 + /* free bp and its page */ 1.147 + if(prev_bp) 1.148 + { 1.149 + /* if prev_bp is set then the new page that 1.150 + * failed is hooked onto prev_bp as an overflow page. 1.151 + * if we don't remove the pointer to the bad page 1.152 + * we may try and access it later and we will die 1.153 + * horribly because it will have already been 1.154 + * free'd and overwritten with bogus data. 1.155 + */ 1.156 + prev_bp->ovfl = NULL; 1.157 + } 1.158 + BUF_REMOVE(bp); 1.159 + free(bp->page); 1.160 + free(bp); 1.161 + return (NULL); 1.162 + } 1.163 + 1.164 + if (!prev_bp) 1.165 + { 1.166 +#if 0 1.167 + /* 16 bit windows and mac can't handle the 1.168 + * oring of the is disk flag. 1.169 + */ 1.170 + segp[segment_ndx] = 1.171 + (BUFHEAD *)((ptrdiff_t)bp | is_disk_mask); 1.172 +#else 1.173 + /* set the is_disk thing inside the structure 1.174 + */ 1.175 + bp->is_disk = is_disk_mask; 1.176 + segp[segment_ndx] = bp; 1.177 +#endif 1.178 + } 1.179 + } else { 1.180 + BUF_REMOVE(bp); 1.181 + MRU_INSERT(bp); 1.182 + } 1.183 + return (bp); 1.184 +} 1.185 + 1.186 +/* 1.187 + * We need a buffer for this page. Either allocate one, or evict a resident 1.188 + * one (if we have as many buffers as we're allowed) and put this one in. 1.189 + * 1.190 + * If newbuf finds an error (returning NULL), it also sets errno. 1.191 + */ 1.192 +static BUFHEAD * 1.193 +newbuf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp) 1.194 +{ 1.195 + register BUFHEAD *bp; /* The buffer we're going to use */ 1.196 + register BUFHEAD *xbp; /* Temp pointer */ 1.197 + register BUFHEAD *next_xbp; 1.198 + SEGMENT segp; 1.199 + int segment_ndx; 1.200 + uint16 oaddr, *shortp; 1.201 + 1.202 + oaddr = 0; 1.203 + bp = LRU; 1.204 + /* 1.205 + * If LRU buffer is pinned, the buffer pool is too small. We need to 1.206 + * allocate more buffers. 1.207 + */ 1.208 + if (hashp->nbufs || (bp->flags & BUF_PIN)) { 1.209 + /* Allocate a new one */ 1.210 + if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL) 1.211 + return (NULL); 1.212 + 1.213 + /* this memset is supposedly unnecessary but lets add 1.214 + * it anyways. 1.215 + */ 1.216 + memset(bp, 0xff, sizeof(BUFHEAD)); 1.217 + 1.218 + if ((bp->page = (char *)malloc((size_t)hashp->BSIZE)) == NULL) { 1.219 + free(bp); 1.220 + return (NULL); 1.221 + } 1.222 + 1.223 + /* this memset is supposedly unnecessary but lets add 1.224 + * it anyways. 1.225 + */ 1.226 + memset(bp->page, 0xff, (size_t)hashp->BSIZE); 1.227 + 1.228 + if (hashp->nbufs) 1.229 + hashp->nbufs--; 1.230 + } else { 1.231 + /* Kick someone out */ 1.232 + BUF_REMOVE(bp); 1.233 + /* 1.234 + * If this is an overflow page with addr 0, it's already been 1.235 + * flushed back in an overflow chain and initialized. 1.236 + */ 1.237 + if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) { 1.238 + /* 1.239 + * Set oaddr before __put_page so that you get it 1.240 + * before bytes are swapped. 1.241 + */ 1.242 + shortp = (uint16 *)bp->page; 1.243 + if (shortp[0]) 1.244 + { 1.245 + if(shortp[0] > (hashp->BSIZE / sizeof(uint16))) 1.246 + { 1.247 + return(NULL); 1.248 + } 1.249 + oaddr = shortp[shortp[0] - 1]; 1.250 + } 1.251 + if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page, 1.252 + bp->addr, (int)IS_BUCKET(bp->flags), 0)) 1.253 + return (NULL); 1.254 + /* 1.255 + * Update the pointer to this page (i.e. invalidate it). 1.256 + * 1.257 + * If this is a new file (i.e. we created it at open 1.258 + * time), make sure that we mark pages which have been 1.259 + * written to disk so we retrieve them from disk later, 1.260 + * rather than allocating new pages. 1.261 + */ 1.262 + if (IS_BUCKET(bp->flags)) { 1.263 + segment_ndx = bp->addr & (hashp->SGSIZE - 1); 1.264 + segp = hashp->dir[bp->addr >> hashp->SSHIFT]; 1.265 +#ifdef DEBUG 1.266 + assert(segp != NULL); 1.267 +#endif 1.268 + 1.269 + if (hashp->new_file && 1.270 + ((bp->flags & BUF_MOD) || 1.271 + ISDISK(segp[segment_ndx]))) 1.272 + segp[segment_ndx] = (BUFHEAD *)BUF_DISK; 1.273 + else 1.274 + segp[segment_ndx] = NULL; 1.275 + } 1.276 + /* 1.277 + * Since overflow pages can only be access by means of 1.278 + * their bucket, free overflow pages associated with 1.279 + * this bucket. 1.280 + */ 1.281 + for (xbp = bp; xbp->ovfl;) { 1.282 + next_xbp = xbp->ovfl; 1.283 + xbp->ovfl = 0; 1.284 + xbp = next_xbp; 1.285 + 1.286 + /* leave pinned pages alone, we are still using 1.287 + * them. */ 1.288 + if (xbp->flags & BUF_PIN) { 1.289 + continue; 1.290 + } 1.291 + 1.292 + /* Check that ovfl pointer is up date. */ 1.293 + if (IS_BUCKET(xbp->flags) || 1.294 + (oaddr != xbp->addr)) 1.295 + break; 1.296 + 1.297 + shortp = (uint16 *)xbp->page; 1.298 + if (shortp[0]) 1.299 + { 1.300 + /* LJM is the number of reported 1.301 + * pages way too much? 1.302 + */ 1.303 + if(shortp[0] > hashp->BSIZE/sizeof(uint16)) 1.304 + return NULL; 1.305 + /* set before __put_page */ 1.306 + oaddr = shortp[shortp[0] - 1]; 1.307 + } 1.308 + if ((xbp->flags & BUF_MOD) && __put_page(hashp, 1.309 + xbp->page, xbp->addr, 0, 0)) 1.310 + return (NULL); 1.311 + xbp->addr = 0; 1.312 + xbp->flags = 0; 1.313 + BUF_REMOVE(xbp); 1.314 + LRU_INSERT(xbp); 1.315 + } 1.316 + } 1.317 + } 1.318 + 1.319 + /* Now assign this buffer */ 1.320 + bp->addr = addr; 1.321 +#ifdef DEBUG1 1.322 + (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n", 1.323 + bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0); 1.324 +#endif 1.325 + bp->ovfl = NULL; 1.326 + if (prev_bp) { 1.327 + /* 1.328 + * If prev_bp is set, this is an overflow page, hook it in to 1.329 + * the buffer overflow links. 1.330 + */ 1.331 +#ifdef DEBUG1 1.332 + (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n", 1.333 + prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0), 1.334 + (bp ? bp->addr : 0)); 1.335 +#endif 1.336 + prev_bp->ovfl = bp; 1.337 + bp->flags = 0; 1.338 + } else 1.339 + bp->flags = BUF_BUCKET; 1.340 + MRU_INSERT(bp); 1.341 + return (bp); 1.342 +} 1.343 + 1.344 +extern void __buf_init(HTAB *hashp, int32 nbytes) 1.345 +{ 1.346 + BUFHEAD *bfp; 1.347 + int npages; 1.348 + 1.349 + bfp = &(hashp->bufhead); 1.350 + npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT; 1.351 + npages = PR_MAX(npages, MIN_BUFFERS); 1.352 + 1.353 + hashp->nbufs = npages; 1.354 + bfp->next = bfp; 1.355 + bfp->prev = bfp; 1.356 + /* 1.357 + * This space is calloc'd so these are already null. 1.358 + * 1.359 + * bfp->ovfl = NULL; 1.360 + * bfp->flags = 0; 1.361 + * bfp->page = NULL; 1.362 + * bfp->addr = 0; 1.363 + */ 1.364 +} 1.365 + 1.366 +extern int 1.367 +__buf_free(HTAB *hashp, int do_free, int to_disk) 1.368 +{ 1.369 + BUFHEAD *bp; 1.370 + int status = -1; 1.371 + 1.372 + /* Need to make sure that buffer manager has been initialized */ 1.373 + if (!LRU) 1.374 + return (0); 1.375 + for (bp = LRU; bp != &hashp->bufhead;) { 1.376 + /* Check that the buffer is valid */ 1.377 + if (bp->addr || IS_BUCKET(bp->flags)) { 1.378 + if (to_disk && (bp->flags & BUF_MOD) && 1.379 + (status = __put_page(hashp, bp->page, 1.380 + bp->addr, IS_BUCKET(bp->flags), 0))) { 1.381 + 1.382 + if (do_free) { 1.383 + if (bp->page) 1.384 + free(bp->page); 1.385 + BUF_REMOVE(bp); 1.386 + free(bp); 1.387 + } 1.388 + 1.389 + return (status); 1.390 + } 1.391 + } 1.392 + /* Check if we are freeing stuff */ 1.393 + if (do_free) { 1.394 + if (bp->page) 1.395 + free(bp->page); 1.396 + BUF_REMOVE(bp); 1.397 + free(bp); 1.398 + bp = LRU; 1.399 + } else 1.400 + bp = bp->prev; 1.401 + } 1.402 + return (0); 1.403 +} 1.404 + 1.405 +extern void 1.406 +__reclaim_buf(HTAB *hashp, BUFHEAD *bp) 1.407 +{ 1.408 + bp->ovfl = 0; 1.409 + bp->addr = 0; 1.410 + bp->flags = 0; 1.411 + BUF_REMOVE(bp); 1.412 + LRU_INSERT(bp); 1.413 +}