]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/sysfs/dir.c
[PATCH] debugfs inode leak
[karo-tx-linux.git] / fs / sysfs / dir.c
index 49bd219275db30d6616a05ff8509045f88a39ec5..610b5bdbe75bc1a04c870a3def601b9b666a1772 100644 (file)
@@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
 
        memset(sd, 0, sizeof(*sd));
        atomic_set(&sd->s_count, 1);
+       atomic_set(&sd->s_event, 0);
        INIT_LIST_HEAD(&sd->s_children);
        list_add(&sd->s_sibling, &parent_sd->s_children);
        sd->s_element = element;
@@ -50,6 +51,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
        return sd;
 }
 
+/*
+ *
+ * Return -EEXIST if there is already a sysfs element with the same name for
+ * the same parent.
+ *
+ * called with parent inode's i_mutex held
+ */
+int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
+                         const unsigned char *new)
+{
+       struct sysfs_dirent * sd;
+
+       list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+               if (sd->s_element) {
+                       const unsigned char *existing = sysfs_get_name(sd);
+                       if (strcmp(existing, new))
+                               continue;
+                       else
+                               return -EEXIST;
+               }
+       }
+
+       return 0;
+}
+
+
 int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
                        void * element, umode_t mode, int type)
 {
@@ -102,7 +129,11 @@ static int create_dir(struct kobject * k, struct dentry * p,
        mutex_lock(&p->d_inode->i_mutex);
        *d = lookup_one_len(n, p, strlen(n));
        if (!IS_ERR(*d)) {
-               error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
+               if (sysfs_dirent_exist(p->d_fsdata, n))
+                       error = -EEXIST;
+               else
+                       error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
+                                                               SYSFS_DIR);
                if (!error) {
                        error = sysfs_create(*d, mode, init_dir);
                        if (!error) {
@@ -302,6 +333,7 @@ void sysfs_remove_dir(struct kobject * kobj)
         * Drop reference from dget() on entrance.
         */
        dput(dentry);
+       kobj->dentry = NULL;
 }
 
 int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
@@ -472,14 +504,10 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
        return offset;
 }
 
-struct file_operations sysfs_dir_operations = {
+const struct file_operations sysfs_dir_operations = {
        .open           = sysfs_dir_open,
        .release        = sysfs_dir_close,
        .llseek         = sysfs_dir_lseek,
        .read           = generic_read_dir,
        .readdir        = sysfs_readdir,
 };
-
-EXPORT_SYMBOL_GPL(sysfs_create_dir);
-EXPORT_SYMBOL_GPL(sysfs_remove_dir);
-EXPORT_SYMBOL_GPL(sysfs_rename_dir);