%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_sysfs.c

// Copyright (c) Veeam Software Group GmbH

#include "stdafx.h"
#include "ctrl_sysfs.h"

#ifdef PERSISTENT_CBT
#include "cbt_persistent.h"
#endif

#define SECTION "ctrl_sysfs"
#include "log_format.h"

#include <linux/sysfs.h>

#ifdef VEEAMSNAP_SYSFS_PARAMS
int set_params(char* param_name, char* param_value);
int get_params(char* buf);
#endif

#ifdef PERSISTENT_CBT
uint64_t _notify_counter = 0;

// major

int get_veeamsnap_major(void);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
#if defined(HAVE_DEFINE_CLASS_CREATE_H)
static ssize_t major_show(struct class *class, struct class_attribute *attr, char *buf)
#else
static ssize_t major_show(const struct class *class, const struct class_attribute *attr, char *buf)
#endif
#else
static ssize_t major_show(struct class *class, char *buf)
#endif
{
    sprintf(buf, "%d", get_veeamsnap_major());
    return strlen(buf);
}

// blkdev_notify

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
#if defined(HAVE_DEFINE_CLASS_CREATE_H)
static ssize_t blkdev_notify_show(struct class *class, struct class_attribute *attr, char *buf)
#else
static ssize_t blkdev_notify_show(const struct class *class, const struct class_attribute *attr, char *buf)
#endif
#else
static ssize_t blkdev_notify_show(struct class *class, char *buf)
#endif
{
    log_tr_lld("Show notify counter ", _notify_counter);
    sprintf(buf, "%lld", _notify_counter);
    return strlen(buf);
}

enum ENotifyCommandType
{
    NotifyCommandInvalid = 0,
    NotifyCommandAdd = 1,
    NotifyCommandRemove = 2
};

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
#if defined(HAVE_DEFINE_CLASS_CREATE_H)
static ssize_t blkdev_notify_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
#else
static ssize_t blkdev_notify_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count)
#endif
#else
static ssize_t blkdev_notify_store(struct class *class, const char *buf, size_t count)
#endif
{
    int res = SUCCESS;
    /*
    string format: "add sda /devices/.../sda"
    */
    size_t state = 0;
    size_t ofs = 0;
    size_t len = 0;

    enum ENotifyCommandType type = NotifyCommandInvalid;
    char* dev_name = NULL;
    char* dev_path = NULL;

    //log_tr_s("DEBUG! buffer: ", buf);

    ++_notify_counter;

    // to do string parsing
    while ((ofs+len) < count)
    {
        if ( (buf[ofs + len] == ' ') || (buf[ofs + len] == '\n') || (buf[ofs + len] == '\t') || ((ofs + len) == (count-1)) )
        {
            if (len > 1)
            {
                switch (state){
                case 0://add or remove
                    if ((len == 3) && (0 == memcmp("add", buf + ofs, 3))){
                        type = NotifyCommandAdd;
                        //log_tr("DEBUG! Found add command");
                    }
                    else if ((len == 6) && (0 == memcmp("remove", buf + ofs, 6))){
                        type = NotifyCommandRemove;
                        //log_tr("DEBUG! Found remove command");
                    }else{
                        log_tr("Invalid command found");
                        type = NotifyCommandInvalid;
                    }
                    break;
                case 1://device name
                    dev_name = dbg_kzalloc(5+len+1, GFP_KERNEL);
                    if (dev_name == NULL){
                        res = -ENOMEM;
                        log_err("Failed allocate memory for device name");
                    }
                    memcpy(dev_name, "/dev/", 5);
                    memcpy(dev_name+5, buf + ofs, len);
                    dev_name[5+len] = '\0';
                    //log_tr_s("DEBUG! Found device name", dev_name);
                    break;
                case 2://device path
                    dev_path = dbg_kzalloc(len+1, GFP_KERNEL);
                    if (dev_path == NULL){
                        res = -ENOMEM;
                        log_err("Failed allocate memory for device path");
                    }
                    memcpy(dev_path, buf + ofs, len);
                    dev_path[len] = '\0';
                    //log_tr_s("DEBUG! Found device path", dev_path);
                    break;
                default:
                    log_err_s("Failed to parse text: ", buf + ofs);
                }
                ++state;
            }
            ofs += len+1;
            len = 0;
        }
        ++len;
    }

    //call block device notifier
    if ((res == SUCCESS) && (dev_name != NULL) && (dev_path != NULL) && (type != NotifyCommandInvalid)){
        if (type == NotifyCommandAdd)
            cbt_persistent_device_attach(dev_name, dev_path);
        if (type == NotifyCommandRemove)
            cbt_persistent_device_detach(dev_name, dev_path);
    }
    else{
        log_err_s("Failed to parse notification ", buf);
    }

    if (dev_name != NULL)
        dbg_kfree(dev_name);
    if (dev_path != NULL)
        dbg_kfree(dev_path);

    return count;
}
#endif //PERSISTENT_CBT

#ifdef VEEAMSNAP_SYSFS_PARAMS
// params
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
static ssize_t params_show(struct class *class, struct class_attribute *attr, char *buf)
#else
static ssize_t params_show(struct class *class, char *buf)
#endif
{
    int res = get_params(buf);
    if (res == SUCCESS)
        return strlen(buf);

    log_err("Failed to read parameters");
    return 0;
}

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
static ssize_t params_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
#else
static ssize_t params_store(struct class *class, const char *buf, size_t count)
#endif
{
    int res = -EINVAL;
    size_t ofs = 0;

    char* param_name = NULL;
    char* param_value = NULL;

    //log_tr_s("DEBUG! buffer: ", buf);

    // to do string parsing
    while (ofs < count)
    {
        if (buf[ofs] == '='){ //separator found
            size_t len = ofs;
            param_name = dbg_kzalloc(len + 1, GFP_KERNEL);
            if (param_name == NULL){
                res = -ENOMEM;
                break;
            }
            memcpy(param_name, buf, len);
            param_name[len] = '\0';

            ofs += 1;//skip separator
            len = count - ofs;
            param_value = dbg_kzalloc(len + 1, GFP_KERNEL);
            if (param_value == NULL){
                res = -ENOMEM;
                break;
            }
            memcpy(param_value, buf+ofs, len);
            param_value[len] = '\0';

            res = SUCCESS;
            break;
        }

        ++ofs;
    }

    //call block device notifier
    res = set_params(param_name, param_value);
    if (SUCCESS != res)
        log_err_s("Failed to set parameter ", param_name);

    if (param_name != NULL)
        dbg_kfree(param_name);
    if (param_value != NULL)
        dbg_kfree(param_value);


    return count;
}
#endif

#ifndef __ATTR_RW
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
#endif

#ifndef __ATTR_RO
#define __ATTR_RO(_name) {						\
	.attr	= { .name = __stringify(_name), .mode = 0444 },		\
	.show	= _name##_show,						\
}
#endif

#ifndef CLASS_ATTR_RW
#define CLASS_ATTR_RW(_name) \
struct class_attribute class_attr_##_name = __ATTR_RW(_name)
#endif
#ifndef CLASS_ATTR_RO
#define CLASS_ATTR_RO(_name) \
struct class_attribute class_attr_##_name = __ATTR_RO(_name)
#endif

#ifdef PERSISTENT_CBT
static CLASS_ATTR_RW(blkdev_notify);
static CLASS_ATTR_RO(major);
#endif

#ifdef VEEAMSNAP_SYSFS_PARAMS
CLASS_ATTR_RW(params);
#endif

static struct class *veeamsnap_class = NULL;

int ctrl_sysfs_init(struct device **p_device)
{
    int res;
#if defined(HAVE_DEFINE_CLASS_CREATE_H)
    veeamsnap_class = class_create(THIS_MODULE, "veeamsnap");
#else
    veeamsnap_class = class_create("veeamsnap");
#endif
    if (IS_ERR(veeamsnap_class)){
        res = PTR_ERR(veeamsnap_class);
        log_err_d("bad class create. Error code ", 0-res);
        return res;
    }

    do{
#ifdef PERSISTENT_CBT
        log_tr("Create 'major' sysfs attribute");
        res = class_create_file(veeamsnap_class, &class_attr_major);
        if (res != SUCCESS){
            log_err("Failed to create 'major' sysfs file");
            break;
        }

        log_tr("Create 'blkdev_notify' sysfs attribute");
        res = class_create_file(veeamsnap_class, &class_attr_blkdev_notify);
        if (res != SUCCESS){
            log_err("Failed to create 'blkdev_notify' sysfs file");
            break;
        }
#endif
#ifdef VEEAMSNAP_SYSFS_PARAMS
        log_tr("Create 'params' sysfs attribute");
        res = class_create_file(veeamsnap_class, &class_attr_params);
        if (res != SUCCESS){
            log_err("Failed to create 'params' sysfs file");
            break;
        }
#endif
        {
            struct device *dev = device_create(veeamsnap_class, NULL, MKDEV(get_veeamsnap_major(), 0), NULL, "veeamsnap");
            if (IS_ERR(dev)){
                res = PTR_ERR(dev);
                log_err_d("Failed to create device, result=", res);
                break;
            }

            *p_device = dev;
        }
    } while (false);

    if (res != SUCCESS){
        class_destroy(veeamsnap_class);
        veeamsnap_class = NULL;
    }
    return res;
}

void ctrl_sysfs_done(struct device **p_device)
{
    if (*p_device) {
        device_unregister(*p_device);
        *p_device = NULL;
    }

    if (veeamsnap_class != NULL){
#ifdef VEEAMSNAP_SYSFS_PARAMS
		class_remove_file(veeamsnap_class, &class_attr_params);
#endif
#ifdef PERSISTENT_CBT
        class_remove_file(veeamsnap_class, &class_attr_blkdev_notify);
		class_remove_file(veeamsnap_class, &class_attr_major);
#endif
        class_destroy(veeamsnap_class);
        veeamsnap_class = NULL;
    }
}


Zerion Mini Shell 1.0