security/nss/lib/dbm/src/hash_buf.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*-
michael@0 2 * Copyright (c) 1990, 1993, 1994
michael@0 3 * The Regents of the University of California. All rights reserved.
michael@0 4 *
michael@0 5 * This code is derived from software contributed to Berkeley by
michael@0 6 * Margo Seltzer.
michael@0 7 *
michael@0 8 * Redistribution and use in source and binary forms, with or without
michael@0 9 * modification, are permitted provided that the following conditions
michael@0 10 * are met:
michael@0 11 * 1. Redistributions of source code must retain the above copyright
michael@0 12 * notice, this list of conditions and the following disclaimer.
michael@0 13 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 14 * notice, this list of conditions and the following disclaimer in the
michael@0 15 * documentation and/or other materials provided with the distribution.
michael@0 16 * 3. ***REMOVED*** - see
michael@0 17 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
michael@0 18 * 4. Neither the name of the University nor the names of its contributors
michael@0 19 * may be used to endorse or promote products derived from this software
michael@0 20 * without specific prior written permission.
michael@0 21 *
michael@0 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
michael@0 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
michael@0 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
michael@0 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
michael@0 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
michael@0 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
michael@0 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
michael@0 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@0 32 * SUCH DAMAGE.
michael@0 33 */
michael@0 34
michael@0 35 #if defined(LIBC_SCCS) && !defined(lint)
michael@0 36 static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
michael@0 37 #endif /* LIBC_SCCS and not lint */
michael@0 38
michael@0 39 /*
michael@0 40 * PACKAGE: hash
michael@0 41 *
michael@0 42 * DESCRIPTION:
michael@0 43 * Contains buffer management
michael@0 44 *
michael@0 45 * ROUTINES:
michael@0 46 * External
michael@0 47 * __buf_init
michael@0 48 * __get_buf
michael@0 49 * __buf_free
michael@0 50 * __reclaim_buf
michael@0 51 * Internal
michael@0 52 * newbuf
michael@0 53 */
michael@0 54 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
michael@0 55 #include <sys/param.h>
michael@0 56 #endif
michael@0 57
michael@0 58 #include <errno.h>
michael@0 59 #include <stddef.h>
michael@0 60 #include <stdio.h>
michael@0 61 #include <stdlib.h>
michael@0 62 #include <string.h>
michael@0 63
michael@0 64 #ifdef DEBUG
michael@0 65 #include <assert.h>
michael@0 66 #endif
michael@0 67
michael@0 68 #include "mcom_db.h"
michael@0 69 #include "hash.h"
michael@0 70 #include "page.h"
michael@0 71 /* #include "extern.h" */
michael@0 72
michael@0 73 static BUFHEAD *newbuf __P((HTAB *, uint32, BUFHEAD *));
michael@0 74
michael@0 75 /* Unlink B from its place in the lru */
michael@0 76 #define BUF_REMOVE(B) { \
michael@0 77 (B)->prev->next = (B)->next; \
michael@0 78 (B)->next->prev = (B)->prev; \
michael@0 79 }
michael@0 80
michael@0 81 /* Insert B after P */
michael@0 82 #define BUF_INSERT(B, P) { \
michael@0 83 (B)->next = (P)->next; \
michael@0 84 (B)->prev = (P); \
michael@0 85 (P)->next = (B); \
michael@0 86 (B)->next->prev = (B); \
michael@0 87 }
michael@0 88
michael@0 89 #define MRU hashp->bufhead.next
michael@0 90 #define LRU hashp->bufhead.prev
michael@0 91
michael@0 92 #define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
michael@0 93 #define LRU_INSERT(B) BUF_INSERT((B), LRU)
michael@0 94
michael@0 95 /*
michael@0 96 * We are looking for a buffer with address "addr". If prev_bp is NULL, then
michael@0 97 * address is a bucket index. If prev_bp is not NULL, then it points to the
michael@0 98 * page previous to an overflow page that we are trying to find.
michael@0 99 *
michael@0 100 * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
michael@0 101 * be valid. Therefore, you must always verify that its address matches the
michael@0 102 * address you are seeking.
michael@0 103 */
michael@0 104 extern BUFHEAD *
michael@0 105 __get_buf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp, int newpage)
michael@0 106 /* If prev_bp set, indicates a new overflow page. */
michael@0 107 {
michael@0 108 register BUFHEAD *bp;
michael@0 109 register uint32 is_disk_mask;
michael@0 110 register int is_disk, segment_ndx = 0;
michael@0 111 SEGMENT segp = 0;
michael@0 112
michael@0 113 is_disk = 0;
michael@0 114 is_disk_mask = 0;
michael@0 115 if (prev_bp) {
michael@0 116 bp = prev_bp->ovfl;
michael@0 117 if (!bp || (bp->addr != addr))
michael@0 118 bp = NULL;
michael@0 119 if (!newpage)
michael@0 120 is_disk = BUF_DISK;
michael@0 121 } else {
michael@0 122 /* Grab buffer out of directory */
michael@0 123 segment_ndx = addr & (hashp->SGSIZE - 1);
michael@0 124
michael@0 125 /* valid segment ensured by __call_hash() */
michael@0 126 segp = hashp->dir[addr >> hashp->SSHIFT];
michael@0 127 #ifdef DEBUG
michael@0 128 assert(segp != NULL);
michael@0 129 #endif
michael@0 130
michael@0 131 bp = PTROF(segp[segment_ndx]);
michael@0 132
michael@0 133 is_disk_mask = ISDISK(segp[segment_ndx]);
michael@0 134 is_disk = is_disk_mask || !hashp->new_file;
michael@0 135 }
michael@0 136
michael@0 137 if (!bp) {
michael@0 138 bp = newbuf(hashp, addr, prev_bp);
michael@0 139 if (!bp)
michael@0 140 return(NULL);
michael@0 141 if(__get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
michael@0 142 {
michael@0 143 /* free bp and its page */
michael@0 144 if(prev_bp)
michael@0 145 {
michael@0 146 /* if prev_bp is set then the new page that
michael@0 147 * failed is hooked onto prev_bp as an overflow page.
michael@0 148 * if we don't remove the pointer to the bad page
michael@0 149 * we may try and access it later and we will die
michael@0 150 * horribly because it will have already been
michael@0 151 * free'd and overwritten with bogus data.
michael@0 152 */
michael@0 153 prev_bp->ovfl = NULL;
michael@0 154 }
michael@0 155 BUF_REMOVE(bp);
michael@0 156 free(bp->page);
michael@0 157 free(bp);
michael@0 158 return (NULL);
michael@0 159 }
michael@0 160
michael@0 161 if (!prev_bp)
michael@0 162 {
michael@0 163 #if 0
michael@0 164 /* 16 bit windows and mac can't handle the
michael@0 165 * oring of the is disk flag.
michael@0 166 */
michael@0 167 segp[segment_ndx] =
michael@0 168 (BUFHEAD *)((ptrdiff_t)bp | is_disk_mask);
michael@0 169 #else
michael@0 170 /* set the is_disk thing inside the structure
michael@0 171 */
michael@0 172 bp->is_disk = is_disk_mask;
michael@0 173 segp[segment_ndx] = bp;
michael@0 174 #endif
michael@0 175 }
michael@0 176 } else {
michael@0 177 BUF_REMOVE(bp);
michael@0 178 MRU_INSERT(bp);
michael@0 179 }
michael@0 180 return (bp);
michael@0 181 }
michael@0 182
michael@0 183 /*
michael@0 184 * We need a buffer for this page. Either allocate one, or evict a resident
michael@0 185 * one (if we have as many buffers as we're allowed) and put this one in.
michael@0 186 *
michael@0 187 * If newbuf finds an error (returning NULL), it also sets errno.
michael@0 188 */
michael@0 189 static BUFHEAD *
michael@0 190 newbuf(HTAB *hashp, uint32 addr, BUFHEAD *prev_bp)
michael@0 191 {
michael@0 192 register BUFHEAD *bp; /* The buffer we're going to use */
michael@0 193 register BUFHEAD *xbp; /* Temp pointer */
michael@0 194 register BUFHEAD *next_xbp;
michael@0 195 SEGMENT segp;
michael@0 196 int segment_ndx;
michael@0 197 uint16 oaddr, *shortp;
michael@0 198
michael@0 199 oaddr = 0;
michael@0 200 bp = LRU;
michael@0 201 /*
michael@0 202 * If LRU buffer is pinned, the buffer pool is too small. We need to
michael@0 203 * allocate more buffers.
michael@0 204 */
michael@0 205 if (hashp->nbufs || (bp->flags & BUF_PIN)) {
michael@0 206 /* Allocate a new one */
michael@0 207 if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL)
michael@0 208 return (NULL);
michael@0 209
michael@0 210 /* this memset is supposedly unnecessary but lets add
michael@0 211 * it anyways.
michael@0 212 */
michael@0 213 memset(bp, 0xff, sizeof(BUFHEAD));
michael@0 214
michael@0 215 if ((bp->page = (char *)malloc((size_t)hashp->BSIZE)) == NULL) {
michael@0 216 free(bp);
michael@0 217 return (NULL);
michael@0 218 }
michael@0 219
michael@0 220 /* this memset is supposedly unnecessary but lets add
michael@0 221 * it anyways.
michael@0 222 */
michael@0 223 memset(bp->page, 0xff, (size_t)hashp->BSIZE);
michael@0 224
michael@0 225 if (hashp->nbufs)
michael@0 226 hashp->nbufs--;
michael@0 227 } else {
michael@0 228 /* Kick someone out */
michael@0 229 BUF_REMOVE(bp);
michael@0 230 /*
michael@0 231 * If this is an overflow page with addr 0, it's already been
michael@0 232 * flushed back in an overflow chain and initialized.
michael@0 233 */
michael@0 234 if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
michael@0 235 /*
michael@0 236 * Set oaddr before __put_page so that you get it
michael@0 237 * before bytes are swapped.
michael@0 238 */
michael@0 239 shortp = (uint16 *)bp->page;
michael@0 240 if (shortp[0])
michael@0 241 {
michael@0 242 if(shortp[0] > (hashp->BSIZE / sizeof(uint16)))
michael@0 243 {
michael@0 244 return(NULL);
michael@0 245 }
michael@0 246 oaddr = shortp[shortp[0] - 1];
michael@0 247 }
michael@0 248 if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
michael@0 249 bp->addr, (int)IS_BUCKET(bp->flags), 0))
michael@0 250 return (NULL);
michael@0 251 /*
michael@0 252 * Update the pointer to this page (i.e. invalidate it).
michael@0 253 *
michael@0 254 * If this is a new file (i.e. we created it at open
michael@0 255 * time), make sure that we mark pages which have been
michael@0 256 * written to disk so we retrieve them from disk later,
michael@0 257 * rather than allocating new pages.
michael@0 258 */
michael@0 259 if (IS_BUCKET(bp->flags)) {
michael@0 260 segment_ndx = bp->addr & (hashp->SGSIZE - 1);
michael@0 261 segp = hashp->dir[bp->addr >> hashp->SSHIFT];
michael@0 262 #ifdef DEBUG
michael@0 263 assert(segp != NULL);
michael@0 264 #endif
michael@0 265
michael@0 266 if (hashp->new_file &&
michael@0 267 ((bp->flags & BUF_MOD) ||
michael@0 268 ISDISK(segp[segment_ndx])))
michael@0 269 segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
michael@0 270 else
michael@0 271 segp[segment_ndx] = NULL;
michael@0 272 }
michael@0 273 /*
michael@0 274 * Since overflow pages can only be access by means of
michael@0 275 * their bucket, free overflow pages associated with
michael@0 276 * this bucket.
michael@0 277 */
michael@0 278 for (xbp = bp; xbp->ovfl;) {
michael@0 279 next_xbp = xbp->ovfl;
michael@0 280 xbp->ovfl = 0;
michael@0 281 xbp = next_xbp;
michael@0 282
michael@0 283 /* leave pinned pages alone, we are still using
michael@0 284 * them. */
michael@0 285 if (xbp->flags & BUF_PIN) {
michael@0 286 continue;
michael@0 287 }
michael@0 288
michael@0 289 /* Check that ovfl pointer is up date. */
michael@0 290 if (IS_BUCKET(xbp->flags) ||
michael@0 291 (oaddr != xbp->addr))
michael@0 292 break;
michael@0 293
michael@0 294 shortp = (uint16 *)xbp->page;
michael@0 295 if (shortp[0])
michael@0 296 {
michael@0 297 /* LJM is the number of reported
michael@0 298 * pages way too much?
michael@0 299 */
michael@0 300 if(shortp[0] > hashp->BSIZE/sizeof(uint16))
michael@0 301 return NULL;
michael@0 302 /* set before __put_page */
michael@0 303 oaddr = shortp[shortp[0] - 1];
michael@0 304 }
michael@0 305 if ((xbp->flags & BUF_MOD) && __put_page(hashp,
michael@0 306 xbp->page, xbp->addr, 0, 0))
michael@0 307 return (NULL);
michael@0 308 xbp->addr = 0;
michael@0 309 xbp->flags = 0;
michael@0 310 BUF_REMOVE(xbp);
michael@0 311 LRU_INSERT(xbp);
michael@0 312 }
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 /* Now assign this buffer */
michael@0 317 bp->addr = addr;
michael@0 318 #ifdef DEBUG1
michael@0 319 (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
michael@0 320 bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
michael@0 321 #endif
michael@0 322 bp->ovfl = NULL;
michael@0 323 if (prev_bp) {
michael@0 324 /*
michael@0 325 * If prev_bp is set, this is an overflow page, hook it in to
michael@0 326 * the buffer overflow links.
michael@0 327 */
michael@0 328 #ifdef DEBUG1
michael@0 329 (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
michael@0 330 prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0),
michael@0 331 (bp ? bp->addr : 0));
michael@0 332 #endif
michael@0 333 prev_bp->ovfl = bp;
michael@0 334 bp->flags = 0;
michael@0 335 } else
michael@0 336 bp->flags = BUF_BUCKET;
michael@0 337 MRU_INSERT(bp);
michael@0 338 return (bp);
michael@0 339 }
michael@0 340
michael@0 341 extern void __buf_init(HTAB *hashp, int32 nbytes)
michael@0 342 {
michael@0 343 BUFHEAD *bfp;
michael@0 344 int npages;
michael@0 345
michael@0 346 bfp = &(hashp->bufhead);
michael@0 347 npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
michael@0 348 npages = PR_MAX(npages, MIN_BUFFERS);
michael@0 349
michael@0 350 hashp->nbufs = npages;
michael@0 351 bfp->next = bfp;
michael@0 352 bfp->prev = bfp;
michael@0 353 /*
michael@0 354 * This space is calloc'd so these are already null.
michael@0 355 *
michael@0 356 * bfp->ovfl = NULL;
michael@0 357 * bfp->flags = 0;
michael@0 358 * bfp->page = NULL;
michael@0 359 * bfp->addr = 0;
michael@0 360 */
michael@0 361 }
michael@0 362
michael@0 363 extern int
michael@0 364 __buf_free(HTAB *hashp, int do_free, int to_disk)
michael@0 365 {
michael@0 366 BUFHEAD *bp;
michael@0 367 int status = -1;
michael@0 368
michael@0 369 /* Need to make sure that buffer manager has been initialized */
michael@0 370 if (!LRU)
michael@0 371 return (0);
michael@0 372 for (bp = LRU; bp != &hashp->bufhead;) {
michael@0 373 /* Check that the buffer is valid */
michael@0 374 if (bp->addr || IS_BUCKET(bp->flags)) {
michael@0 375 if (to_disk && (bp->flags & BUF_MOD) &&
michael@0 376 (status = __put_page(hashp, bp->page,
michael@0 377 bp->addr, IS_BUCKET(bp->flags), 0))) {
michael@0 378
michael@0 379 if (do_free) {
michael@0 380 if (bp->page)
michael@0 381 free(bp->page);
michael@0 382 BUF_REMOVE(bp);
michael@0 383 free(bp);
michael@0 384 }
michael@0 385
michael@0 386 return (status);
michael@0 387 }
michael@0 388 }
michael@0 389 /* Check if we are freeing stuff */
michael@0 390 if (do_free) {
michael@0 391 if (bp->page)
michael@0 392 free(bp->page);
michael@0 393 BUF_REMOVE(bp);
michael@0 394 free(bp);
michael@0 395 bp = LRU;
michael@0 396 } else
michael@0 397 bp = bp->prev;
michael@0 398 }
michael@0 399 return (0);
michael@0 400 }
michael@0 401
michael@0 402 extern void
michael@0 403 __reclaim_buf(HTAB *hashp, BUFHEAD *bp)
michael@0 404 {
michael@0 405 bp->ovfl = 0;
michael@0 406 bp->addr = 0;
michael@0 407 bp->flags = 0;
michael@0 408 BUF_REMOVE(bp);
michael@0 409 LRU_INSERT(bp);
michael@0 410 }

mercurial