The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/vfs/hammer/hammer_transaction.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2007-2008 The DragonFly Project.  All rights reserved.
    3  * 
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Matthew Dillon <dillon@backplane.com>
    6  * 
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 
   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
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of The DragonFly Project nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific, prior written permission.
   20  * 
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include "hammer.h"
   36 
   37 static u_int32_t ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n);
   38 
   39 
   40 /*
   41  * Start a standard transaction.
   42  *
   43  * May be called without fs_token
   44  */
   45 void
   46 hammer_start_transaction(struct hammer_transaction *trans,
   47                          struct hammer_mount *hmp)
   48 {
   49         struct timeval tv;
   50         int error;
   51 
   52         trans->type = HAMMER_TRANS_STD;
   53         trans->hmp = hmp;
   54         trans->rootvol = hammer_get_root_volume(hmp, &error);
   55         KKASSERT(error == 0);
   56         trans->tid = 0;
   57         trans->sync_lock_refs = 0;
   58         trans->flags = 0;
   59 
   60         getmicrotime(&tv);
   61         trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
   62         trans->time32 = (u_int32_t)tv.tv_sec;
   63 }
   64 
   65 /*
   66  * Start a simple read-only transaction.  This will not stall.
   67  *
   68  * May be called without fs_token
   69  */
   70 void
   71 hammer_simple_transaction(struct hammer_transaction *trans,
   72                           struct hammer_mount *hmp)
   73 {
   74         struct timeval tv;
   75         int error;
   76 
   77         trans->type = HAMMER_TRANS_RO;
   78         trans->hmp = hmp;
   79         trans->rootvol = hammer_get_root_volume(hmp, &error);
   80         KKASSERT(error == 0);
   81         trans->tid = 0;
   82         trans->sync_lock_refs = 0;
   83         trans->flags = 0;
   84 
   85         getmicrotime(&tv);
   86         trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
   87         trans->time32 = (u_int32_t)tv.tv_sec;
   88 }
   89 
   90 /*
   91  * Start a transaction using a particular TID.  Used by the sync code.
   92  * This does not stall.
   93  *
   94  * This routine may only be called from the flusher thread.  We predispose
   95  * sync_lock_refs, implying serialization against the synchronization stage
   96  * (which the flusher is responsible for).
   97  */
   98 void
   99 hammer_start_transaction_fls(struct hammer_transaction *trans,
  100                              struct hammer_mount *hmp)
  101 {
  102         struct timeval tv;
  103         int error;
  104 
  105         bzero(trans, sizeof(*trans));
  106 
  107         trans->type = HAMMER_TRANS_FLS;
  108         trans->hmp = hmp;
  109         trans->rootvol = hammer_get_root_volume(hmp, &error);
  110         KKASSERT(error == 0);
  111         trans->tid = hammer_alloc_tid(hmp, 1);
  112         trans->sync_lock_refs = 1;
  113         trans->flags = 0;
  114 
  115         getmicrotime(&tv);
  116         trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
  117         trans->time32 = (u_int32_t)tv.tv_sec;
  118 }
  119 
  120 /*
  121  * May be called without fs_token
  122  */
  123 void
  124 hammer_done_transaction(struct hammer_transaction *trans)
  125 {
  126         int expected_lock_refs __debugvar;
  127 
  128         hammer_rel_volume(trans->rootvol, 0);
  129         trans->rootvol = NULL;
  130         expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
  131         KKASSERT(trans->sync_lock_refs == expected_lock_refs);
  132         trans->sync_lock_refs = 0;
  133         if (trans->type != HAMMER_TRANS_FLS) {
  134                 if (trans->flags & HAMMER_TRANSF_NEWINODE) {
  135                         lwkt_gettoken(&trans->hmp->fs_token);
  136                         hammer_inode_waitreclaims(trans);
  137                         lwkt_reltoken(&trans->hmp->fs_token);
  138                 }
  139         }
  140 }
  141 
  142 /*
  143  * Allocate (count) TIDs.  If running in multi-master mode the returned
  144  * base will be aligned to a 16-count plus the master id (0-15).  
  145  * Multi-master mode allows non-conflicting to run and new objects to be
  146  * created on multiple masters in parallel.  The transaction id identifies
  147  * the original master.  The object_id is also subject to this rule in
  148  * order to allow objects to be created on multiple masters in parallel.
  149  *
  150  * Directories may pre-allocate a large number of object ids (100,000).
  151  *
  152  * NOTE: There is no longer a requirement that successive transaction
  153  *       ids be 2 apart for separator generation.
  154  *
  155  * NOTE: When called by pseudo-backends such as ioctls the allocated
  156  *       TID will be larger then the current flush TID, if a flush is running,
  157  *       so any mirroring will pick the records up on a later flush.
  158  */
  159 hammer_tid_t
  160 hammer_alloc_tid(hammer_mount_t hmp, int count)
  161 {
  162         hammer_tid_t tid;
  163 
  164         if (hmp->master_id < 0) {
  165                 tid = hmp->next_tid + 1;
  166                 hmp->next_tid = tid + count;
  167         } else {
  168                 tid = (hmp->next_tid + HAMMER_MAX_MASTERS) &
  169                       ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1);
  170                 hmp->next_tid = tid + count * HAMMER_MAX_MASTERS;
  171                 tid |= hmp->master_id;
  172         }
  173         if (tid >= 0xFFFFFFFFFF000000ULL)
  174                 panic("hammer_start_transaction: Ran out of TIDs!");
  175         if (hammer_debug_tid)
  176                 kprintf("alloc_tid %016llx\n", (long long)tid);
  177         return(tid);
  178 }
  179 
  180 /*
  181  * Allocate an object id.
  182  *
  183  * We use the upper OBJID_CACHE_BITS bits of the namekey to try to match
  184  * the low bits of the objid we allocate.
  185  */
  186 hammer_tid_t
  187 hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip, int64_t namekey)
  188 {
  189         hammer_objid_cache_t ocp;
  190         hammer_tid_t tid;
  191         u_int32_t n;
  192 
  193         while ((ocp = dip->objid_cache) == NULL) {
  194                 if (hmp->objid_cache_count < OBJID_CACHE_SIZE) {
  195                         ocp = kmalloc(sizeof(*ocp), hmp->m_misc,
  196                                       M_WAITOK|M_ZERO);
  197                         ocp->base_tid = hammer_alloc_tid(hmp,
  198                                                         OBJID_CACHE_BULK * 2);
  199                         ocp->base_tid += OBJID_CACHE_BULK_MASK64;
  200                         ocp->base_tid &= ~OBJID_CACHE_BULK_MASK64;
  201                         /* may have blocked, recheck */
  202                         if (dip->objid_cache == NULL) {
  203                                 TAILQ_INSERT_TAIL(&hmp->objid_cache_list,
  204                                                   ocp, entry);
  205                                 ++hmp->objid_cache_count;
  206                                 dip->objid_cache = ocp;
  207                                 ocp->dip = dip;
  208                         } else {
  209                                 kfree(ocp, hmp->m_misc);
  210                         }
  211                 } else {
  212                         /*
  213                          * Steal one from another directory?
  214                          *
  215                          * Throw away ocp's that are more then half full, they
  216                          * aren't worth stealing.
  217                          */
  218                         ocp = TAILQ_FIRST(&hmp->objid_cache_list);
  219                         if (ocp->dip)
  220                                 ocp->dip->objid_cache = NULL;
  221                         if (ocp->count >= OBJID_CACHE_BULK / 2) {
  222                                 TAILQ_REMOVE(&hmp->objid_cache_list,
  223                                              ocp, entry);
  224                                 --hmp->objid_cache_count;
  225                                 kfree(ocp, hmp->m_misc);
  226                         } else {
  227                                 dip->objid_cache = ocp;
  228                                 ocp->dip = dip;
  229                         }
  230                 }
  231         }
  232         TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
  233 
  234         /*
  235          * Allocate inode numbers uniformly.
  236          */
  237 
  238         n = (namekey >> (63 - OBJID_CACHE_BULK_BITS)) & OBJID_CACHE_BULK_MASK;
  239         n = ocp_allocbit(ocp, n);
  240         tid = ocp->base_tid + n;
  241 
  242 #if 0
  243         /*
  244          * The TID is incremented by 1 or by 16 depending what mode the
  245          * mount is operating in.
  246          */
  247         ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS;
  248 #endif
  249         if (ocp->count >= OBJID_CACHE_BULK * 3 / 4) {
  250                 dip->objid_cache = NULL;
  251                 --hmp->objid_cache_count;
  252                 ocp->dip = NULL;
  253                 kfree(ocp, hmp->m_misc);
  254         } else {
  255                 TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry);
  256         }
  257         return(tid);
  258 }
  259 
  260 /*
  261  * Allocate a bit starting with bit n.  Wrap if necessary.
  262  *
  263  * This routine is only ever called if a bit is available somewhere
  264  * in the bitmap.
  265  */
  266 static u_int32_t
  267 ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n)
  268 {
  269         u_int32_t n0;
  270 
  271         n0 = (n >> 5) & 31;
  272         n &= 31;
  273 
  274         while (ocp->bm1[n0] & (1 << n)) {
  275                 if (ocp->bm0 & (1 << n0)) {
  276                         n0 = (n0 + 1) & 31;
  277                         n = 0;
  278                 } else if (++n == 32) {
  279                         n0 = (n0 + 1) & 31;
  280                         n = 0;
  281                 }
  282         }
  283         ++ocp->count;
  284         ocp->bm1[n0] |= 1 << n;
  285         if (ocp->bm1[n0] == 0xFFFFFFFFU)
  286                 ocp->bm0 |= 1 << n0;
  287         return((n0 << 5) + n);
  288 }
  289 
  290 void
  291 hammer_clear_objid(hammer_inode_t dip)
  292 {
  293         hammer_objid_cache_t ocp;
  294 
  295         if ((ocp = dip->objid_cache) != NULL) {
  296                 dip->objid_cache = NULL;
  297                 ocp->dip = NULL;
  298                 TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
  299                 TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
  300         }
  301 }
  302 
  303 void
  304 hammer_destroy_objid_cache(hammer_mount_t hmp)
  305 {
  306         hammer_objid_cache_t ocp;
  307 
  308         while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
  309                 TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
  310                 if (ocp->dip)
  311                         ocp->dip->objid_cache = NULL;
  312                 kfree(ocp, hmp->m_misc);
  313                 --hmp->objid_cache_count;
  314         }
  315         KKASSERT(hmp->objid_cache_count == 0);
  316 }
  317 

Cache object: 5f4733c76a1965c1fcc8158920d3e2be


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.