Linux存储IO栈(2)-- sysfs与内核对象

来源:互联网 发布:2016年外贸依存度数据 编辑:程序博客网 时间:2024/05/15 05:48

sysfs与内核对象

本篇文章不是以文件系统的角度来详细描述sysfs,而是从内核对象如何通过sysfs表示整个设备驱动模型为切入点,进一步理解Linux内核对象。

内核对象添加到sysfs

在上文《内核对象与对象集》中,将kobject添加到sysfs中,kobject_add –> kobject_add_varg –> kobject_add_internal,调用create_dir创建sysfs目录和属性文件。

static int create_dir(struct kobject *kobj){    const struct kobj_ns_type_operations *ops;    int error;        //调用sysfs接口创建kobject对应的目录    error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));    if (error)        return error;    error = populate_dir(kobj);  //在kobject对应的目录中生成默认属性文件    if (error) {        sysfs_remove_dir(kobj);        return error;    }    /*     * @kobj->sd may be deleted by an ancestor going away.  Hold an     * extra reference so that it stays until @kobj is gone.     */    sysfs_get(kobj->sd);    /*     * If @kobj has ns_ops, its children need to be filtered based on     * their namespace tags.  Enable namespace support on @kobj->sd.     */    ops = kobj_child_ns_ops(kobj);    if (ops) {        BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);        BUG_ON(ops->type >= KOBJ_NS_TYPES);        BUG_ON(!kobj_ns_type_registered(ops->type));        sysfs_enable_ns(kobj->sd);    }    return 0;}/* * populate_dir - populate directory with attributes. * @kobj: object we're working on. * * Most subsystems have a set of default attributes that are associated * with an object that registers with them.  This is a helper called during * object registration that loops through the default attributes of the * subsystem and creates attributes files for them in sysfs. */static int populate_dir(struct kobject *kobj){    struct kobj_type *t = get_ktype(kobj);    struct attribute *attr;    int error = 0;    int i;    if (t && t->default_attrs) {        for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {            error = sysfs_create_file(kobj, attr); //为每个属性创建对应的文件            if (error)                break;        }    }    return error;}

create_dir通过调用sysfs_create_dir_ns创建sysfs中的目录,调用sysfs_create_file创建属性文件。

sysfs的核心结构

kern_node代表sysfs中每个节点。

/* * kernfs_node - the building block of kernfs hierarchy.  Each and every * kernfs node is represented by single kernfs_node.  Most fields are * private to kernfs and shouldn't be accessed directly by kernfs users. * * As long as s_count reference is held, the kernfs_node itself is * accessible.  Dereferencing elem or any other outer entity requires * active reference. */struct kernfs_node {    atomic_t        count;   //引用计数    atomic_t        active;  //活动的引用计数#ifdef CONFIG_DEBUG_LOCK_ALLOC    struct lockdep_map  dep_map;#endif    /*     * Use kernfs_get_parent() and kernfs_name/path() instead of     * accessing the following two fields directly.  If the node is     * never moved to a different parent, it is safe to access the     * parent directly.     */    struct kernfs_node  *parent; //指向父节点    const char      *name;       //节点名称,在sysfs显示的名字    struct rb_node      rb;      //接入sysfs红黑树的链接项    const void      *ns;    /* namespace tag */    unsigned int        hash;   /* ns + name hash 红黑树key */    union {        struct kernfs_elem_dir      dir;     //该kern_node类型为目录        struct kernfs_elem_symlink  symlink; //该kern_node类型为链接        struct kernfs_elem_attr     attr;    //该kern_node类型为属性文件    };    void            *priv;    unsigned short      flags; //标记位,目录、链接、属性文件或是否已被删除    umode_t         mode;      //访问权限,在sysfs中该kern_node的权限    unsigned int        ino;   //唯一编号    struct kernfs_iattrs    *iattr;  //用于设置非默认的inode属性,如果没有则置为NULL};

在sysfs中创建目录sysfs_create_dir_ns

/** * sysfs_create_dir_ns - create a directory for an object with a namespace tag * @kobj: object we're creating directory for * @ns: the namespace tag to use */int sysfs_create_dir_ns(struct kobject *kobj, const void *ns){    struct kernfs_node *parent, *kn;    BUG_ON(!kobj);    if (kobj->parent)        parent = kobj->parent->sd; //如果kobject设置parent,则使用之    else        parent = sysfs_root_kn;  //否则parent就设置为sysfs根目录    if (!parent)        return -ENOENT;    //创建目录    kn = kernfs_create_dir_ns(parent, kobject_name(kobj),                  S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);    if (IS_ERR(kn)) {        if (PTR_ERR(kn) == -EEXIST)            sysfs_warn_dup(parent, kobject_name(kobj));        return PTR_ERR(kn);    }    kobj->sd = kn;    return 0;}/** * kernfs_create_dir_ns - create a directory * @parent: parent in which to create a new directory * @name: name of the new directory * @mode: mode of the new directory * @priv: opaque data associated with the new directory * @ns: optional namespace tag of the directory * * Returns the created node on success, ERR_PTR() value on failure. */struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,                     const char *name, umode_t mode,                     void *priv, const void *ns){    struct kernfs_node *kn;    int rc;    /* allocate 分配空间并初始化, KERNFS_DIR指定创建目录 */    kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR);    if (!kn)        return ERR_PTR(-ENOMEM);    kn->dir.root = parent->dir.root; //指向根目录kern_node    kn->ns = ns;  //指定命名空间    kn->priv = priv;    /* link in */    rc = kernfs_add_one(kn); //将kern_node加入父目录的红黑树中    if (!rc)        return kn;    kernfs_put(kn);    return ERR_PTR(rc);}

kernfs_create_dir_ns函数中的两个主要函数kernfs_new_node和kernfs_add_one,在创建文件和创建符号链接同样使用,仅是参数不同。

为kern_node结构分配空间,并初始化

struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,                    const char *name, umode_t mode,                    unsigned flags){    struct kernfs_node *kn;    //分配kern_node空间,并初始化    kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags);    if (kn) {        kernfs_get(parent);        kn->parent = parent;    }    return kn;}static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,                         const char *name, umode_t mode,                         unsigned flags){    struct kernfs_node *kn;    int ret;    name = kstrdup_const(name, GFP_KERNEL); //复制常量字符串    if (!name)        return NULL;    kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); //在缓存空间分配kernfs_node    if (!kn)        goto err_out1;    /*     * If the ino of the sysfs entry created for a kmem cache gets     * allocated from an ida layer, which is accounted to the memcg that     * owns the cache, the memcg will get pinned forever. So do not account     * ino ida allocations.     */    ret = ida_simple_get(&root->ino_ida, 1, 0,  //获取唯一标号,用于唯一标示kern_node                 GFP_KERNEL | __GFP_NOACCOUNT);    if (ret < 0)        goto err_out2;    kn->ino = ret;    atomic_set(&kn->count, 1);  //更新引用计数    atomic_set(&kn->active, KN_DEACTIVATED_BIAS);    RB_CLEAR_NODE(&kn->rb);    //设置kern_node相关域    kn->name = name;    kn->mode = mode;    kn->flags = flags;    return kn; err_out2:    kmem_cache_free(kernfs_node_cache, kn); err_out1:    kfree_const(name);    return NULL;}

将kern_node添加到parent的红黑树中:

/** *  kernfs_add_one - add kernfs_node to parent without warning *  @kn: kernfs_node to be added * *  The caller must already have initialized @kn->parent.  This *  function increments nlink of the parent's inode if @kn is a *  directory and link into the children list of the parent. * *  RETURNS: *  0 on success, -EEXIST if entry with the given name already *  exists. */int kernfs_add_one(struct kernfs_node *kn){    struct kernfs_node *parent = kn->parent;    struct kernfs_iattrs *ps_iattr;    bool has_ns;    int ret;    mutex_lock(&kernfs_mutex);    ret = -EINVAL;    has_ns = kernfs_ns_enabled(parent);    if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",         has_ns ? "required" : "invalid", parent->name, kn->name))        goto out_unlock;    if (kernfs_type(parent) != KERNFS_DIR) //检查parent是否为目录        goto out_unlock;    ret = -ENOENT;    if (parent->flags & KERNFS_EMPTY_DIR)  //检查parent是否为空目录        goto out_unlock;    //检查parent是否是active状态    if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))        goto out_unlock;    kn->hash = kernfs_name_hash(kn->name, kn->ns); //作为红黑树比较的key    ret = kernfs_link_sibling(kn); //kern_node链入parent节点红黑树中    if (ret)        goto out_unlock;    /* Update timestamps on the parent */    ps_iattr = parent->iattr;    if (ps_iattr) {        struct iattr *ps_iattrs = &ps_iattr->ia_iattr;        ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;    }    mutex_unlock(&kernfs_mutex);    /*     * Activate the new node unless CREATE_DEACTIVATED is requested.     * If not activated here, the kernfs user is responsible for     * activating the node with kernfs_activate().  A node which hasn't     * been activated is not visible to userland and its removal won't     * trigger deactivation.     */    if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED))        kernfs_activate(kn);    return 0;out_unlock:    mutex_unlock(&kernfs_mutex);    return ret;}

sysfs红黑树中的key:

/** *  kernfs_name_hash *  @name: Null terminated string to hash *  @ns:   Namespace tag to hash * *  Returns 31 bit hash of ns + name (so it fits in an off_t ) */static unsigned int kernfs_name_hash(const char *name, const void *ns){    unsigned long hash = init_name_hash();    unsigned int len = strlen(name);    while (len--)        hash = partial_name_hash(*name++, hash);    hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));    hash &= 0x7fffffffU;    /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */    if (hash < 2)        hash += 2;    if (hash >= INT_MAX)        hash = INT_MAX - 1;    return hash;}static int kernfs_name_compare(unsigned int hash, const char *name,                   const void *ns, const struct kernfs_node *kn){    if (hash < kn->hash)        return -1;    if (hash > kn->hash)        return 1;    if (ns < kn->ns)        return -1;    if (ns > kn->ns)        return 1;    return strcmp(name, kn->name);}
  • kernfs_name_hash: 根据name和ns计算kern_node的hash值,保存在kern_node.hash域中。
  • kernfs_name_compare: sysfs红黑树key的比较函数, 比较优先级是: hash > ns > name

kern_node链入parent节点红黑树中:

/** *  kernfs_link_sibling - link kernfs_node into sibling rbtree *  @kn: kernfs_node of interest * *  Link @kn into its sibling rbtree which starts from *  @kn->parent->dir.children. * *  Locking: *  mutex_lock(kernfs_mutex) * *  RETURNS: *  0 on susccess -EEXIST on failure. */static int kernfs_link_sibling(struct kernfs_node *kn){    struct rb_node **node = &kn->parent->dir.children.rb_node; //parent目录的红黑树    struct rb_node *parent = NULL;    while (*node) {  //在parent的目录中,寻找合适的位置将kn插入parent的红黑树中        struct kernfs_node *pos;        int result;        pos = rb_to_kn(*node);        parent = *node;        result = kernfs_sd_compare(kn, pos); //优先顺序: hash > ns > name        if (result < 0)            node = &pos->rb.rb_left;        else if (result > 0)            node = &pos->rb.rb_right;        else            return -EEXIST;    }    /* add new node and rebalance the tree */    rb_link_node(&kn->rb, parent, node);    rb_insert_color(&kn->rb, &kn->parent->dir.children);    /* successfully added, account subdir number */    if (kernfs_type(kn) == KERNFS_DIR)        kn->parent->dir.subdirs++;    return 0;}

在sysfs中创建文件

static inline int __must_check sysfs_create_file(struct kobject *kobj,                         const struct attribute *attr){    return sysfs_create_file_ns(kobj, attr, NULL);}/** * sysfs_create_file_ns - create an attribute file for an object with custom ns * @kobj: object we're creating for * @attr: attribute descriptor * @ns: namespace the new file should belong to */int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,             const void *ns){    BUG_ON(!kobj || !kobj->sd || !attr);    return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);}EXPORT_SYMBOL_GPL(sysfs_create_file_ns);int sysfs_add_file_mode_ns(struct kernfs_node *parent,               const struct attribute *attr, bool is_bin,               umode_t mode, const void *ns){    struct lock_class_key *key = NULL;    const struct kernfs_ops *ops;    struct kernfs_node *kn;    loff_t size;    if (!is_bin) {        struct kobject *kobj = parent->priv;        const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;        /* every kobject with an attribute needs a ktype assigned */        if (WARN(!sysfs_ops, KERN_ERR             "missing sysfs attribute operations for kobject: %s\n",             kobject_name(kobj)))            return -EINVAL;        //确定读写的操作函数        if (sysfs_ops->show && sysfs_ops->store) {            if (mode & SYSFS_PREALLOC)                ops = &sysfs_prealloc_kfops_rw;            else                ops = &sysfs_file_kfops_rw;        } else if (sysfs_ops->show) {            if (mode & SYSFS_PREALLOC)                ops = &sysfs_prealloc_kfops_ro;            else                ops = &sysfs_file_kfops_ro;        } else if (sysfs_ops->store) {            if (mode & SYSFS_PREALLOC)                ops = &sysfs_prealloc_kfops_wo;            else                ops = &sysfs_file_kfops_wo;        } else            ops = &sysfs_file_kfops_empty;        size = PAGE_SIZE;    } else {        struct bin_attribute *battr = (void *)attr;        if (battr->mmap)            ops = &sysfs_bin_kfops_mmap;        else if (battr->read && battr->write)            ops = &sysfs_bin_kfops_rw;        else if (battr->read)            ops = &sysfs_bin_kfops_ro;        else if (battr->write)            ops = &sysfs_bin_kfops_wo;        else            ops = &sysfs_file_kfops_empty;        size = battr->size;    }#ifdef CONFIG_DEBUG_LOCK_ALLOC    if (!attr->ignore_lockdep)        key = attr->key ?: (struct lock_class_key *)&attr->skey;#endif    kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops,                  (void *)attr, ns, key); //创建属性文件    if (IS_ERR(kn)) {        if (PTR_ERR(kn) == -EEXIST)            sysfs_warn_dup(parent, attr->name);        return PTR_ERR(kn);    }    return 0;}

通过上面的代码跟踪,创建属性文件由__kernfs_create_file实现,最终仍然是调用kernfs_new_node和kernfs_add_one。

/** * __kernfs_create_file - kernfs internal function to create a file * @parent: directory to create the file in * @name: name of the file * @mode: mode of the file * @size: size of the file * @ops: kernfs operations for the file * @priv: private data for the file * @ns: optional namespace tag of the file * @key: lockdep key for the file's active_ref, %NULL to disable lockdep * * Returns the created node on success, ERR_PTR() value on error. */struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,                     const char *name,                     umode_t mode, loff_t size,                     const struct kernfs_ops *ops,                     void *priv, const void *ns,                     struct lock_class_key *key){    struct kernfs_node *kn;    unsigned flags;    int rc;    flags = KERNFS_FILE; //创建的kern_node类型为file    //分配空间并初始化    kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, flags);    if (!kn)        return ERR_PTR(-ENOMEM);    kn->attr.ops = ops;    kn->attr.size = size;    kn->ns = ns;    kn->priv = priv;#ifdef CONFIG_DEBUG_LOCK_ALLOC    if (key) {        lockdep_init_map(&kn->dep_map, "s_active", key, 0);        kn->flags |= KERNFS_LOCKDEP;    }#endif    /*     * kn->attr.ops is accesible only while holding active ref.  We     * need to know whether some ops are implemented outside active     * ref.  Cache their existence in flags.     */    if (ops->seq_show)        kn->flags |= KERNFS_HAS_SEQ_SHOW;    if (ops->mmap)        kn->flags |= KERNFS_HAS_MMAP;    rc = kernfs_add_one(kn); //将kern_node添加到parent的红黑树中    if (rc) {        kernfs_put(kn);        return ERR_PTR(rc);    }    return kn;}

在sysfs_add_file_mode_ns函数中根据flags的不同,注册不同的读写回调函数,下面以sysfs_prealloc_kfops_rw函数为例,其他结构类似,不赘述。

//常规文件--sysfs_prealloc_kfops_rwstatic const struct kernfs_ops sysfs_prealloc_kfops_rw = {    .read       = sysfs_kf_read,    .write      = sysfs_kf_write,    .prealloc   = true,};/* kernfs read callback for regular sysfs files with pre-alloc */static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,                 size_t count, loff_t pos){    const struct sysfs_ops *ops = sysfs_file_ops(of->kn); //获取kobject中的sysfs_ops操作表    struct kobject *kobj = of->kn->parent->priv;    size_t len;    /*     * If buf != of->prealloc_buf, we don't know how     * large it is, so cannot safely pass it to ->show     */    if (pos || WARN_ON_ONCE(buf != of->prealloc_buf))        return 0;    len = ops->show(kobj, of->kn->priv, buf); //kobject中sd域的sysfs_ops操作表中的show    return min(count, len);}/* kernfs write callback for regular sysfs files */static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,                  size_t count, loff_t pos){   //获取kobject中的sysfs_ops操作表    const struct sysfs_ops *ops = sysfs_file_ops(of->kn);    struct kobject *kobj = of->kn->parent->priv;    if (!count)        return 0;    return ops->store(kobj, of->kn->priv, buf, count); //kobject中sd域的sysfs_ops操作表中的store}

关于属性文件的读写操作,最终都回调到kobject中的sd域的sysfs_ops操作表,这个操作表示在kobject_init函数中设置。回顾kobject_create函数:

struct kobject *kobject_create(void){    struct kobject *kobj;    kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); //分配空间    if (!kobj)        return NULL;    kobject_init(kobj, &dynamic_kobj_ktype);  //初始化, kobj_type类型为dynamic_kobj_ktype    return kobj;}//注册如下结构static struct kobj_type dynamic_kobj_ktype = {    .release    = dynamic_kobj_release,    .sysfs_ops  = &kobj_sysfs_ops,};const struct sysfs_ops kobj_sysfs_ops = {    .show   = kobj_attr_show,    .store  = kobj_attr_store,};EXPORT_SYMBOL_GPL(kobj_sysfs_ops);

kobject的sysfs的show和store方法为:kobj_attr_show和kobj_attr_store

static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,                  char *buf){    struct kobj_attribute *kattr;    ssize_t ret = -EIO;    kattr = container_of(attr, struct kobj_attribute, attr);    if (kattr->show)  //如果业务子系统设置了show函数,则调用        ret = kattr->show(kobj, kattr, buf);    return ret;}static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,                   const char *buf, size_t count){    struct kobj_attribute *kattr;    ssize_t ret = -EIO;    kattr = container_of(attr, struct kobj_attribute, attr);    if (kattr->store)  //如果业务子系统设置了store函数,则调用        ret = kattr->store(kobj, kattr, buf, count);    return ret;}

真正的对属性文件进行读写的回调由业务子系统实现。

在sysfs中创建符号链接

/** *  sysfs_create_link - create symlink between two objects. *  @kobj:  object whose directory we're creating the link in. *  @target:    object we're pointing to. *  @name:      name of the symlink. */int sysfs_create_link(struct kobject *kobj, struct kobject *target,              const char *name){    return sysfs_do_create_link(kobj, target, name, 1);}EXPORT_SYMBOL_GPL(sysfs_create_link);static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,                const char *name, int warn){    struct kernfs_node *parent = NULL;    if (!kobj)        parent = sysfs_root_kn;    else        parent = kobj->sd;    if (!parent)        return -EFAULT;    return sysfs_do_create_link_sd(parent, target, name, warn);}static int sysfs_do_create_link_sd(struct kernfs_node *parent,                   struct kobject *target_kobj,                   const char *name, int warn){    struct kernfs_node *kn, *target = NULL;    BUG_ON(!name || !parent);    /*     * We don't own @target_kobj and it may be removed at any time.     * Synchronize using sysfs_symlink_target_lock.  See     * sysfs_remove_dir() for details.     */    spin_lock(&sysfs_symlink_target_lock);    if (target_kobj->sd) {        target = target_kobj->sd;        kernfs_get(target);    }    spin_unlock(&sysfs_symlink_target_lock);    if (!target)        return -ENOENT;    kn = kernfs_create_link(parent, name, target); //创建sysfs符号链接    kernfs_put(target);    if (!IS_ERR(kn))        return 0;    if (warn && PTR_ERR(kn) == -EEXIST)        sysfs_warn_dup(parent, name);    return PTR_ERR(kn);}

由上面的代码追踪,创建符号链接由kernfs_create_link函数上。

/** * kernfs_create_link - create a symlink * @parent: directory to create the symlink in * @name: name of the symlink * @target: target node for the symlink to point to * * Returns the created node on success, ERR_PTR() value on error. */struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,                       const char *name,                       struct kernfs_node *target){    struct kernfs_node *kn;    int error;    //指定创建符号链接    kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK);    if (!kn)        return ERR_PTR(-ENOMEM);    if (kernfs_ns_enabled(parent))        kn->ns = target->ns;    kn->symlink.target_kn = target;    kernfs_get(target); /* ref owned by symlink */    error = kernfs_add_one(kn); //将kern_node添加到parent的红黑树中    if (!error)        return kn;    kernfs_put(kn);    return ERR_PTR(error);}

与创建目录和文件类似,最终仍然是调用kernfs_new_node和kernfs_add_one实现。

基于内核对象编程套路

目标:在sysfs中创建一个目录/sys/kernel/storage/,在该目录下,还创建了一个文件value。value可以写入整型数据,随后可以读出。
* 定义内核对象

struct storage_obj {    struct kobject kobj;    int val;  //用于保存写入的数据};
  • 定义属性类型
struct storage_attribute {    struct attribute *attr;    ssize_t (*show)(struct kobject *, struct attribute *, char *);    ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);}
  • 声明属性
    定义属性的show和store方法,如下:
//定义并初始化storage_attributestruct storage_attribute *sattr = &struct storage_attribute {    .attr = {.name = "value", .mode = 0666},    .show = storage_show,    .store = storage_store,};
  • 实现sysfs操作
ssize_t storage_show(struct kobject *kobj, struct attribute *attr, char *buf) {    struct storage *stor = container_of(kobj, struct storage_obj, kobj);    stor->val = atoi(buf);}ssize_t storage_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t s) {    struct storage *stor = container_of(kobj, struct storage_obj, kobj);    memcpy(buf, s, itoa(stor->val));}
  • 定义内核对象release方法
    release方法设置在kobj_type结构中
void storage_release(struct kobject *kobj){    ......}
  • 声明内核对象类型
struct storage_ktype {    struct kobj_type *ktype;}
  • 封装对象属性添加和删除方法
    需要将value属性添加到内核对象,或者从内核对象删除,可以直接调用sysfs_create_file和sysfs_remove_file。但大多数情况下,会对这两个方法做一层封装:storage_create_file和storage_remove_file。
int storage_create_file(struct storage_obj *sobj, const struct storage_attribute *attr){    int error = 0;    if (sobj) {        error = sysfs_create_file(&sobj->kobj, &attr->attr);    }    return error;}void storage_remove_file(struct storage_obj *sobj, const struct storage_attribute *attr){    if (sobj) {        sysfs_remove_file(&sobj->kobj, &attr->attr);    }}
  • 定义对象的创建和销毁方法
struct storage_obj * create_storage_obj() {    struct storage_obj *sobj = (struct storage_obj *)malloc(struct storage_obj);    struct storage_ktype *stype = (struct storage_ktype *)malloc(struct storage_ktype);    sobj->parent = kernel_kobj;    kobject_init_and_add(&sobj->kobj, &stype->ktype);    return sobj}void destroy_storage_obj(struct kobject *kobj) {    struct storage_obj *sobj = container_of(kobj, struct storage_obj, kobj);    kobject_del(kboj);    free(sobj);    free(stype);}
  • 实现模块加载和卸载方法
    加载时调用create_storage_obj, 卸载时调用destroy_storage_obj
1 0