Am Samstag, 25. November 2006 23:20 schrieb Alan Stern:
> On Sat, 25 Nov 2006, Oliver Neukum wrote:
>
> > OK. How about:
> >
> > struct sysfs_buffer_collection {
> > struct list_head associated_buffers;
> > struct mutex lock;
> > };
> >
> > struct sysfs_buffer {
> > size_t count;
> > loff_t pos;
> > char * page;
> > struct sysfs_buffer_collection * set;
> > struct sysfs_ops * ops;
> > struct semaphore sem;
> > int orphaned;
> > int needs_read_fill;
> > int event;
> > };
> >
> > close() would take the lock of sysfs_buffer_collection, then remove the
> > buffer from the list
> > device_remove_file() takes the lock, walks the elemnts, takes their locks
> > and sets orphaned,
> > then it proceeds normally
> > actual IO to the buffers takes the locks and checks orphaned
> >
> > For validity of sysfs_buffer_collection itself, we depend on the vfs
>
> Go ahead and try to write it. You may find it's a little tricky to create
> the sysfs_buffer_collection in the first place (and to delete it at the
> end). It may also be hard to acquire the locks for the dentry, the
> buffer, and the buffer_collection in the right order.
Very well. This boots and survives a few tests.
Regards
Oliver
--- linux-2.6.19-rc6/fs/sysfs/file.c 2006-11-25 23:49:07.000000000 +0100
+++ sysfs/fs/sysfs/file.c 2006-11-26 12:21:39.000000000 +0100
@@ -7,6 +7,7 @@
#include <linux/kobject.h>
#include <linux/namei.h>
#include <linux/poll.h>
+#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -52,13 +53,16 @@
struct sysfs_buffer {
- size_t count;
- loff_t pos;
- char * page;
- struct sysfs_ops * ops;
- struct semaphore sem;
- int needs_read_fill;
- int event;
+ struct list_head list;
+ size_t count;
+ loff_t pos;
+ char * page;
+ struct sysfs_ops * ops;
+ struct sysfs_buffer_collection * set;
+ struct semaphore sem;
+ int orphaned;
+ int needs_read_fill;
+ int event;
};
@@ -153,6 +157,10 @@
ssize_t retval = 0;
down(&buffer->sem);
+ if (buffer->orphaned) {
+ retval = -ENODEV;
+ goto out;
+ }
if (buffer->needs_read_fill) {
if ((retval = fill_read_buffer(file->f_dentry,buffer)))
goto out;
@@ -164,7 +172,46 @@
up(&buffer->sem);
return retval;
}
+/**
+ * add_to_collection - add buffer to a collection
+ * @buffer: buffer to be added
+ * @set set to add to
+ */
+
+static void
+add_to_collection(struct sysfs_buffer *buffer, struct sysfs_buffer_collection *set)
+{
+ buffer->set = set;
+ mutex_lock(&set->lock);
+ list_add(&buffer->list, &set->associates);
+ mutex_unlock(&set->lock);
+}
+
+static void
+remove_from_collection(struct sysfs_buffer *buffer)
+{
+ struct sysfs_buffer_collection *set = buffer->set;
+
+ mutex_lock(&set->lock);
+ list_del(&buffer->list);
+ mutex_unlock(&set->lock);
+}
+static void
+orphan_all_buffers(struct sysfs_buffer_collection *set)
+{
+ struct list_head *c;
+ struct sysfs_buffer *buf;
+
+ mutex_lock(&set->lock);
+ list_for_each(c, &set->associates) {
+ buf = (struct sysfs_buffer *)c;
+ down(&buf->sem);
+ buf->orphaned = 1;
+ up(&buf->sem);
+ }
+ mutex_unlock(&set->lock);
+}
/**
* fill_write_buffer - copy buffer from userspace.
@@ -240,11 +287,16 @@
ssize_t len;
down(&buffer->sem);
+ if (buffer->orphaned) {
+ len = -ENODEV;
+ goto out;
+ }
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
len = flush_write_buffer(file->f_dentry, buffer, len);
if (len > 0)
*ppos += len;
+out:
up(&buffer->sem);
return len;
}
@@ -253,6 +305,7 @@
{
struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
struct attribute * attr = to_attr(file->f_dentry);
+ struct sysfs_buffer_collection *set;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error = 0;
@@ -282,6 +335,19 @@
if (!ops)
goto Eaccess;
+ /* make sure we have a collection to add our buffers to */
+ mutex_lock(&inode->i_mutex);
+ if (!(set = inode->i_private)) {
+ if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto Done;
+ } else {
+ INIT_LIST_HEAD(&set->associates);
+ mutex_init(&set->lock);
+ }
+ }
+ mutex_unlock(&inode->i_mutex);
+
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
@@ -307,9 +373,11 @@
*/
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (buffer) {
+ INIT_LIST_HEAD(&buffer->list);
init_MUTEX(&buffer->sem);
buffer->needs_read_fill = 1;
buffer->ops = ops;
+ add_to_collection(buffer, set);
file->private_data = buffer;
} else
error = -ENOMEM;
@@ -345,6 +413,7 @@
module_put(owner);
if (buffer) {
+ remove_from_collection(buffer);
if (buffer->page)
free_page((unsigned long)buffer->page);
kfree(buffer);
@@ -545,7 +614,11 @@
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
{
- sysfs_hash_and_remove(kobj->dentry,attr->name);
+ struct dentry *d = kobj->dentry;
+
+ if (d->d_inode->i_private)
+ orphan_all_buffers(d->d_inode->i_private);
+ sysfs_hash_and_remove(d, attr->name);
}
--- linux-2.6.19-rc6/fs/sysfs/mount.c 2006-11-16 05:03:40.000000000 +0100
+++ sysfs/fs/sysfs/mount.c 2006-11-26 14:00:13.000000000 +0100
@@ -18,9 +18,12 @@
struct super_block * sysfs_sb = NULL;
kmem_cache_t *sysfs_dir_cachep;
+static void sysfs_clear_inode(struct inode *inode);
+
static struct super_operations sysfs_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
+ .clear_inode = sysfs_clear_inode,
};
static struct sysfs_dirent sysfs_root = {
@@ -31,6 +34,11 @@
.s_iattr = NULL,
};
+static void sysfs_clear_inode(struct inode *inode)
+{
+ kfree(inode->i_private);
+}
+
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
--- linux-2.6.19-rc6/fs/sysfs/sysfs.h 2006-11-16 05:03:40.000000000 +0100
+++ sysfs/fs/sysfs/sysfs.h 2006-11-26 09:59:09.000000000 +0100
@@ -96,3 +96,7 @@
release_sysfs_dirent(sd);
}
+struct sysfs_buffer_collection {
+ struct list_head associates;
+ struct mutex lock;
+};
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel