Blame view

fs/sysfs/group.c 5.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * fs/sysfs/group.c - Operations for adding/removing multiple files at once.
   *
   * Copyright (c) 2003 Patrick Mochel
   * Copyright (c) 2003 Open Source Development Lab
   *
   * This file is released undert the GPL v2. 
   *
   */
  
  #include <linux/kobject.h>
  #include <linux/module.h>
  #include <linux/dcache.h>
5f45f1a78   Christoph Hellwig   [PATCH] remove du...
14
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/err.h>
  #include "sysfs.h"
d4acd722b   James Bottomley   [SCSI] sysfs: add...
17
  static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
608e266a2   Tejun Heo   sysfs: make kobj ...
18
  			 const struct attribute_group *grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  {
  	struct attribute *const* attr;
d4acd722b   James Bottomley   [SCSI] sysfs: add...
21
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

d4acd722b   James Bottomley   [SCSI] sysfs: add...
23
  	for (i = 0, attr = grp->attrs; *attr; i++, attr++)
3ff195b01   Eric W. Biederman   sysfs: Implement ...
24
  		sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  }
d4acd722b   James Bottomley   [SCSI] sysfs: add...
26
  static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
0f4238958   James Bottomley   [SCSI] sysfs: mak...
27
  			const struct attribute_group *grp, int update)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  {
  	struct attribute *const* attr;
d4acd722b   James Bottomley   [SCSI] sysfs: add...
30
  	int error = 0, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

0f4238958   James Bottomley   [SCSI] sysfs: mak...
32
33
34
35
36
37
38
  	for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
  		mode_t mode = 0;
  
  		/* in update mode, we're changing the permissions or
  		 * visibility.  Do this by first removing then
  		 * re-adding (if required) the file */
  		if (update)
3ff195b01   Eric W. Biederman   sysfs: Implement ...
39
  			sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
0f4238958   James Bottomley   [SCSI] sysfs: mak...
40
41
42
43
44
45
46
47
48
49
  		if (grp->is_visible) {
  			mode = grp->is_visible(kobj, *attr, i);
  			if (!mode)
  				continue;
  		}
  		error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR,
  					    (*attr)->mode | mode);
  		if (unlikely(error))
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  	if (error)
d4acd722b   James Bottomley   [SCSI] sysfs: add...
51
  		remove_files(dir_sd, kobj, grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  	return error;
  }
0f4238958   James Bottomley   [SCSI] sysfs: mak...
54
55
  static int internal_create_group(struct kobject *kobj, int update,
  				 const struct attribute_group *grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  {
608e266a2   Tejun Heo   sysfs: make kobj ...
57
  	struct sysfs_dirent *sd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	int error;
0f4238958   James Bottomley   [SCSI] sysfs: mak...
59
60
61
62
63
  	BUG_ON(!kobj || (!update && !kobj->sd));
  
  	/* Updates may happen before the object has been instantiated */
  	if (unlikely(update && !kobj->sd))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  
  	if (grp->name) {
608e266a2   Tejun Heo   sysfs: make kobj ...
66
  		error = sysfs_create_subdir(kobj, grp->name, &sd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
  		if (error)
  			return error;
  	} else
608e266a2   Tejun Heo   sysfs: make kobj ...
70
71
  		sd = kobj->sd;
  	sysfs_get(sd);
0f4238958   James Bottomley   [SCSI] sysfs: mak...
72
  	error = create_files(sd, kobj, grp, update);
608e266a2   Tejun Heo   sysfs: make kobj ...
73
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  		if (grp->name)
608e266a2   Tejun Heo   sysfs: make kobj ...
75
  			sysfs_remove_subdir(sd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  	}
608e266a2   Tejun Heo   sysfs: make kobj ...
77
  	sysfs_put(sd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
  	return error;
  }
0f4238958   James Bottomley   [SCSI] sysfs: mak...
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  /**
   * 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);
  }
  
  /**
1f8e1cdac   Robert P. J. Day   SYSFS: Fix errone...
97
98
99
   * sysfs_update_group - given a directory kobject, update an attribute group
   * @kobj:	The kobject to update the group on
   * @grp:	The attribute group to update
0f4238958   James Bottomley   [SCSI] sysfs: mak...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
   *
   * This function updates an attribute group.  Unlike
   * sysfs_create_group(), it will explicitly not warn or error if any
   * of the attribute files being created already exist.  Furthermore,
   * if the visibility of the files has changed through the is_visible()
   * callback, it will update the permissions and add or remove the
   * relevant files.
   *
   * The primary use for this function is to call it after making a change
   * that affects group visibility.
   *
   * Returns 0 on success or error.
   */
  int sysfs_update_group(struct kobject *kobj,
  		       const struct attribute_group *grp)
  {
  	return internal_create_group(kobj, 1, grp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
  void sysfs_remove_group(struct kobject * kobj, 
  			const struct attribute_group * grp)
  {
608e266a2   Tejun Heo   sysfs: make kobj ...
121
122
  	struct sysfs_dirent *dir_sd = kobj->sd;
  	struct sysfs_dirent *sd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

057f6c019   James Morris   security: prevent...
124
  	if (grp->name) {
3ff195b01   Eric W. Biederman   sysfs: Implement ...
125
  		sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
969affd27   Greg Kroah-Hartman   sysfs: remove BUG...
126
  		if (!sd) {
99fcd77d1   Arjan van de Ven   Use WARN() in fs/...
127
  			WARN(!sd, KERN_WARNING "sysfs group %p not found for "
969affd27   Greg Kroah-Hartman   sysfs: remove BUG...
128
129
  				"kobject '%s'
  ", grp, kobject_name(kobj));
969affd27   Greg Kroah-Hartman   sysfs: remove BUG...
130
131
  			return;
  		}
608e266a2   Tejun Heo   sysfs: make kobj ...
132
133
  	} else
  		sd = sysfs_get(dir_sd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

d4acd722b   James Bottomley   [SCSI] sysfs: add...
135
  	remove_files(sd, kobj, grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	if (grp->name)
608e266a2   Tejun Heo   sysfs: make kobj ...
137
138
139
  		sysfs_remove_subdir(sd);
  
  	sysfs_put(sd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  }
69d44ffbd   Alan Stern   sysfs: Add sysfs_...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  /**
   * sysfs_merge_group - merge files into a pre-existing attribute group.
   * @kobj:	The kobject containing the group.
   * @grp:	The files to create and the attribute group they belong to.
   *
   * This function returns an error if the group doesn't exist or any of the
   * files already exist in that group, in which case none of the new files
   * are created.
   */
  int sysfs_merge_group(struct kobject *kobj,
  		       const struct attribute_group *grp)
  {
  	struct sysfs_dirent *dir_sd;
  	int error = 0;
  	struct attribute *const *attr;
  	int i;
e030d58e8   Alan Stern   sysfs: remove use...
157
  	dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
69d44ffbd   Alan Stern   sysfs: Add sysfs_...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  	if (!dir_sd)
  		return -ENOENT;
  
  	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
  		error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
  	if (error) {
  		while (--i >= 0)
  			sysfs_hash_and_remove(dir_sd, NULL, (*--attr)->name);
  	}
  	sysfs_put(dir_sd);
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(sysfs_merge_group);
  
  /**
   * sysfs_unmerge_group - remove files from a pre-existing attribute group.
   * @kobj:	The kobject containing the group.
   * @grp:	The files to remove and the attribute group they belong to.
   */
  void sysfs_unmerge_group(struct kobject *kobj,
  		       const struct attribute_group *grp)
  {
  	struct sysfs_dirent *dir_sd;
  	struct attribute *const *attr;
e030d58e8   Alan Stern   sysfs: remove use...
183
  	dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
69d44ffbd   Alan Stern   sysfs: Add sysfs_...
184
185
186
187
188
189
190
  	if (dir_sd) {
  		for (attr = grp->attrs; *attr; ++attr)
  			sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
  		sysfs_put(dir_sd);
  	}
  }
  EXPORT_SYMBOL_GPL(sysfs_unmerge_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  
  EXPORT_SYMBOL_GPL(sysfs_create_group);
0f4238958   James Bottomley   [SCSI] sysfs: mak...
193
  EXPORT_SYMBOL_GPL(sysfs_update_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  EXPORT_SYMBOL_GPL(sysfs_remove_group);