diff options
author | Neil Brown <neilb@suse.de> | 2008-07-15 18:58:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-10-16 12:24:47 -0400 |
commit | f1282c844e86db5a041afa41335b5f9eea6cec0c (patch) | |
tree | 3736285f2f7ce145fb06538d616a9c1165ffc125 /fs/sysfs/file.c | |
parent | ec748fa9ed3fec44aeebbf86ae050b0cc7a978d9 (diff) |
sysfs: Support sysfs_notify from atomic context with new sysfs_notify_dirent
Support sysfs_notify from atomic context with new sysfs_notify_dirent
sysfs_notify currently takes sysfs_mutex.
This means that it cannot be called in atomic context.
sysfs_mutex is sometimes held over a malloc (sysfs_rename_dir)
so it can block on low memory.
In md I want to be able to notify on a sysfs attribute from
atomic context, and I don't want to block on low memory because I
could be in the writeout path for freeing memory.
So:
- export the "sysfs_dirent" structure along with sysfs_get, sysfs_put
and sysfs_get_dirent so I can get the sysfs_dirent that I want to
notify on and hold it in an md structure.
- split sysfs_notify_dirent out of sysfs_notify so the sysfs_dirent
can be notified on with no blocking (just a spinlock).
Signed-off-by: Neil Brown <neilb@suse.de>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index ce8339c70a4b..d0d79e6b6d11 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -453,6 +453,22 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | |||
453 | return POLLERR|POLLPRI; | 453 | return POLLERR|POLLPRI; |
454 | } | 454 | } |
455 | 455 | ||
456 | void sysfs_notify_dirent(struct sysfs_dirent *sd) | ||
457 | { | ||
458 | struct sysfs_open_dirent *od; | ||
459 | |||
460 | spin_lock(&sysfs_open_dirent_lock); | ||
461 | |||
462 | od = sd->s_attr.open; | ||
463 | if (od) { | ||
464 | atomic_inc(&od->event); | ||
465 | wake_up_interruptible(&od->poll); | ||
466 | } | ||
467 | |||
468 | spin_unlock(&sysfs_open_dirent_lock); | ||
469 | } | ||
470 | EXPORT_SYMBOL_GPL(sysfs_notify_dirent); | ||
471 | |||
456 | void sysfs_notify(struct kobject *k, char *dir, char *attr) | 472 | void sysfs_notify(struct kobject *k, char *dir, char *attr) |
457 | { | 473 | { |
458 | struct sysfs_dirent *sd = k->sd; | 474 | struct sysfs_dirent *sd = k->sd; |
@@ -463,19 +479,8 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) | |||
463 | sd = sysfs_find_dirent(sd, dir); | 479 | sd = sysfs_find_dirent(sd, dir); |
464 | if (sd && attr) | 480 | if (sd && attr) |
465 | sd = sysfs_find_dirent(sd, attr); | 481 | sd = sysfs_find_dirent(sd, attr); |
466 | if (sd) { | 482 | if (sd) |
467 | struct sysfs_open_dirent *od; | 483 | sysfs_notify_dirent(sd); |
468 | |||
469 | spin_lock(&sysfs_open_dirent_lock); | ||
470 | |||
471 | od = sd->s_attr.open; | ||
472 | if (od) { | ||
473 | atomic_inc(&od->event); | ||
474 | wake_up_interruptible(&od->poll); | ||
475 | } | ||
476 | |||
477 | spin_unlock(&sysfs_open_dirent_lock); | ||
478 | } | ||
479 | 484 | ||
480 | mutex_unlock(&sysfs_mutex); | 485 | mutex_unlock(&sysfs_mutex); |
481 | } | 486 | } |