Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3138

kernel-2.6.18-194.11.1.el5.src.rpm

From: Brad Hinson <bhinson@redhat.com>
Subject: Re: [RHEL 5.1 PATCH] hypfs: inode corruption due to missing 	locking (s390x)
Date: Tue, 04 Sep 2007 17:15:16 -0400
Bugzilla: 254169
Message-Id: <1188940516.2384.25.camel@localhost.localdomain>
Changelog: [s390] hypfs: inode corruption due to missing locking

BZ 254169

When removing and creating files, it is necessary to lock the inode of
the parent directory where the files live. Currently hypfs does not lock
the parent inode, which can lead to inode corruption.

-- 
Brad Hinson <bhinson@redhat.com>
Sr. Support Engineer Lead, System z
Red Hat, Inc.

--- linux-2.6.18.s390x/arch/s390/hypfs/inode.c.orig
+++ linux-2.6.18.s390x/arch/s390/hypfs/inode.c
@@ -59,15 +59,26 @@ static void hypfs_add_dentry(struct dent
 	hypfs_last_dentry = dentry;
 }
 
+static inline int hypfs_positive(struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
+
 static void hypfs_remove(struct dentry *dentry)
 {
 	struct dentry *parent;
 
 	parent = dentry->d_parent;
-	if (S_ISDIR(dentry->d_inode->i_mode))
-		simple_rmdir(parent->d_inode, dentry);
-	else
-		simple_unlink(parent->d_inode, dentry);
+	if (!parent || !parent->d_inode)
+		return;
+	mutex_lock(&parent->d_inode->i_mutex);
+	if (hypfs_positive(dentry)) {
+		if (S_ISDIR(dentry->d_inode->i_mode))
+			simple_rmdir(parent->d_inode, dentry);
+		else
+			simple_unlink(parent->d_inode, dentry);
+	}
+	mutex_unlock(&parent->d_inode->i_mutex);
 	d_delete(dentry);
 	dput(dentry);
 }
@@ -290,6 +301,7 @@ static int hypfs_fill_super(struct super
 	}
 	hypfs_update_update(sb);
 	sb->s_root = root_dentry;
+	printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n");
 	return 0;
 
 err_tree:
@@ -331,13 +343,17 @@ static struct dentry *hypfs_create_file(
 	qname.name = name;
 	qname.len = strlen(name);
 	qname.hash = full_name_hash(name, qname.len);
+	mutex_lock(&parent->d_inode->i_mutex);
 	dentry = lookup_one_len(name, parent, strlen(name));
-	if (IS_ERR(dentry))
-		return ERR_PTR(-ENOMEM);
+	if (IS_ERR(dentry)) {
+		dentry = ERR_PTR(-ENOMEM);
+		goto fail;
+	}
 	inode = hypfs_make_inode(sb, mode);
 	if (!inode) {
 		dput(dentry);
-		return ERR_PTR(-ENOMEM);
+		dentry = ERR_PTR(-ENOMEM);
+		goto fail;
 	}
 	if (mode & S_IFREG) {
 		inode->i_fop = &hypfs_file_ops;
@@ -354,6 +370,8 @@ static struct dentry *hypfs_create_file(
 	inode->i_private = data;
 	d_instantiate(dentry, inode);
 	dget(dentry);
+fail:
+	mutex_unlock(&parent->d_inode->i_mutex);
 	return dentry;
 }
 
@@ -366,7 +384,6 @@ struct dentry *hypfs_mkdir(struct super_
 	if (IS_ERR(dentry))
 		return dentry;
 	hypfs_add_dentry(dentry);
-	parent->d_inode->i_nlink++;
 	return dentry;
 }