diff -NurpP --minimal linux-2.6.22.9-vs2.3.0.27/fs/namei.c linux-2.6.22.9-vs2.3.0.27.5/fs/namei.c --- linux-2.6.22.9-vs2.3.0.27/fs/namei.c 2007-10-11 01:10:22 +0200 +++ linux-2.6.22.9-vs2.3.0.27.5/fs/namei.c 2007-10-17 21:23:41 +0200 @@ -2782,7 +2782,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 = ERR_PTR(-EMLINK); + struct dentry *res; struct vfsmount *old_mnt, *new_mnt; struct file *old_file; struct file *new_file; @@ -2791,11 +2791,14 @@ struct dentry *cow_break_link(const char vxdprintk(VXD_CBIT(misc, 1), "cow_break_link(»%s«)", pathname); path = kmalloc(PATH_MAX, GFP_KERNEL); + res = ERR_PTR(-ENOMEM); if (!path) goto out; + /* old_nd will have refs to dentry and mnt */ ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); vxdprintk(VXD_CBIT(misc, 2), "path_lookup(old): %d", ret); + res = ERR_PTR(ret); if (ret < 0) goto out_free_path; @@ -2803,17 +2806,24 @@ 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«", 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); to[pathlen+1] = 0; retry: to[pathlen] = pad--; + res = ERR_PTR(-EMLINK); if (pad <= '\240') goto out_rel_old; 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); vxdprintk(VXD_CBIT(misc, 2), @@ -2821,10 +2831,12 @@ retry: if (ret < 0) goto retry; - /* this puppy downs the inode sem */ + /* this puppy downs the inode mutex */ new_dentry = lookup_create(&dir_nd, 0); vxdprintk(VXD_CBIT(misc, 2), - "lookup_create(new): %p", 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; @@ -2841,14 +2853,14 @@ retry: } else if (ret < 0) { res = ERR_PTR(ret); - goto out_rel_both; + goto out_unlock_new; } new_mnt = dir_nd.mnt; dget(old_dentry); mntget(old_mnt); - /* this one cleans up the dentry in case of failure */ + /* this one cleans up the dentry/mnt in case of failure */ old_file = dentry_open(old_dentry, old_mnt, O_RDONLY); vxdprintk(VXD_CBIT(misc, 2), "dentry_open(old): %p", old_file); @@ -2859,7 +2871,7 @@ retry: dget(new_dentry); mntget(new_mnt); - /* this one cleans up the dentry in case of failure */ + /* this one cleans up the dentry/mnt in case of failure */ new_file = dentry_open(new_dentry, new_mnt, O_WRONLY); vxdprintk(VXD_CBIT(misc, 2), "dentry_open(new): %p", new_file); @@ -2886,11 +2904,23 @@ retry: .ia_valid = ATTR_UID | ATTR_GID }; - inode_setattr(new_inode, &attr); + ret = inode_setattr(new_inode, &attr); + if (ret) { + res = ERR_PTR(ret); + goto out_fput_both; + } } + mutex_lock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); + vxdprintk(VXD_CBIT(misc, 2), + "vfs_rename: [»%*s«:%d] -> [»%*s«:%d]", + new_dentry->d_name.len, new_dentry->d_name.name, + new_dentry->d_name.len, + old_dentry->d_name.len, old_dentry->d_name.name, + 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); if (!ret) { res = new_dentry; @@ -2911,14 +2941,15 @@ out_fput_old: atomic_read(&old_file->f_count)); fput(old_file); -out_rel_both: +out_unlock_new: mutex_unlock(&dir_nd.dentry->d_inode->i_mutex); if (IS_ERR(res)) vfs_unlink(dir_nd.dentry->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.27/fs/super.c linux-2.6.22.9-vs2.3.0.27.5/fs/super.c --- linux-2.6.22.9-vs2.3.0.27/fs/super.c 2007-08-05 20:53:13 +0200 +++ linux-2.6.22.9-vs2.3.0.27.5/fs/super.c 2007-10-17 20:00:53 +0200 @@ -87,6 +87,7 @@ 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.27/include/linux/fs.h linux-2.6.22.9-vs2.3.0.27.5/include/linux/fs.h --- linux-2.6.22.9-vs2.3.0.27/include/linux/fs.h 2007-10-11 01:10:22 +0200 +++ linux-2.6.22.9-vs2.3.0.27.5/include/linux/fs.h 2007-10-17 19:59:57 +0200 @@ -980,6 +980,7 @@ 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 */