From neilb@suse.de Mon Jan 16 13:57:41 2006 From: Neil Brown To: maneesh@in.ibm.com Date: Thu, 12 Jan 2006 12:17:40 +1100 Message-ID: <17349.44596.839590.753601@cse.unsw.edu.au> Cc: , greg@kroah.com Subject: fix up the sysfs pollable patch On Friday December 23, maneesh@in.ibm.com wrote: > > I donot agree with the sysfs_find() implementation and I think > Neil is trying to rework that. Also IMO, to allow proper poll semantics, > the read buffer should be flushed so as to see new contents on re-read. Does the patch below remove your concerns with sysfs_find? It also should allow you to reread the file (not requiring close and re-open). How I don't think this really classifies as "proper poll semantics". What we are doing is something quite different to what 'poll' is normally used for. It is really a lot more like 'notify', but that interface isn't as mature yet. NeilBrown Signed-off-by: Neil Brown Acked-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 44 ++++++++++++++++++++++++++++++++++++-------- fs/sysfs/inode.c | 21 --------------------- 2 files changed, 36 insertions(+), 29 deletions(-) --- gregkh-2.6.orig/fs/sysfs/file.c +++ gregkh-2.6/fs/sysfs/file.c @@ -375,22 +375,50 @@ static unsigned int sysfs_poll(struct fi poll_wait(filp, &kobj->poll, wait); - if (buffer->event != atomic_read(&sd->s_event)) + if (buffer->event != atomic_read(&sd->s_event)) { res = POLLERR|POLLPRI; + buffer->needs_read_fill = 1; + } return res; } + +static struct dentry *step_down(struct dentry *dir, const char * name) +{ + struct dentry * de; + + if (dir == NULL || dir->d_inode == NULL) + return NULL; + + mutex_lock(&dir->d_inode->i_mutex); + de = lookup_one_len(name, dir, strlen(name)); + mutex_unlock(&dir->d_inode->i_mutex); + dput(dir); + if (IS_ERR(de)) + return NULL; + if (de->d_inode == NULL) { + dput(de); + return NULL; + } + return de; +} + void sysfs_notify(struct kobject * k, char *dir, char *attr) { - struct sysfs_dirent * sd = k->dentry->d_fsdata; - if (sd && dir) - sd = sysfs_find(sd, dir); - if (sd && attr) - sd = sysfs_find(sd, attr); - if (sd) { - atomic_inc(&sd->s_event); + struct dentry *de = k->dentry; + if (de) + dget(de); + if (de && dir) + de = step_down(de, dir); + if (de && attr) + de = step_down(de, attr); + if (de) { + struct sysfs_dirent * sd = de->d_fsdata; + if (sd) + atomic_inc(&sd->s_event); wake_up_interruptible(&k->poll); + dput(de); } } EXPORT_SYMBOL_GPL(sysfs_notify); --- gregkh-2.6.orig/fs/sysfs/inode.c +++ gregkh-2.6/fs/sysfs/inode.c @@ -246,24 +246,3 @@ void sysfs_hash_and_remove(struct dentry } mutex_unlock(&dir->d_inode->i_mutex); } - -struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name) -{ - struct sysfs_dirent * sd, * rv = NULL; - - if (dir->s_dentry == NULL || - dir->s_dentry->d_inode == NULL) - return NULL; - - mutex_lock(&dir->s_dentry->d_inode->i_mutex); - list_for_each_entry(sd, &dir->s_children, s_sibling) { - if (!sd->s_element) - continue; - if (!strcmp(sysfs_get_name(sd), name)) { - rv = sd; - break; - } - } - mutex_unlock(&dir->s_dentry->d_inode->i_mutex); - return rv; -}