ext4: Add fallback for find_group_flex
[safe/jmp/linux-2.6] / fs / sysfs / file.c
index a859c32..1f4a3f8 100644 (file)
 #include <linux/kobject.h>
 #include <linux/kallsyms.h>
 #include <linux/slab.h>
+#include <linux/fsnotify.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/limits.h>
 #include <asm/uaccess.h>
 
 #include "sysfs.h"
 
+/* used in crash dumps to help with debugging */
+static char last_sysfs_file[PATH_MAX];
+void sysfs_printk_last_file(void)
+{
+       printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file);
+}
+
 /*
  * There's one sysfs_buffer for each open file and one
  * sysfs_open_dirent for each sysfs_dirent with one or more open
@@ -129,13 +138,13 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        ssize_t retval = 0;
 
        mutex_lock(&buffer->mutex);
-       if (buffer->needs_read_fill) {
+       if (buffer->needs_read_fill || *ppos == 0) {
                retval = fill_read_buffer(file->f_path.dentry,buffer);
                if (retval)
                        goto out;
        }
        pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
-                __FUNCTION__, count, *ppos, buffer->page);
+                __func__, count, *ppos, buffer->page);
        retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
                                         buffer->count);
 out:
@@ -327,6 +336,11 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
        struct sysfs_buffer *buffer;
        struct sysfs_ops *ops;
        int error = -EACCES;
+       char *p;
+
+       p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file));
+       if (p)
+               memmove(last_sysfs_file, p, strlen(p) + 1);
 
        /* need attr_sd for attr and ops, its parent for kobj */
        if (!sysfs_get_active_two(attr_sd))
@@ -336,9 +350,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
        if (kobj->ktype && kobj->ktype->sysfs_ops)
                ops = kobj->ktype->sysfs_ops;
        else {
-               printk(KERN_ERR "missing sysfs attribute operations for "
+               WARN(1, KERN_ERR "missing sysfs attribute operations for "
                       "kobject: %s\n", kobject_name(kobj));
-               WARN_ON(1);
                goto err_out;
        }
 
@@ -410,8 +423,7 @@ static int sysfs_release(struct inode *inode, struct file *filp)
  * return POLLERR|POLLPRI, and select will return the fd whether
  * it is waiting for read, write, or exceptions.
  * Once poll/select indicates that the value has changed, you
- * need to close and re-open the file, as simply seeking and reading
- * again will not get new data, or reset the state of 'poll'.
+ * need to close and re-open the file, or seek to 0 and read again.
  * Reminder: this only works for attributes which actively support
  * it, and it is not possible to test an attribute from userspace
  * to see if it supports poll (Neither 'poll' nor 'select' return
@@ -441,7 +453,23 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
        return POLLERR|POLLPRI;
 }
 
-void sysfs_notify(struct kobject *k, char *dir, char *attr)
+void sysfs_notify_dirent(struct sysfs_dirent *sd)
+{
+       struct sysfs_open_dirent *od;
+
+       spin_lock(&sysfs_open_dirent_lock);
+
+       od = sd->s_attr.open;
+       if (od) {
+               atomic_inc(&od->event);
+               wake_up_interruptible(&od->poll);
+       }
+
+       spin_unlock(&sysfs_open_dirent_lock);
+}
+EXPORT_SYMBOL_GPL(sysfs_notify_dirent);
+
+void sysfs_notify(struct kobject *k, const char *dir, const char *attr)
 {
        struct sysfs_dirent *sd = k->sd;
 
@@ -451,19 +479,8 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr)
                sd = sysfs_find_dirent(sd, dir);
        if (sd && attr)
                sd = sysfs_find_dirent(sd, attr);
-       if (sd) {
-               struct sysfs_open_dirent *od;
-
-               spin_lock(&sysfs_open_dirent_lock);
-
-               od = sd->s_attr.open;
-               if (od) {
-                       atomic_inc(&od->event);
-                       wake_up_interruptible(&od->poll);
-               }
-
-               spin_unlock(&sysfs_open_dirent_lock);
-       }
+       if (sd)
+               sysfs_notify_dirent(sd);
 
        mutex_unlock(&sysfs_mutex);
 }
@@ -478,11 +495,10 @@ const struct file_operations sysfs_file_operations = {
        .poll           = sysfs_poll,
 };
 
-
-int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
-                  int type)
+int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
+                       const struct attribute *attr, int type, mode_t amode)
 {
-       umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
+       umode_t mode = (amode & S_IALLUGO) | S_IFREG;
        struct sysfs_addrm_cxt acxt;
        struct sysfs_dirent *sd;
        int rc;
@@ -503,6 +519,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
 }
 
 
+int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
+                  int type)
+{
+       return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
+}
+
+
 /**
  *     sysfs_create_file - create an attribute file for an object.
  *     @kobj:  object we're creating for. 
@@ -580,9 +603,11 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
 
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-       rc = notify_change(victim, &newattrs);
+       newattrs.ia_ctime = current_fs_time(inode->i_sb);
+       rc = sysfs_setattr(victim, &newattrs);
 
        if (rc == 0) {
+               fsnotify_change(victim, newattrs.ia_valid);
                mutex_lock(&sysfs_mutex);
                victim_sd->s_mode = newattrs.ia_mode;
                mutex_unlock(&sysfs_mutex);