Commit 6dc7de88 authored by Patrick Mochel's avatar Patrick Mochel

clean up driverfs removal of directories

- Make sure we have a valid inode when deleting a dentry
- use list_for_each_safe instead of manually walking ->d_subdirs
- don't do dget() in driverfs_mknod, since we already have a reference to it via driverfs_create_*
- so, remove extra dput() in driverfs_remove_dir and driverfs_remove_file
- Don't do get_mount() in driverfs_create_file, since it was done for the directory
- so remove extrra put_mount() from driverfs_remove_*
- Call d_invalidate() to unhash the files and directories instead of d_delete
- Remove our own d_unhash(), since d_invalidate() does the equivalent
- inline driverfs_rmdir in driverfs_remove_dir since its the only user and it prevents us from
  taking the dir's semaphore twice.
parent 538588a7
...@@ -140,7 +140,6 @@ static int driverfs_mknod(struct inode *dir, struct dentry *dentry, int mode, in ...@@ -140,7 +140,6 @@ static int driverfs_mknod(struct inode *dir, struct dentry *dentry, int mode, in
inode = driverfs_get_inode(dir->i_sb, mode, dev); inode = driverfs_get_inode(dir->i_sb, mode, dev);
if (inode) { if (inode) {
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dget(dentry);
error = 0; error = 0;
} }
return error; return error;
...@@ -213,48 +212,10 @@ static int driverfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -213,48 +212,10 @@ static int driverfs_unlink(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
down(&inode->i_sem); down(&inode->i_sem);
dentry->d_inode->i_nlink--; dentry->d_inode->i_nlink--;
dput(dentry);
up(&inode->i_sem); up(&inode->i_sem);
d_delete(dentry); d_invalidate(dentry);
return 0;
}
static void d_unhash(struct dentry *dentry)
{
dget(dentry);
spin_lock(&dcache_lock);
switch (atomic_read(&dentry->d_count)) {
default:
spin_unlock(&dcache_lock);
shrink_dcache_parent(dentry);
spin_lock(&dcache_lock);
if (atomic_read(&dentry->d_count) != 2)
break;
case 2:
list_del_init(&dentry->d_hash);
}
spin_unlock(&dcache_lock);
}
static int driverfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error = -ENOTEMPTY;
struct inode * inode = dentry->d_inode;
down(&inode->i_sem);
d_unhash(dentry);
if (driverfs_empty(dentry)) {
dentry->d_inode->i_nlink -= 2;
dput(dentry);
inode->i_flags |= S_DEAD;
dir->i_nlink--;
error = 0;
}
up(&inode->i_sem);
if (!error)
d_delete(dentry);
dput(dentry); dput(dentry);
return error; return 0;
} }
/** /**
...@@ -612,9 +573,6 @@ driverfs_create_file(struct attribute * entry, ...@@ -612,9 +573,6 @@ driverfs_create_file(struct attribute * entry,
if (!entry || !parent) if (!entry || !parent)
return -EINVAL; return -EINVAL;
/* make sure we're mounted */
get_mount();
if (!parent->dentry) { if (!parent->dentry) {
put_mount(); put_mount();
return -EINVAL; return -EINVAL;
...@@ -628,8 +586,6 @@ driverfs_create_file(struct attribute * entry, ...@@ -628,8 +586,6 @@ driverfs_create_file(struct attribute * entry,
} else } else
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
up(&parent->dentry->d_inode->i_sem); up(&parent->dentry->d_inode->i_sem);
if (error)
put_mount();
return error; return error;
} }
...@@ -649,8 +605,6 @@ int driverfs_create_symlink(struct driver_dir_entry * parent, ...@@ -649,8 +605,6 @@ int driverfs_create_symlink(struct driver_dir_entry * parent,
if (!parent) if (!parent)
return -EINVAL; return -EINVAL;
get_mount();
if (!parent->dentry) { if (!parent->dentry) {
put_mount(); put_mount();
return -EINVAL; return -EINVAL;
...@@ -662,8 +616,6 @@ int driverfs_create_symlink(struct driver_dir_entry * parent, ...@@ -662,8 +616,6 @@ int driverfs_create_symlink(struct driver_dir_entry * parent,
else else
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
up(&parent->dentry->d_inode->i_sem); up(&parent->dentry->d_inode->i_sem);
if (error)
put_mount();
return error; return error;
} }
...@@ -689,8 +641,6 @@ void driverfs_remove_file(struct driver_dir_entry * dir, const char * name) ...@@ -689,8 +641,6 @@ void driverfs_remove_file(struct driver_dir_entry * dir, const char * name)
if (dentry->d_inode && if (dentry->d_inode &&
(dentry->d_parent->d_inode == dir->dentry->d_inode)) { (dentry->d_parent->d_inode == dir->dentry->d_inode)) {
driverfs_unlink(dir->dentry->d_inode,dentry); driverfs_unlink(dir->dentry->d_inode,dentry);
dput(dentry);
put_mount();
} }
} }
up(&dir->dentry->d_inode->i_sem); up(&dir->dentry->d_inode->i_sem);
...@@ -701,33 +651,39 @@ void driverfs_remove_file(struct driver_dir_entry * dir, const char * name) ...@@ -701,33 +651,39 @@ void driverfs_remove_file(struct driver_dir_entry * dir, const char * name)
* @dir: directory to remove * @dir: directory to remove
* *
* To make sure we don't orphan anyone, first remove * To make sure we don't orphan anyone, first remove
* all the children in the list, then do vfs_rmdir() to remove it * all the children in the list, then do clean up the directory.
* and decrement the refcount..
*/ */
void driverfs_remove_dir(struct driver_dir_entry * dir) void driverfs_remove_dir(struct driver_dir_entry * dir)
{ {
struct list_head * node; struct list_head * node, * next;
struct dentry * dentry = dir->dentry; struct dentry * dentry = dir->dentry;
struct dentry * parent;
if (!dentry) if (!dentry)
goto done; goto done;
down(&dentry->d_parent->d_inode->i_sem); parent = dget(dentry->d_parent);
down(&parent->d_inode->i_sem);
down(&dentry->d_inode->i_sem); down(&dentry->d_inode->i_sem);
node = dentry->d_subdirs.next; list_for_each_safe(node,next,&dentry->d_subdirs) {
while (node != &dentry->d_subdirs) {
struct dentry * d = list_entry(node,struct dentry,d_child); struct dentry * d = list_entry(node,struct dentry,d_child);
/* make sure dentry is still there */
if (d->d_inode)
driverfs_unlink(dentry->d_inode,d);
}
node = node->next; d_invalidate(dentry);
driverfs_unlink(dentry->d_inode,d); if (driverfs_empty(dentry)) {
dput(d); dentry->d_inode->i_nlink -= 2;
put_mount(); dentry->d_inode->i_flags |= S_DEAD;
parent->d_inode->i_nlink--;
} }
up(&dentry->d_inode->i_sem); up(&dentry->d_inode->i_sem);
driverfs_rmdir(dentry->d_parent->d_inode,dentry);
up(&dentry->d_parent->d_inode->i_sem);
dput(dentry); dput(dentry);
up(&parent->d_inode->i_sem);
dput(parent);
done: done:
put_mount(); put_mount();
} }
......
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