linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / sysfs / file.c
index 352f966..a2875c9 100644 (file)
@@ -3,8 +3,9 @@
  */
 
 #include <linux/module.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
 #include <linux/kobject.h>
+#include <linux/namei.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
@@ -13,7 +14,7 @@
 #define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
 #define to_sattr(a) container_of(a,struct subsys_attribute,attr)
 
-/**
+/*
  * Subsystem file operations.
  * These operations allow subsystems to have files that can be 
  * read/written. 
@@ -23,7 +24,7 @@ subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
 {
        struct subsystem * s = to_subsys(kobj);
        struct subsys_attribute * sattr = to_sattr(attr);
-       ssize_t ret = 0;
+       ssize_t ret = -EIO;
 
        if (sattr->show)
                ret = sattr->show(s,page);
@@ -36,7 +37,7 @@ subsys_attr_store(struct kobject * kobj, struct attribute * attr,
 {
        struct subsystem * s = to_subsys(kobj);
        struct subsys_attribute * sattr = to_sattr(attr);
-       ssize_t ret = 0;
+       ssize_t ret = -EIO;
 
        if (sattr->store)
                ret = sattr->store(s,page,count);
@@ -96,7 +97,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
 /**
  *     flush_read_buffer - push buffer to userspace.
  *     @buffer:        data buffer for file.
- *     @userbuf:       user-passed buffer.
+ *     @buf:           user-passed buffer.
  *     @count:         number of bytes requested.
  *     @ppos:          file position.
  *
@@ -164,7 +165,7 @@ out:
 /**
  *     fill_write_buffer - copy buffer from userspace.
  *     @buffer:        data buffer for file.
- *     @userbuf:       data from user.
+ *     @buf:           data from user.
  *     @count:         number of bytes in @userbuf.
  *
  *     Allocate @buffer->page if it hasn't been already, then
@@ -191,8 +192,9 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
 
 /**
  *     flush_write_buffer - push buffer to kobject.
- *     @file:          file pointer.
+ *     @dentry:        dentry to the attribute
  *     @buffer:        data buffer for file.
+ *     @count:         number of bytes
  *
  *     Get the correct pointers for the kobject and the attribute we're
  *     dealing with, then call the store() method for the attribute, 
@@ -362,9 +364,9 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
        umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
        int error = 0;
 
-       down(&dir->d_inode->i_sem);
+       mutex_lock(&dir->d_inode->i_mutex);
        error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
-       up(&dir->d_inode->i_sem);
+       mutex_unlock(&dir->d_inode->i_mutex);
 
        return error;
 }
@@ -389,9 +391,6 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
  * sysfs_update_file - update the modified timestamp on an object attribute.
  * @kobj: object we're acting for.
  * @attr: attribute descriptor.
- *
- * Also call dnotify for the dentry, which lots of userspace programs
- * use.
  */
 int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
 {
@@ -399,19 +398,14 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
        struct dentry * victim;
        int res = -ENOENT;
 
-       down(&dir->d_inode->i_sem);
-       victim = sysfs_get_dentry(dir, attr->name);
+       mutex_lock(&dir->d_inode->i_mutex);
+       victim = lookup_one_len(attr->name, dir, strlen(attr->name));
        if (!IS_ERR(victim)) {
                /* make sure dentry is really there */
                if (victim->d_inode && 
                    (victim->d_parent->d_inode == dir->d_inode)) {
                        victim->d_inode->i_mtime = CURRENT_TIME;
-                       dnotify_parent(victim, DN_MODIFY);
-
-                       /**
-                        * Drop reference from initial sysfs_get_dentry().
-                        */
-                       dput(victim);
+                       fsnotify_modify(victim);
                        res = 0;
                } else
                        d_drop(victim);
@@ -421,10 +415,47 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
                 */
                dput(victim);
        }
-       up(&dir->d_inode->i_sem);
+       mutex_unlock(&dir->d_inode->i_mutex);
+
+       return res;
+}
+
+
+/**
+ * sysfs_chmod_file - update the modified mode value on an object attribute.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ * @mode: file permissions.
+ *
+ */
+int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+{
+       struct dentry *dir = kobj->dentry;
+       struct dentry *victim;
+       struct inode * inode;
+       struct iattr newattrs;
+       int res = -ENOENT;
+
+       mutex_lock(&dir->d_inode->i_mutex);
+       victim = lookup_one_len(attr->name, dir, strlen(attr->name));
+       if (!IS_ERR(victim)) {
+               if (victim->d_inode &&
+                   (victim->d_parent->d_inode == dir->d_inode)) {
+                       inode = victim->d_inode;
+                       mutex_lock(&inode->i_mutex);
+                       newattrs.ia_mode = (mode & S_IALLUGO) |
+                                               (inode->i_mode & ~S_IALLUGO);
+                       newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+                       res = notify_change(victim, &newattrs);
+                       mutex_unlock(&inode->i_mutex);
+               }
+               dput(victim);
+       }
+       mutex_unlock(&dir->d_inode->i_mutex);
 
        return res;
 }
+EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 
 
 /**
@@ -444,4 +475,3 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
 EXPORT_SYMBOL_GPL(sysfs_update_file);
-