%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /usr/src/veeamsnap-6.1.2.1781/
Upload File :
Create Path :
Current File : //usr/src/veeamsnap-6.1.2.1781/page_array.c

// Copyright (c) Veeam Software Group GmbH

#include "stdafx.h"
#include "page_array.h"

#define SECTION "page_array"
//#include "log_format.h"

atomic64_t page_alloc_count;
atomic64_t page_free_count;
atomic64_t page_array_alloc_count;
atomic64_t page_array_free_count;

void page_arrays_init( void )
{
    atomic64_set( &page_alloc_count, 0 );
    atomic64_set( &page_free_count, 0 );

    atomic64_set( &page_array_alloc_count, 0 );
    atomic64_set( &page_array_free_count, 0 );
}

void page_arrays_print_state( void )
{
    log_tr( "" );
    log_tr( "Page array state:" );
    log_tr_lld( "pages allocated: ", (long long int)atomic64_read( &page_alloc_count ) );
    log_tr_lld( "pages freed: ", (long long int)atomic64_read( &page_free_count ) );
    log_tr_lld( "pages in use: ", (long long int)atomic64_read( &page_alloc_count ) - (long long int)atomic64_read( &page_free_count ) );

    log_tr_lld( "arrays allocated: ", (long long int)atomic64_read( &page_array_alloc_count ) );
    log_tr_lld( "arrays freed: ", (long long int)atomic64_read( &page_array_free_count ) );
    log_tr_lld( "arrays in use: ", (long long int)atomic64_read( &page_array_alloc_count ) - (long long int)atomic64_read( &page_array_free_count ) );
}

page_array_t* page_array_alloc( size_t count, int gfp_opt )
{
    int res = SUCCESS;
    size_t inx;
    page_array_t* arr = NULL;
    while (NULL == (arr = dbg_kzalloc( sizeof( page_array_t ) + count*sizeof( page_info_t ), gfp_opt ))){
        log_err( "Failed to allocate page_array buffer" );
        return NULL;
    }
    arr->pg_cnt = count;
    for (inx = 0; inx < arr->pg_cnt; ++inx){
        if (NULL == (arr->pg[inx].page = alloc_page( gfp_opt ))){
            log_err( "Failed to allocate page" );
            res = -ENOMEM;
            break;
        }
        arr->pg[inx].addr = page_address( arr->pg[inx].page );
        atomic64_inc( &page_alloc_count );
    }
    atomic64_inc( &page_array_alloc_count );

    if (SUCCESS == res)
        return arr;

    page_array_free( arr );
    return NULL;
}

void page_array_free( page_array_t* arr )
{
    size_t inx;
    size_t count = arr->pg_cnt;
    if (arr == NULL)
        return;

    for (inx = 0; inx < count; ++inx){
        if (arr->pg[inx].page != NULL){
            free_page( (unsigned long)(arr->pg[inx].addr) );
            atomic64_inc( &page_free_count );
        }
    }
    dbg_kfree( arr );
    atomic64_inc( &page_array_free_count );
}

size_t page_array_pages2mem( void* dst, size_t arr_ofs, page_array_t* arr, size_t length )
{
    int page_inx = arr_ofs / PAGE_SIZE;
    size_t processed_len = 0;
    void* src;
    {//first
        size_t unordered = arr_ofs & (PAGE_SIZE - 1);
        size_t page_len = min_t( size_t, ( PAGE_SIZE - unordered ), length );

        src = arr->pg[page_inx].addr;
        memcpy( dst + processed_len, src + unordered, page_len );

        ++page_inx;
        processed_len += page_len;
    }
    while ((processed_len < length) && (page_inx < arr->pg_cnt))
    {
        size_t page_len = min_t( size_t, PAGE_SIZE, (length - processed_len) );

        src = arr->pg[page_inx].addr;
        memcpy( dst + processed_len, src, page_len );

        ++page_inx;
        processed_len += page_len;
    }

    return processed_len;
}

size_t page_array_mem2pages( void* src, size_t arr_ofs, page_array_t* arr, size_t length )
{
    int page_inx = arr_ofs / PAGE_SIZE;
    size_t processed_len = 0;
    void* dst;
    {//first
        size_t unordered = arr_ofs & (PAGE_SIZE - 1);
        size_t page_len = min_t( size_t, (PAGE_SIZE - unordered), length );

        dst = arr->pg[page_inx].addr;
        memcpy( dst + unordered, src + processed_len, page_len );

        ++page_inx;
        processed_len += page_len;
    }
    while ((processed_len < length) && (page_inx < arr->pg_cnt))
    {
        size_t page_len = min_t( size_t, PAGE_SIZE, (length - processed_len) );

        dst = arr->pg[page_inx].addr;
        memcpy( dst, src + processed_len, page_len );

        ++page_inx;
        processed_len += page_len;
    }

    return processed_len;
}

size_t page_array_page2user( char __user* dst_user, size_t arr_ofs, page_array_t* arr, size_t length )
{
    size_t left_data_length;
    int page_inx = arr_ofs / PAGE_SIZE;
    size_t processed_len = 0;

    size_t unordered = arr_ofs & (PAGE_SIZE - 1);
    if (unordered != 0)//first
    {
        size_t page_len = min_t( size_t, (PAGE_SIZE - unordered), length );

        left_data_length = copy_to_user( dst_user + processed_len, arr->pg[page_inx].addr  + unordered, page_len );
        if (0 != left_data_length){
            log_err( "Failed to copy data from page array to user buffer" );
            return processed_len;
        }

        ++page_inx;
        processed_len += page_len;
    }
    while ((processed_len < length) && (page_inx < arr->pg_cnt))
    {
        size_t page_len = min_t( size_t, PAGE_SIZE, (length - processed_len) );

        left_data_length = copy_to_user( dst_user + processed_len, arr->pg[page_inx].addr, page_len );
        if (0 != left_data_length){
            log_err( "Failed to copy data from page array to user buffer" );
            break;
        }

        ++page_inx;
        processed_len += page_len;
    }

    return processed_len;
}

size_t page_array_user2page( const char __user* src_user, size_t arr_ofs, page_array_t* arr, size_t length )
{
    size_t left_data_length;
    int page_inx = arr_ofs / PAGE_SIZE;
    size_t processed_len = 0;

    size_t unordered = arr_ofs & (PAGE_SIZE - 1);
    if (unordered != 0)//first
    {
        size_t page_len = min_t( size_t, (PAGE_SIZE - unordered), length );

        left_data_length = copy_from_user( arr->pg[page_inx].addr + unordered, src_user + processed_len, page_len );
        if (0 != left_data_length){
            log_err( "Failed to copy data from page array to user buffer" );
            return processed_len;
        }

        ++page_inx;
        processed_len += page_len;
    }
    while ((processed_len < length) && (page_inx < arr->pg_cnt))
    {
        size_t page_len = min_t( size_t, PAGE_SIZE, (length - processed_len) );

        left_data_length = copy_from_user( arr->pg[page_inx].addr, src_user + processed_len, page_len );
        if (0 != left_data_length){
            log_err( "Failed to copy data from page array to user buffer" );
            break;
        }

        ++page_inx;
        processed_len += page_len;
    }

    return processed_len;
}

size_t page_count_calc( size_t buffer_size )
{
    size_t page_count = buffer_size / PAGE_SIZE;

    if ( buffer_size & (PAGE_SIZE - 1) )
        page_count += 1;
    return page_count;
}

size_t page_count_calc_sectors( sector_t range_start_sect, sector_t range_cnt_sect )
{
    size_t page_count = range_cnt_sect / SECTORS_IN_PAGE;

    if (unlikely( range_cnt_sect & (SECTORS_IN_PAGE - 1) ))
        page_count += 1;
    return page_count;
}

void* page_get_element( page_array_t* arr, size_t index, size_t sizeof_element )
{
    size_t elements_in_page = PAGE_SIZE / sizeof_element;
    size_t pg_inx = index / elements_in_page;
    size_t pg_ofs = (index - (pg_inx * elements_in_page)) * sizeof_element;

    return (arr->pg[pg_inx].addr + pg_ofs);
}

char* page_get_sector( page_array_t* arr, sector_t arr_ofs )
{
    size_t pg_inx = arr_ofs >> (PAGE_SHIFT - SECTOR_SHIFT);
    size_t pg_ofs = sector_to_size( arr_ofs & ((1 << (PAGE_SHIFT - SECTOR_SHIFT)) - 1) );

    return (arr->pg[pg_inx].addr + pg_ofs);
}

void page_array_memset( page_array_t* arr, int value )
{
    size_t inx;
    for (inx = 0; inx < arr->pg_cnt; ++inx){
        void* ptr = arr->pg[inx].addr;
        memset( ptr, value, PAGE_SIZE );
    }
}

void page_array_memcpy( page_array_t* dst, page_array_t* src )
{
    size_t inx;
    size_t count = min_t( size_t, dst->pg_cnt, src->pg_cnt );

    for (inx = 0; inx < count; ++inx){
        void* dst_ptr = dst->pg[inx].addr ;
        void* src_ptr = src->pg[inx].addr;
        memcpy( dst_ptr, src_ptr, PAGE_SIZE );
    }
}

#define _PAGE_INX_CHECK(arr, inx, page_inx) \
if (page_inx >= arr->pg_cnt){ \
    log_err_sz( "Invalid index ", inx ); \
    log_err_sz( "page_inx=", page_inx ); \
    log_err_sz( "page_cnt=", arr->pg_cnt ); \
    return -ENODATA; \
}

#define POINTERS_IN_PAGE (PAGE_SIZE/sizeof(void*))

int page_array_ptr_get(page_array_t* arr, size_t inx, void** value)
{

    size_t page_inx = inx / POINTERS_IN_PAGE;
    _PAGE_INX_CHECK(arr, inx, page_inx);

    {
        size_t pos = inx & (POINTERS_IN_PAGE - 1);
        void** ptr = arr->pg[page_inx].addr;
        *value = ptr[pos];
    }
    return SUCCESS;
}

int page_array_ptr_set(page_array_t* arr, size_t inx, void* value)
{
    size_t page_inx = inx / POINTERS_IN_PAGE;
    _PAGE_INX_CHECK(arr, inx, page_inx);

    {
        size_t byte_pos = inx & (POINTERS_IN_PAGE - 1);
        void** ptr = arr->pg[page_inx].addr;
        ptr[byte_pos] = value;
    }
    return SUCCESS;
}

int page_array_byte_get( page_array_t* arr, size_t inx, byte_t* value )
{
    size_t page_inx = inx >> PAGE_SHIFT;
    _PAGE_INX_CHECK( arr, inx, page_inx );

    {
        size_t byte_pos = inx & (PAGE_SIZE - 1);
        byte_t* ptr = arr->pg[page_inx].addr;
        *value = ptr[byte_pos];
    }
    return SUCCESS;
}

int page_array_byte_set( page_array_t* arr, size_t inx, byte_t value )
{
    size_t page_inx = inx >> PAGE_SHIFT;
    _PAGE_INX_CHECK( arr, inx, page_inx );

    {
        size_t byte_pos = inx & (PAGE_SIZE - 1);
        byte_t* ptr = arr->pg[page_inx].addr;
        ptr[byte_pos] = value;
    }
    return SUCCESS;
}

int page_array_bit_get( page_array_t* arr, size_t inx, bool* value )
{
    byte_t v;
    size_t byte_inx = (inx / BITS_PER_BYTE);
    int res = page_array_byte_get( arr, byte_inx, &v );
    if (SUCCESS != res)
        return res;

    {
        size_t bit_inx = (inx & (BITS_PER_BYTE - 1));
        *value = v & (1 << bit_inx);
    }
    return SUCCESS;
}

int page_array_bit_set( page_array_t* arr, size_t inx, bool value )
{
    size_t byte_inx = (inx / BITS_PER_BYTE);
    size_t page_inx = byte_inx >> PAGE_SHIFT;
    _PAGE_INX_CHECK( arr, inx, page_inx );

    {
        byte_t v;
        size_t bit_inx = (inx & (BITS_PER_BYTE - 1));

        size_t byte_pos = byte_inx & (PAGE_SIZE - 1);
        byte_t* ptr = arr->pg[page_inx].addr;

        v = ptr[byte_pos];
        if (value){
            if (unlikely(v & (1 << bit_inx)))
                return -EALREADY;
            v |= (1 << bit_inx);
        }
        else{
            if (unlikely(0 == (v & (1 << bit_inx))))
                return -EALREADY;
            v &= ~(1 << bit_inx);
        }

        ptr[byte_pos] = v;
    }
    return SUCCESS;
}

Zerion Mini Shell 1.0