diff -NurpP --minimal linux-2.6.22.9-vs2.3.0.28/fs/namei.c linux-2.6.22.9-vs2.3.0.28.2/fs/namei.c --- linux-2.6.22.9-vs2.3.0.28/fs/namei.c 2007-10-18 01:00:26 +0200 +++ linux-2.6.22.9-vs2.3.0.28.2/fs/namei.c 2007-10-19 23:56:54 +0200 @@ -2781,7 +2781,7 @@ struct dentry *cow_break_link(const char int ret, mode, pathlen; struct nameidata old_nd, dir_nd; struct dentry *old_dentry, *new_dentry; - struct dentry *res; + struct dentry *res, *dir; struct vfsmount *old_mnt, *new_mnt; struct file *old_file; struct file *new_file; @@ -2805,12 +2805,9 @@ struct dentry *cow_break_link(const char old_mnt = old_nd.mnt; mode = old_dentry->d_inode->i_mode; - /* lock filesystem during cow */ - mutex_lock(&old_dentry->d_inode->i_sb->s_vfs_cow_mutex); - to = d_path(old_dentry, old_mnt, path, PATH_MAX-2); pathlen = strlen(to); - vxdprintk(VXD_CBIT(misc, 2), "old path »%s« [»%*s«:%d]", to, + vxdprintk(VXD_CBIT(misc, 2), "old path »%s« [»%.*s«:%d]", to, old_dentry->d_name.len, old_dentry->d_name.name, old_dentry->d_name.len); @@ -2824,7 +2821,7 @@ retry: vxdprintk(VXD_CBIT(misc, 1), "temp copy »%s«", to); /* dir_nd will have refs to dentry and mnt */ ret = path_lookup(to, - LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, &dir_nd); + LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE, &dir_nd); vxdprintk(VXD_CBIT(misc, 2), "path_lookup(new): %d", ret); if (ret < 0) @@ -2833,19 +2830,20 @@ retry: /* this puppy downs the inode mutex */ new_dentry = lookup_create(&dir_nd, 0); vxdprintk(VXD_CBIT(misc, 2), - "lookup_create(new): %p [»%*s«:%d]", new_dentry, + "lookup_create(new): %p [»%.*s«:%d]", new_dentry, new_dentry->d_name.len, new_dentry->d_name.name, new_dentry->d_name.len); if (!new_dentry || IS_ERR(new_dentry)) { path_release(&dir_nd); goto retry; } + dir = dir_nd.dentry; ret = vfs_create(dir_nd.dentry->d_inode, new_dentry, mode, &dir_nd); vxdprintk(VXD_CBIT(misc, 2), "vfs_create(new): %d", ret); if (ret == -EEXIST) { - mutex_unlock(&dir_nd.dentry->d_inode->i_mutex); + mutex_unlock(&dir->d_inode->i_mutex); dput(new_dentry); path_release(&dir_nd); goto retry; @@ -2855,8 +2853,13 @@ retry: goto out_unlock_new; } - new_mnt = dir_nd.mnt; + /* drop out early */ + if (d_unhashed(old_dentry)) { + res = ERR_PTR(-ENOENT); + goto out_unlock_new; + } + new_mnt = dir_nd.mnt; dget(old_dentry); mntget(old_mnt); /* this one cleans up the dentry/mnt in case of failure */ @@ -2879,12 +2882,6 @@ retry: goto out_fput_old; } - vxdprintk(VXD_CBIT(misc, 1), - "dentries/inodes: %p/%p %p/%p %p/%p", - old_dentry, old_dentry->d_inode, - new_dentry, new_dentry->d_inode, - dir_nd.dentry, dir_nd.dentry->d_inode); - size = i_size_read(old_file->f_dentry->d_inode); ret = do_cow_splice(old_file, new_file, size); vxdprintk(VXD_CBIT(misc, 2), "do_splice_direct: %d", ret); @@ -2906,11 +2903,15 @@ retry: ret = inode_setattr(new_inode, &attr); if (ret) { res = ERR_PTR(ret); - goto out_fput_both; + goto out_fput_both; } } mutex_lock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); + ret = -ENOENT; + if (d_unhashed(old_dentry)) + goto out_unlock; + vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: [»%*s«:%d] -> [»%*s«:%d]", new_dentry->d_name.len, new_dentry->d_name.name, @@ -2919,8 +2920,11 @@ retry: old_dentry->d_name.len); ret = vfs_rename(dir_nd.dentry->d_inode, new_dentry, old_nd.dentry->d_parent->d_inode, old_dentry); - mutex_unlock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: %d", ret); + +out_unlock: + mutex_unlock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); + if (!ret) { res = new_dentry; dget(new_dentry); @@ -2941,14 +2945,13 @@ out_fput_old: fput(old_file); out_unlock_new: - mutex_unlock(&dir_nd.dentry->d_inode->i_mutex); + mutex_unlock(&dir->d_inode->i_mutex); if (IS_ERR(res)) - vfs_unlink(dir_nd.dentry->d_inode, new_dentry, &dir_nd); + vfs_unlink(dir->d_inode, new_dentry, &dir_nd); dput(new_dentry); out_rel_both: path_release(&dir_nd); out_rel_old: - mutex_unlock(&old_dentry->d_inode->i_sb->s_vfs_cow_mutex); path_release(&old_nd); out_free_path: kfree(path); diff -NurpP --minimal linux-2.6.22.9-vs2.3.0.28/fs/super.c linux-2.6.22.9-vs2.3.0.28.2/fs/super.c --- linux-2.6.22.9-vs2.3.0.28/fs/super.c 2007-10-17 20:00:53 +0200 +++ linux-2.6.22.9-vs2.3.0.28.2/fs/super.c 2007-10-20 00:00:59 +0200 @@ -87,7 +87,6 @@ static struct super_block *alloc_super(s s->s_count = S_BIAS; atomic_set(&s->s_active, 1); mutex_init(&s->s_vfs_rename_mutex); - mutex_init(&s->s_vfs_cow_mutex); mutex_init(&s->s_dquot.dqio_mutex); mutex_init(&s->s_dquot.dqonoff_mutex); init_rwsem(&s->s_dquot.dqptr_sem); diff -NurpP --minimal linux-2.6.22.9-vs2.3.0.28/include/linux/fs.h linux-2.6.22.9-vs2.3.0.28.2/include/linux/fs.h --- linux-2.6.22.9-vs2.3.0.28/include/linux/fs.h 2007-10-17 19:59:57 +0200 +++ linux-2.6.22.9-vs2.3.0.28.2/include/linux/fs.h 2007-10-20 00:01:05 +0200 @@ -980,7 +980,6 @@ struct super_block { * even looking at it. You had been warned. */ struct mutex s_vfs_rename_mutex; /* Kludge */ - struct mutex s_vfs_cow_mutex; /* Granularity of c/m/atime in ns. Cannot be worse than a second */