tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hash_buf.c (12525B)


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