Commit c4bd2bfe authored by Patrick Mochel's avatar Patrick Mochel

sysfs: fix BUG()s on directory creation and removal.

- Don't d_delete() files when removing a directory - they must still be 
  hashed when dput() reaps them, and it will __d_drop() them anyway.

- Don't d_invalidate() the directory on removal. 

- do simple_rmdir() after d_delete() on directory. 

- Remove extra dput(), which was causing refcount to go negative, causing 
  an oops when someone tried to create the directory again.

- Make sure we don't d_delete() or do extra dput() on file when updating, 
  either.
parent 2ec18910
...@@ -98,7 +98,6 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -98,7 +98,6 @@ void sysfs_remove_dir(struct kobject * kobj)
* Unlink and unhash. * Unlink and unhash.
*/ */
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
d_delete(d);
simple_unlink(dentry->d_inode,d); simple_unlink(dentry->d_inode,d);
dput(d); dput(d);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
...@@ -108,16 +107,11 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -108,16 +107,11 @@ void sysfs_remove_dir(struct kobject * kobj)
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
up(&dentry->d_inode->i_sem); up(&dentry->d_inode->i_sem);
d_invalidate(dentry);
simple_rmdir(parent->d_inode,dentry);
d_delete(dentry); d_delete(dentry);
simple_rmdir(parent->d_inode,dentry);
pr_debug(" o %s removing done (%d)\n",dentry->d_name.name, pr_debug(" o %s removing done (%d)\n",dentry->d_name.name,
atomic_read(&dentry->d_count)); atomic_read(&dentry->d_count));
/**
* Drop reference from initial sysfs_get_dentry().
*/
dput(dentry);
/** /**
* Drop reference from dget() on entrance. * Drop reference from dget() on entrance.
......
...@@ -93,19 +93,14 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name) ...@@ -93,19 +93,14 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name)
/* make sure dentry is really there */ /* make sure dentry is really there */
if (victim->d_inode && if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) { (victim->d_parent->d_inode == dir->d_inode)) {
simple_unlink(dir->d_inode,victim);
d_delete(victim);
pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
atomic_read(&victim->d_count)); atomic_read(&victim->d_count));
/*
* Drop reference from initial sysfs_get_dentry(). simple_unlink(dir->d_inode,victim);
*/
dput(victim);
} }
/*
/** * Drop reference from sysfs_get_dentry() above.
* Drop the reference acquired from sysfs_get_dentry() above.
*/ */
dput(victim); dput(victim);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment