Example #1
0
void os_mem_info(void)
{
    MEM_DEBUG("struct heap_mem=%d, MEM_BLOCK_ALIGN_BYTE=%d", sizeof(struct heap_mem), MEM_BLOCK_ALIGN_BYTE);
    MEM_DEBUG("total memory: %d", mem_size_aligned);
    MEM_DEBUG("used memory : %d", used_mem);
    MEM_DEBUG("maximum allocated memory: %d", max_mem);
}
Example #2
0
void memWriteProcess()
{
  uint8_t memId = p.data[0];
  uint8_t writeLen;
  uint32_t memAddr;
  uint8_t status = 0;

  memcpy(&memAddr, &p.data[1], 4);
  writeLen = p.size - 5;

  MEM_DEBUG("Packet is MEM WRITE\n");
  p.header = CRTP_HEADER(CRTP_PORT_MEM, WRITE_CH);
  // Dont' touch the first 5 bytes, they will be the same.
  if (memId == EEPROM_ID)
  {
    if (memAddr + writeLen <= EEPROM_SIZE &&
        eepromWriteBuffer(&p.data[5], memAddr, writeLen))
      status = 0;
    else
      status = EIO;
  }
  else if(memId == LEDMEM_ID)
  {
    if ((memAddr + writeLen) <= sizeof(ledringmem))
    {
      memcpy(&(ledringmem[memAddr]), &p.data[5], writeLen);
      MEM_DEBUG("LED write addr:%i, led:%i\n", memAddr, writeLen);
    }
    else
    {
      MEM_DEBUG("\LED write failed! addr:%i, led:%i\n", memAddr, writeLen);
    }
  }
  else
  {
/*****************************************************************************
 * function:
 *         crypto_free_slab_list(qae_slab_pool *list, int memfd)
 * @param[in] list, pointer to a slab list
 * @param[in] memfd, file descriptor for the memory driver
 *
 * @description
 *      Free all slabs in the supplied slab list.
 *
 *****************************************************************************/
static void crypto_free_slab_list(qae_slab_pool *list, int memfd)
{
    qae_slab *slb, *s_next_slab;
#ifdef USE_QAT_CONTIG_MEM
    qat_contig_mem_config qmcfg;
#endif

    /* cleanup all the empty slabs */
    for (slb = list->next; list->slot_size > 0 ; slb = s_next_slab) {
        /* need to save this off before unmapping. This is why we can't have
           slb = slb->next_slab in the for loop above. */
        s_next_slab = slb->next;
#ifdef USE_QAT_CONTIG_MEM
        MEM_DEBUG("%s do munmap  of %p\n", __func__, slb);
        qmcfg = *((qat_contig_mem_config *) slb);

        if (munmap(slb, SLAB_SIZE) == -1) {
            perror("munmap");
            exit(EXIT_FAILURE);
        }
        MEM_DEBUG("%s ioctl free of %p\n", __func__, slb);
        if (ioctl(memfd, QAT_CONTIG_MEM_FREE, &qmcfg) == -1) {
            perror("ioctl QAT_CONTIG_MEM_FREE");
            exit(EXIT_FAILURE);
        }
#endif
        list->slot_size--;
    }

    MEM_DEBUG("%s done\n", __func__);

}
Example #4
0
void qaeCryptoMemFree(void *ptr)
{
    int rc;

    MEM_DEBUG("%s: Address: %p\n", __func__, ptr);

    if (NULL == ptr) {
        MEM_WARN("qaeCryptoMemFree trying to free NULL pointer.\n");
        return;
    }

    MEM_DEBUG("%s: pthread_mutex_lock\n", __func__);
    if ((rc = pthread_mutex_lock(&mem_mutex)) != 0) {
        MEM_ERROR("pthread_mutex_lock: %s\n", strerror(rc));
        return;
    }

    qaeMemFreeNUMA(&ptr);

    if ((rc = pthread_mutex_unlock(&mem_mutex)) != 0) {
        MEM_ERROR("pthread_mutex_unlock: %s\n", strerror(rc));
        return;
    }
    MEM_DEBUG("%s: pthread_mutex_unlock\n", __func__);
}
Example #5
0
/**
 * This function will release the previously allocated memory block by
 * os_malloc. The released memory block is taken back to system heap.
 *
 * @rmem the address of memory which will be released
 */
void os_free(void *rmem)
{
    struct heap_mem *mem;

    /*RT_DEBUG_NOT_IN_INTERRUPT;*/

    if (rmem == NULL)
    {
        return;
    }
    MEM_ASSERT((((uint32_t)rmem) & (MEM_ALIGN_BYTE - 1)) == 0);
    MEM_ASSERT((uint8_t *)rmem >= (uint8_t *)heap_ptr &&
                (uint8_t *)rmem < (uint8_t *)heap_end);

    if ((uint8_t *)rmem < (uint8_t *)heap_ptr ||
            (uint8_t *)rmem >= (uint8_t *)heap_end)
    {
        MEM_DEBUG("illegal memory");
        return;
    }

    /* Get the corresponding struct heap_mem ... */
    mem = (struct heap_mem *)((uint8_t *)rmem - MEM_BLOCK_SIZE);

    MEM_DEBUG("release memory 0x%x, size: %d",
                (uint32_t)rmem,
                (uint32_t)(mem->next - ((uint8_t *)mem - heap_ptr)));

#ifdef MEM_SAFETY
    /* protect the heap from concurrent access */
    sem_wait(&heap_sem);
#endif

    /* ... which has to be in a used state ... */
    MEM_ASSERT(mem->used);
    MEM_ASSERT(mem->magic == HEAP_MAGIC);
    /* ... and is now unused. */
    mem->used  = 0;
    mem->magic = 0;

    if (mem < lfree)
    {
        /* the newly freed struct is now the lowest */
        lfree = mem;
    }

#ifdef MEM_STATISTIC
    used_mem -= (mem->next - ((uint8_t *)mem - heap_ptr));
#endif

    /* finally, see if prev or next are free also */
    plug_holes(mem);
#ifdef MEM_SAFETY
    sem_post(&heap_sem);
#endif
}
Example #6
0
/**
 * This function will initialize system heap memory.
 *
 * @begin_addr the beginning address of heap memory.
 * @end_addr   the end address of heap memory.
 */
void os_mem_init(void *begin_addr, void *end_addr)
{
    struct heap_mem *mem;
    uint32_t begin_align = MEM_ALIGN_UP((uint32_t)begin_addr, MEM_ALIGN_BYTE);
    uint32_t end_align = MEM_ALIGN_DOWN((uint32_t)end_addr, MEM_ALIGN_BYTE);

    /*RT_DEBUG_NOT_IN_INTERRUPT;*/

    /* alignment addr */
    if ((end_align > (2 * MEM_BLOCK_SIZE)) &&
            ((end_align - 2 * MEM_BLOCK_SIZE) >= begin_align))
    {
        /* calculate the aligned memory size */
        mem_size_aligned = end_align - begin_align - 2 * MEM_BLOCK_SIZE;
    }
    else
    {
        MEM_DEBUG("mem init, error begin address 0x%x, and end address 0x%x",
                    (uint32_t)begin_addr, (uint32_t)end_addr);
        return;
    }

    /* point to begin address of heap */
    heap_ptr = (uint8_t *)begin_align;

    MEM_DEBUG("mem init, heap begin address 0x%x, size %d",
                (uint32_t)heap_ptr, mem_size_aligned);

    /* initialize the start of the heap */
    mem        = (struct heap_mem *)heap_ptr;
    mem->magic = HEAP_MAGIC;
    mem->next  = mem_size_aligned + MEM_BLOCK_SIZE;
    mem->prev  = 0;
    mem->used  = 0;

    /* initialize the end of the heap */
    heap_end        = (struct heap_mem *)&heap_ptr[mem->next];
    heap_end->magic = HEAP_MAGIC;
    heap_end->used  = 1;
    heap_end->next  = mem_size_aligned + MEM_BLOCK_SIZE;
    heap_end->prev  = mem_size_aligned + MEM_BLOCK_SIZE;

#ifdef MEM_SAFETY
    if(sem_init(&heap_sem, 0, 1) == -1)
    {
        MEM_DEBUG("heap_sem intitialization failed\n");
        MEM_ASSERT(0);
    }
#endif

    /* initialize the lowest-free pointer to the start of the heap */
    lfree = (struct heap_mem *)heap_ptr;
}
/******************************************************************************
* function:
*         qaeCryptoMemRealloc(void *ptr, size_t memsize, const char *file,
*                             int line)
*
* @param[in] ptr,     address of start of usable memory for old allocation
* @param[in] memsize, size of new block required
* @param[in] file,    the C source filename of the call site
* @param[in] line,    the line number withing the C source file of the call
*                     site
*
* description:
*   Change the size of usable memory in an allocated block. This may allocate
*   a new block and copy the data to it.
*
******************************************************************************/
void *qaeCryptoMemRealloc(void *ptr, size_t memsize, const char *file,
                          int line)
{
    int copy = crypto_slot_get_size(ptr);
    void *n = crypto_alloc_from_slab(memsize, file, line);
    MEM_DEBUG("%s: Alloc Address: %p Size: %d File: %s:%d\n", __func__, n,
          memsize, file, line);

    if (memsize < copy)
        copy = memsize;
    memcpy(n, ptr, copy);
    MEM_DEBUG("%s: Free Address: %p\n", __func__, ptr);
    crypto_free_to_slab(ptr);
    return n;
}
/******************************************************************************
* function:
*         qaeCryptoMemAlloc(size_t memsize, const char *file, int line)
*
* @param[in] memsize,  size of usable memory requested
* @param[in] file,     the C source filename of the call site
* @param[in] line,     the line number within the C source file of the call
*                      site
*
* description:
*   Allocate a block of pinned memory.
*
******************************************************************************/
void *qaeCryptoMemAlloc(size_t memsize, const char *file, int line)
{
    void *pAddress = crypto_alloc_from_slab(memsize, file, line);
    MEM_DEBUG("%s: Address: %p Size: %d File: %s:%d\n", __func__, pAddress,
          memsize, file, line);
    return pAddress;
}
Example #9
0
void memReadProcess()
{
  uint8_t memId = p.data[0];
  uint8_t readLen = p.data[5];
  uint32_t memAddr;
  uint8_t status = 0;

  memcpy(&memAddr, &p.data[1], 4);

  MEM_DEBUG("Packet is MEM READ\n");
  p.header = CRTP_HEADER(CRTP_PORT_MEM, READ_CH);
  // Dont' touch the first 5 bytes, they will be the same.

  if (memId == EEPROM_ID)
  {
    if (memAddr + readLen <= EEPROM_SIZE &&
        eepromReadBuffer(&p.data[6], memAddr, readLen))
      status = 0;
    else
      status = EIO;
  }
  else if (memId == LEDMEM_ID)
  {
    if (memAddr + readLen <= sizeof(ledringmem) &&
        memcpy(&p.data[6], &(ledringmem[memAddr]), readLen))
      status = 0;
    else
      status = EIO;
  }
  else
  {
    memId = memId - NBR_STATIC_MEM;
    if (memAddr + readLen <= OW_MAX_SIZE &&
        owRead(memId, memAddr, readLen, &p.data[6]))
      status = 0;
    else
      status = EIO;
  }

#if 0
  {
    int i;
    for (i = 0; i < readLen; i++)
      consolePrintf("%X ", p.data[i+6]);

    consolePrintf("\nStatus %i\n", status);
  }
#endif

  p.data[5] = status;
  if (status == 0)
    p.size = 6 + readLen;
  else
    p.size = 6;


  crtpSendPacket(&p);
}
/*****************************************************************************
 * function:
 *         crypto_free_slab(qae_slab *slb, void *thread_key)
 *
 * @param[in] slb, pointer to the slab to be freed
 * @param[in] thread_key, thread local key that points to the slab pools
 *
 * @description
 *      free a slab to kernel
 *
 *****************************************************************************/
static void crypto_free_slab(qae_slab *slb, void *thread_key)
{
    qat_contig_mem_config qmcfg;
    qae_slab_pools_local *tls_ptr = (qae_slab_pools_local *)thread_key;
#ifdef USE_QAT_CONTIG_MEM
    MEM_DEBUG("%s do munmap  of %p\n", __func__, slb);
    qmcfg = *((qat_contig_mem_config *) slb);

    if (munmap(slb, SLAB_SIZE) == -1) {
        perror("munmap");
        exit(EXIT_FAILURE);
    }
    MEM_DEBUG("%s ioctl free of %p\n", __func__, slb);
    if (ioctl(tls_ptr->crypto_qat_contig_memfd, QAT_CONTIG_MEM_FREE, &qmcfg)
        == -1) {
        perror("ioctl QAT_CONTIG_MEM_FREE");
        exit(EXIT_FAILURE);
    }
#endif
}
Example #11
0
void *qaeCryptoMemAlloc(size_t memsize, const char *file, int line)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    int rc;
    void *pAddress = NULL;

    MEM_DEBUG("%s: pthread_mutex_lock\n", __func__);
    if ((rc = pthread_mutex_lock(&mem_mutex)) != 0) {
        MEM_ERROR("pthread_mutex_lock: %s\n", strerror(rc));
        return NULL;
    }

    pAddress = qaeMemAllocNUMA(memsize, 0, QAT_BYTE_ALIGNMENT);
    MEM_DEBUG("%s: Address: %p Size: %d File: %s:%d\n", __func__, pAddress,
          memsize, file, line);
    if ((rc = pthread_mutex_unlock(&mem_mutex)) != 0) {
        MEM_ERROR("pthread_mutex_unlock: %s\n", strerror(rc));
    }
    MEM_DEBUG("%s: pthread_mutex_unlock\n", __func__);
    return pAddress;
}
Example #12
0
/**
 * This function will change the previously allocated memory block.
 *
 * @rmem pointer to memory allocated by os_malloc
 * @newsize the required new size
 *
 * @return the changed memory block address
 */
void *os_realloc(void *rmem, uint32_t newsize)
{
    uint32_t size;
    uint32_t ptr, ptr2;
    struct heap_mem *mem, *mem2;
    void *nmem;

    /*RT_DEBUG_NOT_IN_INTERRUPT;*/

    /* alignment size */
    newsize = MEM_ALIGN_UP(newsize, MEM_ALIGN_BYTE);
    if (newsize > mem_size_aligned)
    {
        MEM_DEBUG("realloc: out of memory");
        return NULL;
    }

    /* allocate a new memory block */
    if (rmem == NULL)
    {
        return os_malloc(newsize);
    }

#ifdef MEM_SAFETY
    sem_wait(&heap_sem);
#endif

    if ((uint8_t *)rmem < (uint8_t *)heap_ptr ||
            (uint8_t *)rmem >= (uint8_t *)heap_end)
    {
#ifdef MEM_SAFETY
        /* illegal memory */
        sem_post(&heap_sem);
#endif

        return rmem;
    }

    mem = (struct heap_mem *)((uint8_t *)rmem - MEM_BLOCK_SIZE);

    ptr = (uint8_t *)mem - heap_ptr;
    size = mem->next - ptr - MEM_BLOCK_SIZE;
    if (size == newsize)
    {
#ifdef MEM_SAFETY
        /* the size is the same as */
        sem_post(&heap_sem);
#endif
        return rmem;
    }

    if (newsize + MEM_BLOCK_SIZE + MEM_BLOCK_MIN_SIZE < size)
    {
        /* split memory block */
#ifdef MEM_STATISTIC
        used_mem -= (size - newsize);
#endif

        ptr2 = ptr + MEM_BLOCK_SIZE + newsize;
        mem2 = (struct heap_mem *)&heap_ptr[ptr2];
        mem2->magic = HEAP_MAGIC;
        mem2->used = 0;
        mem2->next = mem->next;
        mem2->prev = ptr;
        mem->next = ptr2;
        if (mem2->next != mem_size_aligned + MEM_BLOCK_SIZE)
        {
            ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
        }

        plug_holes(mem2);
#ifdef MEM_SAFETY
        sem_post(&heap_sem);
#endif
        return rmem;
    }
#ifdef MEM_SAFETY
    sem_post(&heap_sem);
#endif

    /* expand memory */
    nmem = os_malloc(newsize);
    if (nmem != NULL) /* check memory */
    {
        memcpy(nmem, rmem, size < newsize ? size : newsize);
        os_free(rmem);
    }

    return nmem;
}
Example #13
0
/**
 * Allocate a block of memory with a minimum of 'size' bytes.
 *
 * @size is the minimum size of the requested block in bytes.
 *
 * @return pointer to allocated memory or NULL if no free memory was found.
 */
void *os_malloc(uint32_t size)
{
    uint32_t ptr, ptr2;
    struct heap_mem *mem, *mem2;

    /* Note:shall not used in ISR, I never do this. */
    /*RT_DEBUG_NOT_IN_INTERRUPT;*/

    if (size == 0)
    {
        return NULL;
    }

    if (size != MEM_ALIGN_UP(size, MEM_ALIGN_BYTE))
    {
        MEM_DEBUG("malloc size %d, but align to %d", size, MEM_ALIGN_UP(size, MEM_ALIGN_BYTE));
    }
    else
    {
        MEM_DEBUG("malloc size %d", size);
    }

    /* alignment size */
    size = MEM_ALIGN_UP(size, MEM_ALIGN_BYTE);

    if (size > mem_size_aligned)
    {
        MEM_DEBUG("no memory");
        return NULL;
    }

    /* every data block must be at least MEM_BLOCK_ALIGN_BYTE long */
    if (size < MEM_BLOCK_ALIGN_BYTE)
    {
        size = MEM_BLOCK_ALIGN_BYTE;
    }

#ifdef MEM_SAFETY
    /* take memory semaphore */
    sem_wait(&heap_sem);
#endif

    for (ptr = (uint8_t *)lfree - heap_ptr;
            ptr < mem_size_aligned - size;
            ptr = ((struct heap_mem *)&heap_ptr[ptr])->next)
    {
        mem = (struct heap_mem *)&heap_ptr[ptr];

        if ((!mem->used) && (mem->next - (ptr + MEM_BLOCK_SIZE)) >= size)
        {
            /* mem is not used and at least perfect fit is possible:
             * mem->next - (ptr + MEM_BLOCK_SIZE) gives us the 'user data size' of mem */

            if (mem->next - (ptr + MEM_BLOCK_SIZE) >=
                    (size + MEM_BLOCK_SIZE + MEM_BLOCK_ALIGN_BYTE))
            {
                /* (in addition to the above, we test if another struct heap_mem (MEM_BLOCK_SIZE) containing
                 * at least MEM_BLOCK_ALIGN_BYTE of data also fits in the 'user data space' of 'mem')
                 * -> split large block, create empty remainder,
                 * remainder must be large enough to contain MEM_BLOCK_ALIGN_BYTE data: if
                 * mem->next - (ptr + (2*MEM_BLOCK_SIZE)) == size,
                 * struct heap_mem would fit in but no data between mem2 and mem2->next
                 * @todo we could leave out MEM_BLOCK_ALIGN_BYTE. We would create an empty
                 *       region that couldn't hold data, but when mem->next gets freed,
                 *       the 2 regions would be combined, resulting in more free memory
                 */
                ptr2 = ptr + MEM_BLOCK_SIZE + size;

                /* create mem2 struct */
                mem2       = (struct heap_mem *)&heap_ptr[ptr2];
                mem2->used = 0;
                mem2->next = mem->next;
                mem2->prev = ptr;

                /* and insert it between mem and mem->next */
                mem->next = ptr2;
                mem->used = 1;

                if (mem2->next != mem_size_aligned + MEM_BLOCK_SIZE)
                {
                    ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
                }
#ifdef MEM_STATISTIC
                used_mem += (size + MEM_BLOCK_SIZE);
                if (max_mem < used_mem)
                {
                    max_mem = used_mem;
                }
#endif
            }
            else
            {
                /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
                 * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
                 * take care of this).
                 * -> near fit or excact fit: do not split, no mem2 creation
                 * also can't move mem->next directly behind mem, since mem->next
                 * will always be used at this point!
                 */
                mem->used = 1;
#ifdef MEM_STATISTIC
                used_mem += mem->next - ((uint8_t *)mem - heap_ptr);
                if (max_mem < used_mem)
                {
                    max_mem = used_mem;
                }
#endif
            }
            /* set memory block magic */
            mem->magic = HEAP_MAGIC;

            if (mem == lfree)
            {
                /* Find next free block after mem and update lowest free pointer */
                while (lfree->used && lfree != heap_end)
                {
                    lfree = (struct heap_mem *)&heap_ptr[lfree->next];
                }

                MEM_ASSERT(((lfree == heap_end) || (!lfree->used)));
            }
#ifdef MEM_SAFETY
            sem_post(&heap_sem);
#endif
            MEM_ASSERT((uint32_t)mem + MEM_BLOCK_SIZE + size <= (uint32_t)heap_end);
            MEM_ASSERT((uint32_t)((uint8_t *)mem + MEM_BLOCK_SIZE) % MEM_ALIGN_BYTE == 0);
            MEM_ASSERT((((uint32_t)mem) & (MEM_ALIGN_BYTE - 1)) == 0);

            MEM_DEBUG("allocate memory at 0x%x, size: %d",
                        (uint32_t)((uint8_t *)mem + MEM_BLOCK_SIZE),
                        (uint32_t)(mem->next - ((uint8_t *)mem - heap_ptr)));

            /* return the memory data except mem struct */
            return (uint8_t *)mem + MEM_BLOCK_SIZE;
        }
    }
#ifdef MEM_SAFETY
    sem_post(&heap_sem);
#endif
    return NULL;
}
/******************************************************************************
* function:
*         qaeCryptoMemFree(void *ptr)
*
* @param[in] ptr, address of start of usable memory
*
* description:
*   Free a block of memory previously allocated by this allocator.
*
******************************************************************************/
void qaeCryptoMemFree(void *ptr)
{
    MEM_DEBUG("%s: Address: %p\n", __func__, ptr);
    if (NULL != ptr)
        crypto_free_to_slab(ptr);
}
/*****************************************************************************
 * function:
 *         crypto_create_slab(int size, int pool_index, int memfd)
 *
 * @param[in] size, the size of the slots within the slab. Note that this is
 *                  not the size of the slab itself
 * @param[in] pool_index, the index of the slot pool
 * @param[in] memfd, the file descriptor of the memory driver
 * @retval qae_slab*, a pointer to the new slab.
 *
 * @description
 *      create a new slab and add it to the linked list
 *      retval pointer to the new slab
 *
 *****************************************************************************/
static qae_slab *crypto_create_slab(int size, int pool_index, int memfd)
{
    int i = 0;
    int nslot = 0;
    qat_contig_mem_config qmcfg = { 0, (uintptr_t) NULL, 0, (uintptr_t) NULL };
    qae_slab *result = NULL;
    qae_slab *slb = NULL;
    qae_slot *slt = NULL;
    QAE_UINT alignment;

    qmcfg.length = SLAB_SIZE;
#ifdef USE_QAT_CONTIG_MEM
    if (ioctl(memfd, QAT_CONTIG_MEM_MALLOC, &qmcfg) == -1) {
        static char errmsg[LINE_MAX];

        snprintf(errmsg, LINE_MAX, "ioctl QAT_CONTIG_MEM_MALLOC(%d)",
                 qmcfg.length);
        perror(errmsg);
        goto exit;
    }
    if ((slb =
         mmap(NULL, qmcfg.length*QAT_CONTIG_MEM_MMAP_ADJUSTMENT,
              PROT_READ | PROT_WRITE,
              MAP_SHARED | MAP_LOCKED, memfd,
              qmcfg.virtualAddress)) == MAP_FAILED) {
        static char errmsg[LINE_MAX];
        snprintf(errmsg, LINE_MAX, "mmap: %d %s", errno, strerror(errno));
        perror(errmsg);
        goto exit;
    }
#endif
    MEM_DEBUG("%s slot size %d\n", __func__, size);
    slb->slot_size = size;
    slb->next_slot = NULL;
    slb->sig = SIG_ALLOC;
    slb->used_slots = 0;


    for (i = sizeof(qae_slab); SLAB_SIZE - sizeof(qat_contig_mem_config)
         - i >= size; i += size) {
        slt = (qae_slot *) ((unsigned char *)slb + i);
        alignment =
            QAE_BYTE_ALIGNMENT -
            (((QAE_UINT) slt + sizeof(qae_slot)) % QAE_BYTE_ALIGNMENT);
        slt = (qae_slot *) (((QAE_UINT) slt) + alignment);
        slt->next = slb->next_slot;
        slt->pool_index = pool_index;
        slt->sig = SIG_FREE;
        slt->file = NULL;
        slt->line = 0;
        slb->next_slot = slt;
        nslot++;
        slt->slab = slb;
    }
    slb->total_slots = nslot;

    /*
     * Make sure the update of the slab list is the last thing to be done.
     * This means it is not necessary to lock against anyone iterating the
     * list from the head
     */

    result = slb;
    MEM_DEBUG("%s slab %p last slot is %p, count is %d\n", __func__, slb, slt,
          nslot);
 exit:
    return result;
}