Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9b5a03e198c951225d0deb05f3107a4631791266
Commit:     9b5a03e198c951225d0deb05f3107a4631791266
Parent:     cee9e53f59fe1842a7d26fa1e76382fb6ed21048
Author:     Michael Holzheu <[EMAIL PROTECTED]>
AuthorDate: Wed Aug 22 13:51:43 2007 +0200
Committer:  Martin Schwidefsky <[EMAIL PROTECTED]>
CommitDate: Wed Aug 22 13:51:49 2007 +0200

    [S390] hypfs: inode corruption due to missing locking
    
    hypfs removes the whole hypfs directory tree and creates a new one, when a
    process triggers an update by writing to the "update" attribute. 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. This patch:
     * Introduces correct locking
     * Fixes i_nlink reference counting for inodes, when creating directories
     * Adds info printk, when hypfs filesystem has been mounted
    
    Signed-off-by: Michael Holzheu <[EMAIL PROTECTED]>
    Signed-off-by: Martin Schwidefsky <[EMAIL PROTECTED]>
    Signed-off-by: Heiko Carstens <[EMAIL PROTECTED]>
---
 arch/s390/hypfs/inode.c |   33 +++++++++++++++++++++++++--------
 1 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index ad4ca75..5245717 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -60,17 +60,28 @@ static void hypfs_add_dentry(struct dentry *dentry)
        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);
+       }
        d_delete(dentry);
        dput(dentry);
+       mutex_unlock(&parent->d_inode->i_mutex);
 }
 
 static void hypfs_delete_tree(struct dentry *root)
@@ -315,6 +326,7 @@ static int hypfs_fill_super(struct super_block *sb, void 
*data, int silent)
        }
        hypfs_update_update(sb);
        sb->s_root = root_dentry;
+       printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n");
        return 0;
 
 err_tree:
@@ -356,13 +368,17 @@ static struct dentry *hypfs_create_file(struct 
super_block *sb,
        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;
@@ -379,6 +395,8 @@ static struct dentry *hypfs_create_file(struct super_block 
*sb,
        inode->i_private = data;
        d_instantiate(dentry, inode);
        dget(dentry);
+fail:
+       mutex_unlock(&parent->d_inode->i_mutex);
        return dentry;
 }
 
@@ -391,7 +409,6 @@ struct dentry *hypfs_mkdir(struct super_block *sb, struct 
dentry *parent,
        if (IS_ERR(dentry))
                return dentry;
        hypfs_add_dentry(dentry);
-       parent->d_inode->i_nlink++;
        return dentry;
 }
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to