您的位置:首页 > 移动开发 > Objective-C

SYSFS以及设备文件或kobject目录创建的关系

2012-09-13 15:20 567 查看
sysfs_create_group()定义的文件 kernel/fs/sysfs/group.c:



static int internal_create_group(struct kobject *kobj, int update,
                 const struct attribute_group *grp)
{
    struct sysfs_dirent *sd;
    int error;

    BUG_ON(!kobj || (!update && !kobj->sd));

    /* Updates may happen before the object has been instantiated */
    if (unlikely(update && !kobj->sd))
        return -EINVAL;

    if (grp->name) {
        error = sysfs_create_subdir(kobj, grp->name, &sd);
        if (error)
            return error;
    } else
        sd = kobj->sd;
    sysfs_get(sd);
    error = create_files(sd, kobj, grp, update);
    if (error) {
        if (grp->name)
            sysfs_remove_subdir(sd);
    }
    sysfs_put(sd);
    return error;
}


sysfs_create_group()定义



/**
 * sysfs_create_group - given a directory kobject, create an attribute group
 * @kobj:   The kobject to create the group on
 * @grp:    The attribute group to create
 *
 * This function creates a group for the first time.  It will explicitly
 * warn and error if any of the attribute files being created already exist.
 *
 * Returns 0 on success or error.
 */
int sysfs_create_group(struct kobject *kobj,
               const struct attribute_group *grp)
{
    return internal_create_group(kobj, 0, grp);
}




attribute 结构位于 kernel/include/linux/sysfs.h



/* FIXME
 * The *owner field is no longer used.
 * x86 tree has been cleaned up. The owner
 * attribute is still left for other arches.
 */
struct attribute {
    const char      *name;
    struct module       *owner;
    mode_t          mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lock_class_key   *key;
    struct lock_class_key   skey;
#endif
};




bus_create_file 函数位于 kernel/drivers/base/bus.c

int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
{
    int error;
    if (bus_get(bus)) {
        error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
        bus_put(bus);
    } else
        error = -EINVAL;
    return error;
}
EXPORT_SYMBOL_GPL(bus_create_file);



sysfs_create_file 函数 位于 kernel/fs/sysfs/file.c

/**
 *  sysfs_create_file - create an attribute file for an object.
 *  @kobj:  object we're creating for.
 *  @attr:  attribute descriptor.
 */

int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
    BUG_ON(!kobj || !kobj->sd || !attr);

    return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);

}

int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
{
    int err = 0;
    int i;

    for (i = 0; ptr[i] && !err; i++)
        err = sysfs_create_file(kobj, ptr[i]);
    if (err)
        while (--i >= 0)
            sysfs_remove_file(kobj, ptr[i]);
    return err;
}


根据 sysfs/file.c文件中的相关调用函数,可以知道,实际上 bus_create_file()函数在/sys 目录下创建的总线目录的名字是由 其第二个参数 attr (attr->attribute.name)来决定的,而不是由第一个参数中的name成员来决定。



函数调用路径为:

bus_create_file -->[b]sysfs_create_file-->sysfs_add_file-->sysfs_add_file_mode--> sysfs_new_dirent(attr->name, mode, type);[/b]



int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
            const struct attribute *attr, int type, mode_t amode)
{
    umode_t mode = (amode & S_IALLUGO) | S_IFREG;
    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

    sd = sysfs_new_dirent(attr->name, mode, type);
    if (!sd)
        return -ENOMEM;
    sd->s_attr.attr = (void *)attr;
    sysfs_dirent_init_lockdep(sd);

    sysfs_addrm_start(&acxt, dir_sd);
    rc = sysfs_add_one(&acxt, sd);
    sysfs_addrm_finish(&acxt);

    if (rc)
        sysfs_put(sd);

    return rc;
}

int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
           int type)
{
    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
}




如果还要追究的话, sysfs_new_dirent函数的实现位于 kernel/fs/sysfs/dir.c

其声明位于: kernel/fs/sysfs/sysfs.h



struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
    char *dup_name = NULL;
    struct sysfs_dirent *sd;

    if (type & SYSFS_COPY_NAME) {
        name = dup_name = kstrdup(name, GFP_KERNEL);
        if (!name)
            return NULL;
    }

    sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
    if (!sd)
        goto err_out1;

    if (sysfs_alloc_ino(&sd->s_ino))
        goto err_out2;

    atomic_set(&sd->s_count, 1);
    atomic_set(&sd->s_active, 0);

    sd->s_name = name;
    sd->s_mode = mode;
    sd->s_flags = type;

    return sd;

 err_out2:
    kmem_cache_free(sysfs_dir_cachep, sd);
 err_out1:
    kfree(dup_name);
    return NULL;
}


sd->s_name = name; 最终告诉了我们这个目录的名字。



sysfs_dir_cachep 结构体变量在如下文件中被定义 kernel/fs/sysfs/mount.c

struct kmem_cache *sysfs_dir_cachep;



int __init sysfs_init(void)
{
    int err = -ENOMEM;

    sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
                          sizeof(struct sysfs_dirent),
                          0, 0, NULL);
    if (!sysfs_dir_cachep)
        goto out;

    err = sysfs_inode_init();
    if (err)
        goto out_err;

    err = register_filesystem(&sysfs_fs_type);
    if (!err) {
        sysfs_mount = kern_mount(&sysfs_fs_type);
        if (IS_ERR(sysfs_mount)) {
            printk(KERN_ERR "sysfs: could not mount!\n");
            err = PTR_ERR(sysfs_mount);
            sysfs_mount = NULL;
            unregister_filesystem(&sysfs_fs_type);
            goto out_err;
        }
    } else
        goto out_err;
out:
    return err;
out_err:
    kmem_cache_destroy(sysfs_dir_cachep);
    sysfs_dir_cachep = NULL;
    goto out;
}

#undef sysfs_get
struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd)
{
    return __sysfs_get(sd);
}
EXPORT_SYMBOL_GPL(sysfs_get);

#undef sysfs_put
void sysfs_put(struct sysfs_dirent *sd)
{
    __sysfs_put(sd);
}
EXPORT_SYMBOL_GPL(sysfs_put);




另外注意到:

bus_register()也调用了这个 bus_create_file()



/**
 * bus_register - register a bus with the system.
 * @bus: bus.
 *
 * Once we have that, we registered the bus with the kobject
 * infrastructure, then register the children subsystems it has:
 * the devices and drivers that belong to the bus.
 */
int bus_register(struct bus_type *bus)
{
    int retval;
    struct bus_type_private *priv;

    priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->bus = bus;
    bus->p = priv;

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
    if (retval)
        goto out;

    priv->subsys.kobj.kset = bus_kset;
    priv->subsys.kobj.ktype = &bus_ktype;
    priv->drivers_autoprobe = 1;

    retval = kset_register(&priv->subsys);
    if (retval)
        goto out;

    retval = bus_create_file(bus, &bus_attr_uevent);
    if (retval)
        goto bus_uevent_fail;

    priv->devices_kset = kset_create_and_add("devices", NULL,
                         &priv->subsys.kobj);
    if (!priv->devices_kset) {
        retval = -ENOMEM;
        goto bus_devices_fail;
    }

    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);
    if (!priv->drivers_kset) {
        retval = -ENOMEM;
        goto bus_drivers_fail;
    }
    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
    klist_init(&priv->klist_drivers, NULL, NULL);

    retval = add_probe_files(bus);
    if (retval)
        goto bus_probe_files_fail;

    retval = bus_add_attrs(bus);
    if (retval)
        goto bus_attrs_fail;

    pr_debug("bus: '%s': registered\n", bus->name);
    return 0;

bus_attrs_fail:
    remove_probe_files(bus);
bus_probe_files_fail:
    kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
    kset_unregister(bus->p->devices_kset);
bus_devices_fail:
    bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
    kset_unregister(&bus->p->subsys);
    kfree(bus->p);
out:
    bus->p = NULL;
    return retval;
}
EXPORT_SYMBOL_GPL(bus_register);




/**
 * bus_unregister - remove a bus from the system
 * @bus: bus.
 *
 * Unregister the child subsystems and the bus itself.
 * Finally, we call bus_put() to release the refcount
 */
void bus_unregister(struct bus_type *bus)
{
    pr_debug("bus: '%s': unregistering\n", bus->name);
    bus_remove_attrs(bus);
    remove_probe_files(bus);
    kset_unregister(bus->p->drivers_kset);
    kset_unregister(bus->p->devices_kset);
    bus_remove_file(bus, &bus_attr_uevent);
    kset_unregister(&bus->p->subsys);
    kfree(bus->p);
    bus->p = NULL;
}
EXPORT_SYMBOL_GPL(bus_unregister);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐