%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/ctrl_fops.c

// Copyright (c) Veeam Software Group GmbH

#include "stdafx.h"
#include <linux/poll.h>
#include <linux/uaccess.h>
#include <linux/sysfs.h>

#include "veeamsnap_ioctl.h"
#include "version.h"
#include "ctrl_pipe.h"
#include "tracking.h"
#include "snapshot.h"

#include "snapstore.h"
#include "snapdata_collect.h"
#include "snapimage.h"
#include "tracker.h"
#include "page_array.h"
#include "blk_deferred.h"
#include "enum_block.h"
#include "kernel_entries.h"

#define SECTION "ctrl_fops "
#include "log_format.h"
#include "cbt_persistent.h"

static atomic_t g_dev_open_cnt = ATOMIC_INIT( 0 );

static struct ioctl_getversion_s version = {
    .major        = FILEVER_MAJOR,
    .minor        = FILEVER_MINOR,
    .revision    = FILEVER_REVISION,
    .build        = FILEVER_BUILD
};


void ctrl_init( void )
{
    ctrl_pipe_init( );
}

void ctrl_done( void )
{
    ctrl_pipe_done( );
}

ssize_t ctrl_read(struct file *fl, char __user *buffer, size_t length, loff_t *offset)
{
    ssize_t bytes_read = 0;
    ctrl_pipe_t* pipe = (ctrl_pipe_t*)fl->private_data;

    if (NULL == pipe) {
        log_err("Unable to read from pipe: invalid pipe pointer");
        return -EINVAL;
    }

    bytes_read = ctrl_pipe_read( pipe, buffer, length );
    if (bytes_read == 0)
        if (fl->f_flags & O_NONBLOCK)
            bytes_read = -EAGAIN;

    return bytes_read;
}


ssize_t ctrl_write( struct file *fl, const char __user *buffer, size_t length, loff_t *offset )
{
    ctrl_pipe_t* pipe = (ctrl_pipe_t*)fl->private_data;

    if (NULL == pipe){
        log_err( "Unable to write into pipe: invalid pipe pointer" );
        return -EINVAL;
    }

    return ctrl_pipe_write(pipe, buffer, length);
}


unsigned int ctrl_poll( struct file *fl, struct poll_table_struct *wait )
{
    ctrl_pipe_t* pipe = (ctrl_pipe_t*)fl->private_data;

    if (NULL == pipe) {
        log_err("Unable to poll pipe: invalid pipe pointer");
        return -EINVAL;
    }

    return ctrl_pipe_poll( pipe );
}


int ctrl_open(struct inode *inode, struct file *fl)
{
    fl->f_pos = 0;

    try_module_get( THIS_MODULE );

    fl->private_data = (void*)ctrl_pipe_get_resource( ctrl_pipe_new( ) );
    if (fl->private_data == NULL){
        log_err( "Failed to open ctrl file" );
        return -ENOMEM;
    }

    atomic_inc( &g_dev_open_cnt );
    //log_tr( "Open ctrl file" );

    return SUCCESS;
}


int ctrl_release(struct inode *inode, struct file *fl)
{
    int result = SUCCESS;

    if ( atomic_read( &g_dev_open_cnt ) > 0 ){
        module_put( THIS_MODULE );
        ctrl_pipe_put_resource( (ctrl_pipe_t*)fl->private_data );

        atomic_dec( &g_dev_open_cnt );
        //log_tr( "Close ctrl file" );
    }
    else{
        log_err( "Unable to close ctrl file: the file is already closed" );
        result = -EALREADY;
    }

    return result;
}


int ioctl_compatibility_flags( unsigned long arg )
{
    struct ioctl_compatibility_flags_s param;

    logging_renew_check( );

    //log_tr( "Get compatibility flags" );

    param.flags = 0;
    param.flags |= VEEAMSNAP_COMPATIBILITY_SNAPSTORE;
#ifdef SNAPSTORE_MULTIDEV
    param.flags |= VEEAMSNAP_COMPATIBILITY_MULTIDEV;
#endif
    param.flags |= VEEAMSNAP_COMPATIBILITY_KENTRY;

    if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_compatibility_flags_s ) )){
        log_err( "Unable to get compatibility flags: invalid user buffer" );
        return -EINVAL;
    }

    return SUCCESS;
}

int ioctl_get_version( unsigned long arg )
{
    log_tr( "Get version" );

    if (0 != copy_to_user( (void*)arg, &version, sizeof( struct ioctl_getversion_s ) )){
        log_err( "Unable to get version: invalid user buffer" );
        return -ENODATA;
    }

    return SUCCESS;
}

int ioctl_tracking_add( unsigned long arg )
{
    struct ioctl_dev_id_s dev;

    if (0 != copy_from_user( &dev, (void*)arg, sizeof( struct ioctl_dev_id_s ) )){
        log_err( "Unable to add device under tracking: invalid user buffer" );
        return -ENODATA;
    }

    return tracking_add( MKDEV( dev.major, dev.minor ), CBT_BLOCK_SIZE_DEGREE, 0ull );
}

int ioctl_tracking_remove( unsigned long arg )
{
    struct ioctl_dev_id_s dev;

    if (0 != copy_from_user( &dev, (void*)arg, sizeof( struct ioctl_dev_id_s ) )){
        log_err( "Unable to remove device from tracking: invalid user buffer" );
        return -ENODATA;
    }
    return tracking_remove( MKDEV( dev.major, dev.minor ) );;
}

int ioctl_tracking_collect( unsigned long arg )
{
    int res;
    struct ioctl_tracking_collect_s get;

    log_tr( "Collecting tracking devices:" );

    if (0 != copy_from_user( &get, (void*)arg, sizeof( struct ioctl_tracking_collect_s ) )){
        log_err( "Unable to collect tracking devices: invalid user buffer" );
        return -ENODATA;
    }

    if (get.p_cbt_info == NULL){
        res = tracking_collect(0x7FFFffff, NULL, &get.count);
        if (SUCCESS == res){
            if (0 != copy_to_user((void*)arg, (void*)&get, sizeof(struct ioctl_tracking_collect_s))){
                log_err("Unable to collect tracking devices: invalid user buffer for arguments");
                res = -ENODATA;
            }
        }
        else{
            log_err_d("Failed to execute tracking_collect. errno=", res);
        }
    }
    else
    {
        struct cbt_info_s* p_cbt_info = NULL;

        p_cbt_info = dbg_kzalloc(get.count * sizeof(struct cbt_info_s), GFP_KERNEL);
        if (NULL == p_cbt_info){
            log_err("Unable to collect tracing devices: cannot allocate memory");
            return -ENOMEM;
        }

        do{
            res = tracking_collect(get.count, p_cbt_info, &get.count);
            if (SUCCESS != res){
                log_err_d("Failed to execute tracking_collect. errno=", res);
                break;
            }
            if (0 != copy_to_user(get.p_cbt_info, p_cbt_info, get.count*sizeof(struct cbt_info_s))){
                log_err("Unable to collect tracking devices: invalid user buffer for CBT info");
                res = -ENODATA;
                break;
            }

            if (0 != copy_to_user((void*)arg, (void*)&get, sizeof(struct ioctl_tracking_collect_s))){
                log_err("Unable to collect tracking devices: invalid user buffer for arguments");
                res = -ENODATA;
                break;
            }

        } while (false);

        dbg_kfree(p_cbt_info);
        p_cbt_info = NULL;
    }
    return res;
}

int ioctl_tracking_block_size( unsigned long arg )
{
    unsigned int blk_sz = CBT_BLOCK_SIZE;

    if (0 != copy_to_user( (void*)arg, &blk_sz, sizeof( unsigned int ) )){
        log_err( "Unable to get tracking block size: invalid user buffer for arguments" );
        return -ENODATA;
    }
    return SUCCESS;
}

int ioctl_tracking_read_cbt_map( unsigned long arg )
{
    struct ioctl_tracking_read_cbt_bitmap_s readbitmap;

    if (0 != copy_from_user( &readbitmap, (void*)arg, sizeof( struct ioctl_tracking_read_cbt_bitmap_s ) )){
        log_err( "Unable to read CBT map: invalid user buffer" );
        return -ENODATA;
    }

    return tracking_read_cbt_bitmap(
        MKDEV( readbitmap.dev_id.major, readbitmap.dev_id.minor ),
        readbitmap.offset,
        readbitmap.length,
        (void*)readbitmap.buff
    );
}

int ioctl_tracking_mark_dirty_blocks(unsigned long arg)
{
    struct ioctl_tracking_mark_dirty_blocks_s param;
    struct block_range_s* p_dirty_blocks;
    size_t buffer_size;
    int result = SUCCESS;

    if (0 != copy_from_user(&param, (void*)arg, sizeof(struct ioctl_tracking_mark_dirty_blocks_s))){
        log_err("Unable to mark dirty blocks: invalid user buffer");
        return -ENODATA;
    }

    buffer_size = param.count * sizeof(struct block_range_s);
    p_dirty_blocks = dbg_kzalloc(buffer_size, GFP_KERNEL);
    if (p_dirty_blocks == NULL){
        log_err_format("Unable to mark dirty blocks: cannot allocate [%ld] bytes", buffer_size);
        return -ENOMEM;
    }

    do{
        if (0 != copy_from_user(p_dirty_blocks, (void*)param.p_dirty_blocks, buffer_size)){
            log_err("Unable to mark dirty blocks: invalid user buffer");
            result = -ENODATA;
            break;
        }

        result = snapimage_mark_dirty_blocks(MKDEV(param.image_dev_id.major, param.image_dev_id.minor), p_dirty_blocks, param.count);
    } while (false);
    dbg_kfree(p_dirty_blocks);

    return result;
}

int ioctl_set_kernel_entries(unsigned long arg)
{
    int ret = 0;
    struct ioctl_set_kernel_entries_s param;
    struct kernel_entry_s *entries = NULL;
    size_t entries_size;
    size_t inx;
    char *name;
    unsigned long symbols_offset;

    if (0 != copy_from_user(&param, (void*)arg, sizeof(struct ioctl_set_kernel_entries_s))) {
        log_err("Unable to set kernel entries: invalid user buffer");
        return -ENODATA;
    }

    entries_size = param.count * sizeof(struct kernel_entry_s);
    entries = dbg_kzalloc(entries_size, GFP_KERNEL);
    if (!entries) {
        log_err_format("Unable to set kernel entries: cannot allocate [%ld] bytes", entries_size);
        return -ENOMEM;
    }

    if (0 != copy_from_user(entries, param.entries, entries_size)) {
        log_err("Unable to set kernel entries: invalid user buffer");
        ret = -ENODATA;
        goto out;
    }

    // check first entry 
    name = strndup_user(entries[0].name, KERNEL_ENTRY_NAME_MAX);
    if (IS_ERR(name)) {
        log_err("Unable to set kernel entries: invalid user buffer");
        ret = PTR_ERR(name);
        goto out;
    }
    if (strcmp(name, KERNEL_ENTRY_BASE_NAME) != 0)
        ret = -EINVAL;
    kfree(name);
    if (ret) {
        log_err_s("Invalid first kernel entry: ", name);
        goto out;
    }
    symbols_offset = (unsigned long)(KERNEL_ENTRY_BASE_FUNCTION) - (unsigned long)entries[0].addr;

    for (inx=1; inx<param.count; inx++) {
        name = strndup_user(entries[inx].name, KERNEL_ENTRY_NAME_MAX);
        if (IS_ERR(name)) {
            log_err("Unable to set kernel entries: invalid user buffer");
            ret = PTR_ERR(name);
            break;
        }

        log_tr_s("Set address for function ", name);
        ret = ke_set_addr(name, (void *)(entries[inx].addr + symbols_offset));
        kfree(name);
        if (ret)
            break;
    }

out:
    dbg_kfree(entries);
    return ret;
}

int ioctl_get_unresolved_kernel_entries(unsigned long arg)
{
    int ret = 0;
    struct ioctl_get_unresolved_kernel_entries_s* param;

    param = dbg_kzalloc(sizeof(struct ioctl_get_unresolved_kernel_entries_s), GFP_KERNEL);
    if (!param) {
        log_err("Unable to get unresolved kernel entries: cannot allocate buffer");
        return -ENOMEM;
    }

    ret = ke_get_unresolved(param->buf, sizeof(param->buf));
    if (ret < 0) {
        log_err("Unable to get unresolved kernel entries");
        goto out;
    }
    if (ret == 0)
        goto out;

    if (0 != copy_to_user((void*)arg, param, sizeof(struct ioctl_get_unresolved_kernel_entries_s))) {
        log_err("Unable to get unresolved kernel entries: invalid user buffer for arguments");
        ret = -ENODATA;
    }
out:
    dbg_kfree(param);
    return ret;
}

int ioctl_snapshot_create( unsigned long arg )
{
    size_t dev_id_buffer_size;
    int status;
    struct ioctl_snapshot_create_s param;
    struct ioctl_dev_id_s* pk_dev_id = NULL;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapshot_create_s ) )){
        log_err( "Unable to create snapshot: invalid user buffer" );
        return -ENODATA;
    }

    dev_id_buffer_size = sizeof( struct ioctl_dev_id_s ) * param.count;
    pk_dev_id = dbg_kzalloc( dev_id_buffer_size, GFP_KERNEL );
    if (NULL == pk_dev_id){
        log_err_format( "Unable to create snapshot: cannot allocate [%ld] bytes.", dev_id_buffer_size );
        return -ENOMEM;
    }

    do{
        size_t dev_buffer_size;
        dev_t* p_dev = NULL;
        int inx = 0;

        if (0 != copy_from_user( pk_dev_id, (void*)param.p_dev_id, param.count*sizeof( struct ioctl_dev_id_s ) )){
            log_err( "Unable to create snapshot: invalid user buffer for parameters." );
            status = -ENODATA;
            break;
        }

        dev_buffer_size = sizeof( dev_t ) * param.count;
        p_dev = dbg_kzalloc( dev_buffer_size, GFP_KERNEL );
        if (NULL == p_dev){
            log_err_format( "Unable to create snapshot: cannot allocate [%ld] bytes", dev_buffer_size );
            status = -ENOMEM;
            break;
        }

        for (inx = 0; inx < param.count; ++inx)
            p_dev[inx] = MKDEV( pk_dev_id[inx].major, pk_dev_id[inx].minor );

        status = snapshot_Create(p_dev, param.count, CBT_BLOCK_SIZE_DEGREE, &param.snapshot_id);

        dbg_kfree( p_dev );
        p_dev = NULL;

    } while (false);
    dbg_kfree( pk_dev_id );
    pk_dev_id = NULL;

    if (status == SUCCESS){
        if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_snapshot_create_s ) )){
            log_err( "Unable to create snapshot: invalid user buffer" );
            status = -ENODATA;
        }
    }

    return status;
}

int ioctl_snapshot_destroy( unsigned long arg )
{
    unsigned long long param;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( unsigned long long ) )){
        log_err( "Unable to destroy snapshot: invalid user buffer" );
        return -ENODATA;
    }

    return snapshot_Destroy( param );
}
//////////////////////////////////////////////////////////////////////////
int ioctl_snapstore_create( unsigned long arg )
{
    int res = SUCCESS;
    struct ioctl_snapstore_create_s param;
    struct ioctl_dev_id_s* pk_dev_id = NULL;
    size_t dev_id_buffer_size;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapstore_create_s ) )){
        log_err( "Unable to create snapstore: invalid user buffer" );
        return -EINVAL;
    }

    dev_id_buffer_size = sizeof( struct ioctl_dev_id_s ) * param.count;
    pk_dev_id = dbg_kzalloc( dev_id_buffer_size, GFP_KERNEL );
    if (NULL == pk_dev_id){
        log_err_format( "Unable to create snapstore: cannot allocate [%ld] bytes", dev_id_buffer_size );
        return -ENOMEM;
    }

    do{
        size_t inx = 0;
        dev_t* dev_id_set = NULL;
        veeam_uuid_t* id = (veeam_uuid_t*)param.id;
        dev_t snapstore_dev_id;
        size_t dev_id_set_length = (size_t)param.count;
        size_t dev_id_set_buffer_size;

        if ((0 == param.snapstore_dev_id.major) && (0 == param.snapstore_dev_id.minor))
            snapstore_dev_id = 0; //memory snapstore
        else if ((-1 == param.snapstore_dev_id.major) && (-1 == param.snapstore_dev_id.minor))
            snapstore_dev_id = 0xFFFFffff; //multidevice snapstore
        else
            snapstore_dev_id = MKDEV( param.snapstore_dev_id.major, param.snapstore_dev_id.minor ); //ordinal file snapstore

        if (0 != copy_from_user( pk_dev_id, (void*)param.p_dev_id, param.count*sizeof( struct ioctl_dev_id_s ) )){
            log_err( "Unable to create snapstore: invalid user buffer for parameters" );
            res = -ENODATA;
            break;
        }

        dev_id_set_buffer_size = sizeof( dev_t ) * param.count;
        dev_id_set = dbg_kzalloc( dev_id_set_buffer_size, GFP_KERNEL );
        if (NULL == dev_id_set){
            log_err_format( "Unable to create snapstore: cannot allocate [%ld] bytes", dev_id_set_buffer_size );
            res = -ENOMEM;
            break;
        }

        for (inx = 0; inx < dev_id_set_length; ++inx)
            dev_id_set[inx] = MKDEV( pk_dev_id[inx].major, pk_dev_id[inx].minor );

        res = snapstore_create( id, snapstore_dev_id, dev_id_set, dev_id_set_length );

        dbg_kfree( dev_id_set );
    } while (false);
    dbg_kfree( pk_dev_id );

    return res;
}

int ioctl_snapstore_file( unsigned long arg )
{
    int res = SUCCESS;
    struct ioctl_snapstore_file_add_s param;
    page_array_t* ranges = NULL;//struct ioctl_range_s* ranges = NULL;
    size_t ranges_buffer_size;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapstore_file_add_s ) )){
        log_err( "Unable to add file to snapstore: invalid user buffer" );
        return -EINVAL;
    }

    ranges_buffer_size = sizeof( struct ioctl_range_s ) * param.range_count;

    ranges = page_array_alloc( page_count_calc( ranges_buffer_size ), GFP_KERNEL );
    if (NULL == ranges){
        log_err_format( "Unable to add file to snapstore: cannot allocate [%ld] bytes", ranges_buffer_size );
        return -ENOMEM;
    }

    do{
        veeam_uuid_t* id = (veeam_uuid_t*)(param.id);
        size_t ranges_cnt = (size_t)param.range_count;

        if (ranges_buffer_size != page_array_user2page( (void*)param.ranges, 0, ranges, ranges_buffer_size ) ){
            log_err( "Unable to add file to snapstore: invalid user buffer for parameters." );
            res = -ENODATA;
            break;
        }

        res = snapstore_add_file( id, ranges, ranges_cnt );
    }while (false);
    page_array_free( ranges );

    return res;
}

int ioctl_snapstore_memory( unsigned long arg )
{
    int res = SUCCESS;
    struct ioctl_snapstore_memory_limit_s param;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapstore_memory_limit_s ) )){
        log_err( "Unable to add memory block to snapstore: invalid user buffer" );
        return -EINVAL;
    }

    res = snapstore_add_memory( (veeam_uuid_t*)param.id, param.size );

    return res;
}
int ioctl_snapstore_cleanup( unsigned long arg )
{
    int res = SUCCESS;
    struct ioctl_snapstore_cleanup_s param;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapstore_cleanup_s ) )){
        log_err( "Unable to perform snapstore cleanup: invalid user buffer" );
        return -EINVAL;
    }
    log_tr_uuid("id=", ((veeam_uuid_t*)(param.id)));
    res = snapstore_cleanup((veeam_uuid_t*)param.id, &param.filled_bytes);

    if (res == SUCCESS){
        if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_snapstore_cleanup_s ) )){
            log_err( "Unable to perform snapstore cleanup: invalid user buffer" );
            res = -ENODATA;
        }
    }

    return res;
}

#ifdef SNAPSTORE_MULTIDEV
int ioctl_snapstore_file_multidev( unsigned long arg )
    {
    int res = SUCCESS;
    struct ioctl_snapstore_file_add_multidev_s param;
    page_array_t* ranges = NULL;//struct ioctl_range_s* ranges = NULL;
    size_t ranges_buffer_size;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_snapstore_file_add_multidev_s ) )){
        log_err( "Unable to add file to multidev snapstore: invalid user buffer" );
        return -EINVAL;
    }

    ranges_buffer_size = sizeof( struct ioctl_range_s ) * param.range_count;

    ranges = page_array_alloc( page_count_calc( ranges_buffer_size ), GFP_KERNEL );
    if (NULL == ranges){
        log_err_format( "Unable to add file to multidev snapstore: cannot allocate [%ld] bytes", ranges_buffer_size );
        return -ENOMEM;
    }

    do{
        veeam_uuid_t* id = (veeam_uuid_t*)(param.id);
        dev_t snapstore_device = MKDEV( param.dev_id.major, param.dev_id.minor );
        size_t ranges_cnt = (size_t)param.range_count;

        if (ranges_buffer_size != page_array_user2page( (void*)param.ranges, 0, ranges, ranges_buffer_size )){
            log_err( "Unable to add file to snapstore: invalid user buffer for parameters." );
            res = -ENODATA;
            break;
        }

        res = snapstore_add_multidev( id, snapstore_device, ranges, ranges_cnt );
    } while (false);
    page_array_free( ranges );

    return res;
}

#endif
//////////////////////////////////////////////////////////////////////////

int ioctl_snapshot_errno( unsigned long arg )
{
    int res;
    struct ioctl_snapshot_errno_s param;

    //log_tr( "Snapshot get errno for device");

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_dev_id_s ) )){
        log_err( "Unable failed to get snapstore error code: invalid user buffer" );
        return -EINVAL;
    }

    res = snapstore_device_errno( MKDEV( param.dev_id.major, param.dev_id.minor ), &param.err_code );

    if (res != SUCCESS)
        return res;

    if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_snapshot_errno_s ) )){
        log_err( "Unable to get snapstore error code: invalid user buffer" );
        return -EINVAL;
    }

    return SUCCESS;
}

int ioctl_collect_snapshotdata_location_start( unsigned long arg )
{
    struct ioctl_collect_snapshotdata_location_start_s param;

    //log_tr( "Collect snapshot data location start" );

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_collect_snapshotdata_location_start_s ) )){
		log_err("Unable to collect location of snapstore file: invalid user buffer");
        return -EINVAL;
    }

    return snapdata_collect_LocationStart(
        MKDEV( param.dev_id.major, param.dev_id.minor ),
        param.magic_buff,
        param.magic_length
        );
}

int ioctl_collect_snapshotdata_location_get( unsigned long arg )
{
    int res;
    struct ioctl_collect_snapshotdata_location_get_s param;
    rangelist_t ranges;
    size_t ranges_count = 0;

    //log_tr( "Collect snapshot data location get" );

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_collect_snapshotdata_location_get_s ) )){
        log_err( "Unable to get location of snapstore file: invalid input buffer" );
        return -EINVAL;
    }

    rangelist_init( &ranges );
    do{
        res = snapdata_collect_LocationGet( MKDEV( param.dev_id.major, param.dev_id.minor ), &ranges, &ranges_count );
        if (res != SUCCESS){
            log_err_d( "Failed to get location of snapstore file. errno=", res );
            break;
        }

        if (param.ranges == NULL ){//It`s normal. It is range count getting
            res = SUCCESS;
            break;
        }

        if (param.range_count < ranges_count){
            log_err( "Unable to get location of snapstore file: invalid range array count" );
            log_err_d( "Buffer ranges available: ", param.range_count );
            log_err_sz( "Ranges needed: ", ranges_count );
            res = -EINVAL;
            break;
        }

        {
            size_t inx = 0;
            range_t  rg;
            struct ioctl_range_s rg_ctl;

            for (inx = 0; (SUCCESS == rangelist_get( &ranges, &rg )) && (inx < ranges_count); ++inx){
                rg_ctl.left = sector_to_streamsize( rg.ofs );
                rg_ctl.right = rg_ctl.left + sector_to_streamsize( rg.cnt );

                if (0 != copy_to_user( param.ranges + inx, &rg_ctl, sizeof( struct ioctl_range_s ) )){
                    log_err( "Unable to get location of snapstore file: invalid range array buffer" );
                    res = -EINVAL;
                    break;
                };
            }
        }
    } while (false);
    rangelist_done( &ranges );

    if (res == SUCCESS){
        param.range_count = ranges_count;
        if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_collect_snapshotdata_location_get_s ) )){
            log_err( "Unable to get location of snapstore file: invalid output buffer" );
            res = -EINVAL;
        }
    }

    return res;
}

int ioctl_collect_snapshotdata_location_complete( unsigned long arg )
{
    struct ioctl_collect_snapshotdata_location_complete_s param;

    //log_tr( "Collect snapshot data location complete" );

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_collect_snapshotdata_location_complete_s ) )){
        log_err( "Unable to collect location of snapstore file: invalid user buffer" );
        return -EINVAL;
    }

    return snapdata_collect_LocationComplete( MKDEV( param.dev_id.major, param.dev_id.minor ) );
}

int ioctl_collect_snapimages( unsigned long arg )
{
    int status = SUCCESS;
    struct ioctl_collect_shapshot_images_s param;

    if (0 != copy_from_user( &param, (void*)arg, sizeof( struct ioctl_collect_shapshot_images_s ) )){
        log_err( "Unable to collect snapshot images: invalid user buffer" );
        return -ENODATA;
    }

    status = snapimage_collect_images( param.count, param.p_image_info, &param.count );

    if (0 != copy_to_user( (void*)arg, &param, sizeof( struct ioctl_collect_shapshot_images_s ) )){
        log_err( "Unable to collect snapshot images: invalid user buffer" );
        return -ENODATA;
    }

    return status;
}

int ioctl_persistentcbt_data(unsigned long arg)
{
    int status = SUCCESS;
    struct ioctl_persistentcbt_data_s param;
    char* cbtdata = NULL;

    if (0 != copy_from_user(&param, (void*)arg, sizeof(struct ioctl_persistentcbt_data_s))) {
        log_err("Unable to retrieve persistent CBT data. Invalid input parameters.");
        return -ENODATA;
    }

    if ( (param.size == 0) || (param.size == 1) || (param.parameter == NULL) )
    {
        log_tr("Cleanup persistent CBT data parameters");
        cbt_persistent_cbtdata_free();
    }
    else
    {
        cbtdata = dbg_kzalloc(param.size + 1, GFP_KERNEL);
        if (cbtdata == NULL) {
            log_err("Unable to retrieve persistent cbt data. Not enough memory.");
            return -ENOMEM;
        }

        do
        {
            if (0 != copy_from_user((void*)cbtdata, (void*)param.parameter, param.size)) {
                log_err("Unable to retreive persistent CBT data. Invalid input parameters.");
                status = -ENODATA;
                break;
            }

            log_tr_s("Setup persistent CBT data parameters: ", cbtdata);
            status = cbt_persistent_cbtdata_new(cbtdata);

        } while (false);
        dbg_kfree(cbtdata);
    }
    return status;
}

int ioctl_printstate( unsigned long arg )
{
    log_tr( "--------------------------------------------------------------------------" );
    log_tr( "state:" );
    log_tr_format( "version: %d.%d.%d.%d.", version.major, version.minor, version.revision, version.build );
#ifdef VEEAMSNAP_MEMORY_LEAK_CONTROL
    dbg_mem_print_state( );
#endif
    snapimage_print_state( );
    tracker_print_state( );
    page_arrays_print_state( );
    blk_deferred_print_state( );
    enum_block_print_state();
    log_tr( "--------------------------------------------------------------------------" );

    return SUCCESS;
}


typedef int (veeam_ioctl_t)(unsigned long arg);
typedef struct veeam_ioctl_table_s{
    unsigned int cmd;
    veeam_ioctl_t* fn;
#ifdef VEEAM_IOCTL_LOGGING
    char* name;
#endif
}veeam_ioctl_table_t;

#ifdef VEEAM_IOCTL_LOGGING
static veeam_ioctl_table_t veeam_ioctl_table[] =
{
    { (IOCTL_COMPATIBILITY_FLAGS), ioctl_compatibility_flags, "IOCTL_COMPATIBILITY_FLAGS" },
    { (IOCTL_GETVERSION), ioctl_get_version, "IOCTL_GETVERSION" },

    { (IOCTL_TRACKING_ADD), ioctl_tracking_add, "IOCTL_TRACKING_ADD" },
    { (IOCTL_TRACKING_REMOVE), ioctl_tracking_remove, "IOCTL_TRACKING_REMOVE" },
    { (IOCTL_TRACKING_COLLECT), ioctl_tracking_collect, "IOCTL_TRACKING_COLLECT" },
    { (IOCTL_TRACKING_BLOCK_SIZE), ioctl_tracking_block_size, "IOCTL_TRACKING_BLOCK_SIZE" },
    { (IOCTL_TRACKING_READ_CBT_BITMAP), ioctl_tracking_read_cbt_map, "IOCTL_TRACKING_READ_CBT_BITMAP" },
    { (IOCTL_TRACKING_MARK_DIRTY_BLOCKS), ioctl_tracking_mark_dirty_blocks, "IOCTL_TRACKING_MARK_DIRTY_BLOCKS" },

    { (IOCTL_SNAPSHOT_CREATE), ioctl_snapshot_create, "IOCTL_SNAPSHOT_CREATE" },
    { (IOCTL_SNAPSHOT_DESTROY), ioctl_snapshot_destroy, "IOCTL_SNAPSHOT_DESTROY" },
    { (IOCTL_SNAPSHOT_ERRNO), ioctl_snapshot_errno, "IOCTL_SNAPSHOT_ERRNO" },

    { (IOCTL_SNAPSTORE_CREATE), ioctl_snapstore_create, "IOCTL_SNAPSTORE_CREATE" },
    { (IOCTL_SNAPSTORE_FILE), ioctl_snapstore_file, "IOCTL_SNAPSTORE_FILE" },
    { (IOCTL_SNAPSTORE_MEMORY), ioctl_snapstore_memory, "IOCTL_SNAPSTORE_MEMORY" },
    { (IOCTL_SNAPSTORE_CLEANUP), ioctl_snapstore_cleanup, "IOCTL_SNAPSTORE_CLEANUP" },
#ifdef SNAPSTORE_MULTIDEV
    { (IOCTL_SNAPSTORE_FILE_MULTIDEV), ioctl_snapstore_file_multidev, "IOCTL_SNAPSTORE_FILE_MULTIDEV" },
#endif
    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_START), ioctl_collect_snapshotdata_location_start, "IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_START" },
    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_GET), ioctl_collect_snapshotdata_location_get, "IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_GET" },
    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_COMPLETE), ioctl_collect_snapshotdata_location_complete, "IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_COMPLETE" },
    { (IOCTL_COLLECT_SNAPSHOT_IMAGES), ioctl_collect_snapimages, "IOCTL_COLLECT_SNAPSHOT_IMAGES" },
    { (IOCTL_PERSISTENTCBT_DATA), ioctl_persistentcbt_data, "IOCTL_PERSISTENTCBT_DATA" },

    { (IOCTL_PRINTSTATE), ioctl_printstate, "IOCTL_PRINTSTATE" },
    { 0, NULL, NULL}
};
#else
static veeam_ioctl_table_t veeam_ioctl_table[] =
{
    { (IOCTL_COMPATIBILITY_FLAGS), ioctl_compatibility_flags },
    { (IOCTL_GETVERSION), ioctl_get_version },

    { (IOCTL_TRACKING_ADD), ioctl_tracking_add },
    { (IOCTL_TRACKING_REMOVE), ioctl_tracking_remove },
    { (IOCTL_TRACKING_COLLECT), ioctl_tracking_collect },
    { (IOCTL_TRACKING_BLOCK_SIZE), ioctl_tracking_block_size },
    { (IOCTL_TRACKING_READ_CBT_BITMAP), ioctl_tracking_read_cbt_map },
    { (IOCTL_TRACKING_MARK_DIRTY_BLOCKS), ioctl_tracking_mark_dirty_blocks},
    { (IOCTL_SET_KERNEL_ENTRIES), ioctl_set_kernel_entries},
    { (IOCTL_GET_UNRESOLVED_KERNEL_ENTRIES), ioctl_get_unresolved_kernel_entries},

    { (IOCTL_SNAPSHOT_CREATE), ioctl_snapshot_create },
    { (IOCTL_SNAPSHOT_DESTROY), ioctl_snapshot_destroy },
    { (IOCTL_SNAPSHOT_ERRNO), ioctl_snapshot_errno },

    { (IOCTL_SNAPSTORE_CREATE), ioctl_snapstore_create },
    { (IOCTL_SNAPSTORE_FILE), ioctl_snapstore_file },
    { (IOCTL_SNAPSTORE_MEMORY), ioctl_snapstore_memory },
    { (IOCTL_SNAPSTORE_CLEANUP), ioctl_snapstore_cleanup },
#ifdef SNAPSTORE_MULTIDEV
    { (IOCTL_SNAPSTORE_FILE_MULTIDEV), ioctl_snapstore_file_multidev },
#endif

    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_START), ioctl_collect_snapshotdata_location_start },
    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_GET), ioctl_collect_snapshotdata_location_get },
    { (IOCTL_COLLECT_SNAPSHOTDATA_LOCATION_COMPLETE), ioctl_collect_snapshotdata_location_complete },
    { (IOCTL_COLLECT_SNAPSHOT_IMAGES), ioctl_collect_snapimages },
    { (IOCTL_PERSISTENTCBT_DATA), ioctl_persistentcbt_data },
    { (IOCTL_PRINTSTATE), ioctl_printstate },
    { 0, NULL }
};
#endif

long ctrl_unlocked_ioctl( struct file *filp, unsigned int cmd, unsigned long arg )
{
    long status = -ENOTTY;
    size_t inx = 0;

    while (veeam_ioctl_table[inx].cmd != 0){
        if (veeam_ioctl_table[inx].cmd == cmd){
#ifdef VEEAM_IOCTL_LOGGING
            if (veeam_ioctl_table[inx].name != NULL){
                log_warn( veeam_ioctl_table[inx].name );
            }
#endif
            status = veeam_ioctl_table[inx].fn( arg );
            break;
        }
        ++inx;
    }

    return status;
}


Zerion Mini Shell 1.0