aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 14:45:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:05 -0400
commit0ab66088c855eca68513bdd7442a426c4b374ced (patch)
tree7f931f7f984ac14701a33d123fa9e03d9048bf8f /fs/sysfs/file.c
parenteb36165353d0e5ac32b063f555acedcbaf6d3b75 (diff)
sysfs: implement sysfs_dirent active reference and immediate disconnect
sysfs: implement sysfs_dirent active reference and immediate disconnect Opening a sysfs node references its associated kobject, so userland can arbitrarily prolong lifetime of a kobject which complicates lifetime rules in drivers. This patch implements active reference and makes the association between kobject and sysfs immediately breakable. Now each sysfs_dirent has two reference counts - s_count and s_active. s_count is a regular reference count which guarantees that the containing sysfs_dirent is accessible. As long as s_count reference is held, all sysfs internal fields in sysfs_dirent are accessible including s_parent and s_name. The newly added s_active is active reference count. This is acquired by invoking sysfs_get_active() and it's the caller's responsibility to ensure sysfs_dirent itself is accessible (should be holding s_count one way or the other). Dereferencing sysfs_dirent to access objects out of sysfs proper requires active reference. This includes access to the associated kobjects, attributes and ops. The active references can be drained and denied by calling sysfs_deactivate(). All active sysfs_dirents must be deactivated after deletion but before the default reference is dropped. This enables immediate disconnect of sysfs nodes. Once a sysfs_dirent is deleted, it won't access any entity external to sysfs proper. Because attr/bin_attr ops access both the node itself and its parent for kobject, they need to hold active references to both. sysfs_get/put_active_two() helpers are provided to help grabbing both references. Parent's is acquired first and released last. Unlike other operations, mmapped area lingers on after mmap() is finished and the module implement implementing it and kobj need to stay referenced till all the mapped pages are gone. This is accomplished by holding one set of active references to the bin_attr and its parent if there have been any mmap during lifetime of an openfile. The references are dropped when the openfile is released. This change makes sysfs lifetime rules independent from both kobject's and module's. It not only fixes several race conditions caused by sysfs not holding onto the proper module when referencing kobject, but also helps fixing and simplifying lifetime management in driver model and drivers by taking sysfs out of the equation. Please read the following message for more info. http://article.gmane.org/gmane.linux.kernel/510293 Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c130
1 files changed, 76 insertions, 54 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 04f6b0ebc889..310430baf572 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -87,8 +87,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
87 */ 87 */
88static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) 88static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
89{ 89{
90 struct sysfs_dirent * sd = dentry->d_fsdata; 90 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
91 struct kobject * kobj = to_kobj(dentry->d_parent); 91 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
92 struct sysfs_ops * ops = buffer->ops; 92 struct sysfs_ops * ops = buffer->ops;
93 int ret = 0; 93 int ret = 0;
94 ssize_t count; 94 ssize_t count;
@@ -98,8 +98,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
98 if (!buffer->page) 98 if (!buffer->page)
99 return -ENOMEM; 99 return -ENOMEM;
100 100
101 buffer->event = atomic_read(&sd->s_event); 101 /* need attr_sd for attr and ops, its parent for kobj */
102 count = ops->show(kobj, sd->s_elem.attr.attr, buffer->page); 102 if (!sysfs_get_active_two(attr_sd))
103 return -ENODEV;
104
105 buffer->event = atomic_read(&attr_sd->s_event);
106 count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
107
108 sysfs_put_active_two(attr_sd);
109
103 BUG_ON(count > (ssize_t)PAGE_SIZE); 110 BUG_ON(count > (ssize_t)PAGE_SIZE);
104 if (count >= 0) { 111 if (count >= 0) {
105 buffer->needs_read_fill = 0; 112 buffer->needs_read_fill = 0;
@@ -195,14 +202,23 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
195 * passing the buffer that we acquired in fill_write_buffer(). 202 * passing the buffer that we acquired in fill_write_buffer().
196 */ 203 */
197 204
198static int 205static int
199flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count) 206flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
200{ 207{
201 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 208 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
202 struct kobject * kobj = to_kobj(dentry->d_parent); 209 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
203 struct sysfs_ops * ops = buffer->ops; 210 struct sysfs_ops * ops = buffer->ops;
211 int rc;
212
213 /* need attr_sd for attr and ops, its parent for kobj */
214 if (!sysfs_get_active_two(attr_sd))
215 return -ENODEV;
216
217 rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
218
219 sysfs_put_active_two(attr_sd);
204 220
205 return ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count); 221 return rc;
206} 222}
207 223
208 224
@@ -246,22 +262,22 @@ out:
246 262
247static int sysfs_open_file(struct inode *inode, struct file *file) 263static int sysfs_open_file(struct inode *inode, struct file *file)
248{ 264{
249 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
250 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 265 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
251 struct attribute *attr = attr_sd->s_elem.attr.attr; 266 struct attribute *attr = attr_sd->s_elem.attr.attr;
267 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
252 struct sysfs_buffer_collection *set; 268 struct sysfs_buffer_collection *set;
253 struct sysfs_buffer * buffer; 269 struct sysfs_buffer * buffer;
254 struct sysfs_ops * ops = NULL; 270 struct sysfs_ops * ops = NULL;
255 int error = 0; 271 int error;
256 272
257 if (!kobj || !attr) 273 /* need attr_sd for attr and ops, its parent for kobj */
258 goto Einval; 274 if (!sysfs_get_active_two(attr_sd))
275 return -ENODEV;
259 276
260 /* Grab the module reference for this attribute if we have one */ 277 /* Grab the module reference for this attribute */
261 if (!try_module_get(attr->owner)) { 278 error = -ENODEV;
262 error = -ENODEV; 279 if (!try_module_get(attr->owner))
263 goto Done; 280 goto err_sput;
264 }
265 281
266 /* if the kobject has no ktype, then we assume that it is a subsystem 282 /* if the kobject has no ktype, then we assume that it is a subsystem
267 * itself, and use ops for it. 283 * itself, and use ops for it.
@@ -276,30 +292,30 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
276 /* No sysfs operations, either from having no subsystem, 292 /* No sysfs operations, either from having no subsystem,
277 * or the subsystem have no operations. 293 * or the subsystem have no operations.
278 */ 294 */
295 error = -EACCES;
279 if (!ops) 296 if (!ops)
280 goto Eaccess; 297 goto err_mput;
281 298
282 /* make sure we have a collection to add our buffers to */ 299 /* make sure we have a collection to add our buffers to */
283 mutex_lock(&inode->i_mutex); 300 mutex_lock(&inode->i_mutex);
284 if (!(set = inode->i_private)) { 301 if (!(set = inode->i_private)) {
285 if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { 302 error = -ENOMEM;
286 error = -ENOMEM; 303 if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL)))
287 goto Done; 304 goto err_mput;
288 } else { 305 else
289 INIT_LIST_HEAD(&set->associates); 306 INIT_LIST_HEAD(&set->associates);
290 }
291 } 307 }
292 mutex_unlock(&inode->i_mutex); 308 mutex_unlock(&inode->i_mutex);
293 309
310 error = -EACCES;
311
294 /* File needs write support. 312 /* File needs write support.
295 * The inode's perms must say it's ok, 313 * The inode's perms must say it's ok,
296 * and we must have a store method. 314 * and we must have a store method.
297 */ 315 */
298 if (file->f_mode & FMODE_WRITE) { 316 if (file->f_mode & FMODE_WRITE) {
299
300 if (!(inode->i_mode & S_IWUGO) || !ops->store) 317 if (!(inode->i_mode & S_IWUGO) || !ops->store)
301 goto Eaccess; 318 goto err_mput;
302
303 } 319 }
304 320
305 /* File needs read support. 321 /* File needs read support.
@@ -308,46 +324,45 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
308 */ 324 */
309 if (file->f_mode & FMODE_READ) { 325 if (file->f_mode & FMODE_READ) {
310 if (!(inode->i_mode & S_IRUGO) || !ops->show) 326 if (!(inode->i_mode & S_IRUGO) || !ops->show)
311 goto Eaccess; 327 goto err_mput;
312 } 328 }
313 329
314 /* No error? Great, allocate a buffer for the file, and store it 330 /* No error? Great, allocate a buffer for the file, and store it
315 * it in file->private_data for easy access. 331 * it in file->private_data for easy access.
316 */ 332 */
333 error = -ENOMEM;
317 buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); 334 buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
318 if (buffer) { 335 if (!buffer)
319 INIT_LIST_HEAD(&buffer->associates); 336 goto err_mput;
320 init_MUTEX(&buffer->sem);
321 buffer->needs_read_fill = 1;
322 buffer->ops = ops;
323 add_to_collection(buffer, inode);
324 file->private_data = buffer;
325 } else
326 error = -ENOMEM;
327 goto Done;
328 337
329 Einval: 338 INIT_LIST_HEAD(&buffer->associates);
330 error = -EINVAL; 339 init_MUTEX(&buffer->sem);
331 goto Done; 340 buffer->needs_read_fill = 1;
332 Eaccess: 341 buffer->ops = ops;
333 error = -EACCES; 342 add_to_collection(buffer, inode);
343 file->private_data = buffer;
344
345 /* open succeeded, put active references and pin attr_sd */
346 sysfs_put_active_two(attr_sd);
347 sysfs_get(attr_sd);
348 return 0;
349
350 err_mput:
334 module_put(attr->owner); 351 module_put(attr->owner);
335 Done: 352 err_sput:
336 if (error) 353 sysfs_put_active_two(attr_sd);
337 kobject_put(kobj);
338 return error; 354 return error;
339} 355}
340 356
341static int sysfs_release(struct inode * inode, struct file * filp) 357static int sysfs_release(struct inode * inode, struct file * filp)
342{ 358{
343 struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
344 struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; 359 struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
345 struct attribute *attr = attr_sd->s_elem.attr.attr; 360 struct attribute *attr = attr_sd->s_elem.attr.attr;
346 struct sysfs_buffer * buffer = filp->private_data; 361 struct sysfs_buffer * buffer = filp->private_data;
347 362
348 if (buffer) 363 if (buffer)
349 remove_from_collection(buffer, inode); 364 remove_from_collection(buffer, inode);
350 kobject_put(kobj); 365 sysfs_put(attr_sd);
351 /* After this point, attr should not be accessed. */ 366 /* After this point, attr should not be accessed. */
352 module_put(attr->owner); 367 module_put(attr->owner);
353 368
@@ -376,18 +391,25 @@ static int sysfs_release(struct inode * inode, struct file * filp)
376static unsigned int sysfs_poll(struct file *filp, poll_table *wait) 391static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
377{ 392{
378 struct sysfs_buffer * buffer = filp->private_data; 393 struct sysfs_buffer * buffer = filp->private_data;
379 struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); 394 struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
380 struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata; 395 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
381 int res = 0; 396
397 /* need parent for the kobj, grab both */
398 if (!sysfs_get_active_two(attr_sd))
399 goto trigger;
382 400
383 poll_wait(filp, &kobj->poll, wait); 401 poll_wait(filp, &kobj->poll, wait);
384 402
385 if (buffer->event != atomic_read(&sd->s_event)) { 403 sysfs_put_active_two(attr_sd);
386 res = POLLERR|POLLPRI;
387 buffer->needs_read_fill = 1;
388 }
389 404
390 return res; 405 if (buffer->event != atomic_read(&attr_sd->s_event))
406 goto trigger;
407
408 return 0;
409
410 trigger:
411 buffer->needs_read_fill = 1;
412 return POLLERR|POLLPRI;
391} 413}
392 414
393 415