linux/fs/sysfs/group.c
<<
>>
Prefs
   1/*
   2 * fs/sysfs/group.c - Operations for adding/removing multiple files at once.
   3 *
   4 * Copyright (c) 2003 Patrick Mochel
   5 * Copyright (c) 2003 Open Source Development Lab
   6 *
   7 * This file is released undert the GPL v2. 
   8 *
   9 */
  10
  11#include <linux/kobject.h>
  12#include <linux/module.h>
  13#include <linux/dcache.h>
  14#include <linux/namei.h>
  15#include <linux/err.h>
  16#include "sysfs.h"
  17
  18
  19static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
  20                         const struct attribute_group *grp)
  21{
  22        struct attribute *const* attr;
  23        struct bin_attribute *const* bin_attr;
  24
  25        if (grp->attrs)
  26                for (attr = grp->attrs; *attr; attr++)
  27                        sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
  28        if (grp->bin_attrs)
  29                for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++)
  30                        sysfs_remove_bin_file(kobj, *bin_attr);
  31}
  32
  33static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
  34                        const struct attribute_group *grp, int update)
  35{
  36        struct attribute *const* attr;
  37        struct bin_attribute *const* bin_attr;
  38        int error = 0, i;
  39
  40        if (grp->attrs) {
  41                for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
  42                        umode_t mode = 0;
  43
  44                        /*
  45                         * In update mode, we're changing the permissions or
  46                         * visibility.  Do this by first removing then
  47                         * re-adding (if required) the file.
  48                         */
  49                        if (update)
  50                                sysfs_hash_and_remove(dir_sd, NULL,
  51                                                      (*attr)->name);
  52                        if (grp->is_visible) {
  53                                mode = grp->is_visible(kobj, *attr, i);
  54                                if (!mode)
  55                                        continue;
  56                        }
  57                        error = sysfs_add_file_mode(dir_sd, *attr,
  58                                                    SYSFS_KOBJ_ATTR,
  59                                                    (*attr)->mode | mode);
  60                        if (unlikely(error))
  61                                break;
  62                }
  63                if (error) {
  64                        remove_files(dir_sd, kobj, grp);
  65                        goto exit;
  66                }
  67        }
  68
  69        if (grp->bin_attrs) {
  70                for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
  71                        if (update)
  72                                sysfs_remove_bin_file(kobj, *bin_attr);
  73                        error = sysfs_create_bin_file(kobj, *bin_attr);
  74                        if (error)
  75                                break;
  76                }
  77                if (error)
  78                        remove_files(dir_sd, kobj, grp);
  79        }
  80exit:
  81        return error;
  82}
  83
  84
  85static int internal_create_group(struct kobject *kobj, int update,
  86                                 const struct attribute_group *grp)
  87{
  88        struct sysfs_dirent *sd;
  89        int error;
  90
  91        BUG_ON(!kobj || (!update && !kobj->sd));
  92
  93        /* Updates may happen before the object has been instantiated */
  94        if (unlikely(update && !kobj->sd))
  95                return -EINVAL;
  96        if (!grp->attrs && !grp->bin_attrs) {
  97                WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
  98                        kobj->name, grp->name ? "" : grp->name);
  99                return -EINVAL;
 100        }
 101        if (grp->name) {
 102                error = sysfs_create_subdir(kobj, grp->name, &sd);
 103                if (error)
 104                        return error;
 105        } else
 106                sd = kobj->sd;
 107        sysfs_get(sd);
 108        error = create_files(sd, kobj, grp, update);
 109        if (error) {
 110                if (grp->name)
 111                        sysfs_remove_subdir(sd);
 112        }
 113        sysfs_put(sd);
 114        return error;
 115}
 116
 117/**
 118 * sysfs_create_group - given a directory kobject, create an attribute group
 119 * @kobj:       The kobject to create the group on
 120 * @grp:        The attribute group to create
 121 *
 122 * This function creates a group for the first time.  It will explicitly
 123 * warn and error if any of the attribute files being created already exist.
 124 *
 125 * Returns 0 on success or error.
 126 */
 127int sysfs_create_group(struct kobject *kobj,
 128                       const struct attribute_group *grp)
 129{
 130        return internal_create_group(kobj, 0, grp);
 131}
 132
 133/**
 134 * sysfs_update_group - given a directory kobject, update an attribute group
 135 * @kobj:       The kobject to update the group on
 136 * @grp:        The attribute group to update
 137 *
 138 * This function updates an attribute group.  Unlike
 139 * sysfs_create_group(), it will explicitly not warn or error if any
 140 * of the attribute files being created already exist.  Furthermore,
 141 * if the visibility of the files has changed through the is_visible()
 142 * callback, it will update the permissions and add or remove the
 143 * relevant files.
 144 *
 145 * The primary use for this function is to call it after making a change
 146 * that affects group visibility.
 147 *
 148 * Returns 0 on success or error.
 149 */
 150int sysfs_update_group(struct kobject *kobj,
 151                       const struct attribute_group *grp)
 152{
 153        return internal_create_group(kobj, 1, grp);
 154}
 155
 156
 157
 158void sysfs_remove_group(struct kobject * kobj, 
 159                        const struct attribute_group * grp)
 160{
 161        struct sysfs_dirent *dir_sd = kobj->sd;
 162        struct sysfs_dirent *sd;
 163
 164        if (grp->name) {
 165                sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
 166                if (!sd) {
 167                        WARN(!sd, KERN_WARNING "sysfs group %p not found for "
 168                                "kobject '%s'\n", grp, kobject_name(kobj));
 169                        return;
 170                }
 171        } else
 172                sd = sysfs_get(dir_sd);
 173
 174        remove_files(sd, kobj, grp);
 175        if (grp->name)
 176                sysfs_remove_subdir(sd);
 177
 178        sysfs_put(sd);
 179}
 180
 181/**
 182 * sysfs_merge_group - merge files into a pre-existing attribute group.
 183 * @kobj:       The kobject containing the group.
 184 * @grp:        The files to create and the attribute group they belong to.
 185 *
 186 * This function returns an error if the group doesn't exist or any of the
 187 * files already exist in that group, in which case none of the new files
 188 * are created.
 189 */
 190int sysfs_merge_group(struct kobject *kobj,
 191                       const struct attribute_group *grp)
 192{
 193        struct sysfs_dirent *dir_sd;
 194        int error = 0;
 195        struct attribute *const *attr;
 196        int i;
 197
 198        dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
 199        if (!dir_sd)
 200                return -ENOENT;
 201
 202        for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
 203                error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
 204        if (error) {
 205                while (--i >= 0)
 206                        sysfs_hash_and_remove(dir_sd, NULL, (*--attr)->name);
 207        }
 208        sysfs_put(dir_sd);
 209
 210        return error;
 211}
 212EXPORT_SYMBOL_GPL(sysfs_merge_group);
 213
 214/**
 215 * sysfs_unmerge_group - remove files from a pre-existing attribute group.
 216 * @kobj:       The kobject containing the group.
 217 * @grp:        The files to remove and the attribute group they belong to.
 218 */
 219void sysfs_unmerge_group(struct kobject *kobj,
 220                       const struct attribute_group *grp)
 221{
 222        struct sysfs_dirent *dir_sd;
 223        struct attribute *const *attr;
 224
 225        dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
 226        if (dir_sd) {
 227                for (attr = grp->attrs; *attr; ++attr)
 228                        sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
 229                sysfs_put(dir_sd);
 230        }
 231}
 232EXPORT_SYMBOL_GPL(sysfs_unmerge_group);
 233
 234/**
 235 * sysfs_add_link_to_group - add a symlink to an attribute group.
 236 * @kobj:       The kobject containing the group.
 237 * @group_name: The name of the group.
 238 * @target:     The target kobject of the symlink to create.
 239 * @link_name:  The name of the symlink to create.
 240 */
 241int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
 242                            struct kobject *target, const char *link_name)
 243{
 244        struct sysfs_dirent *dir_sd;
 245        int error = 0;
 246
 247        dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name);
 248        if (!dir_sd)
 249                return -ENOENT;
 250
 251        error = sysfs_create_link_sd(dir_sd, target, link_name);
 252        sysfs_put(dir_sd);
 253
 254        return error;
 255}
 256EXPORT_SYMBOL_GPL(sysfs_add_link_to_group);
 257
 258/**
 259 * sysfs_remove_link_from_group - remove a symlink from an attribute group.
 260 * @kobj:       The kobject containing the group.
 261 * @group_name: The name of the group.
 262 * @link_name:  The name of the symlink to remove.
 263 */
 264void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
 265                                  const char *link_name)
 266{
 267        struct sysfs_dirent *dir_sd;
 268
 269        dir_sd = sysfs_get_dirent(kobj->sd, NULL, group_name);
 270        if (dir_sd) {
 271                sysfs_hash_and_remove(dir_sd, NULL, link_name);
 272                sysfs_put(dir_sd);
 273        }
 274}
 275EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
 276
 277EXPORT_SYMBOL_GPL(sysfs_create_group);
 278EXPORT_SYMBOL_GPL(sysfs_update_group);
 279EXPORT_SYMBOL_GPL(sysfs_remove_group);
 280
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.