summaryrefslogtreecommitdiffstats
path: root/fs/sysfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r--fs/sysfs/inode.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e79e38d52c0..1a81ebce20e 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -13,6 +13,7 @@
#include <linux/backing-dev.h>
#include <linux/capability.h>
#include <linux/errno.h>
+#include <asm/semaphore.h>
#include "sysfs.h"
extern struct super_block * sysfs_sb;
@@ -209,6 +210,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
return NULL;
}
+static inline void orphan_all_buffers(struct inode *node)
+{
+ struct sysfs_buffer_collection *set = node->i_private;
+ struct sysfs_buffer *buf;
+
+ mutex_lock(&node->i_mutex);
+ if (node->i_private) {
+ list_for_each_entry(buf, &set->associates, associates) {
+ down(&buf->sem);
+ buf->orphaned = 1;
+ up(&buf->sem);
+ }
+ }
+ mutex_unlock(&node->i_mutex);
+}
+
/*
* Unhashes the dentry corresponding to given sysfs_dirent
@@ -217,16 +234,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
{
struct dentry * dentry = sd->s_dentry;
+ struct inode *inode;
if (dentry) {
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry) && dentry->d_inode)) {
+ inode = dentry->d_inode;
+ spin_lock(&inode->i_lock);
+ __iget(inode);
+ spin_unlock(&inode->i_lock);
dget_locked(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, dentry);
+ orphan_all_buffers(inode);
+ iput(inode);
} else {
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);