diff -NurpP --minimal linux-2.6.22.9-vs2.3.0.28.3/fs/namei.c linux-2.6.22.9-vs2.3.0.28.4.2/fs/namei.c --- linux-2.6.22.9-vs2.3.0.28.3/fs/namei.c 2007-10-25 13:30:54 +0200 +++ linux-2.6.22.9-vs2.3.0.28.4.2/fs/namei.c 2007-10-25 18:04:41 +0200 @@ -2775,7 +2775,7 @@ long do_cow_splice(struct file *in, stru struct dentry *cow_break_link(const char *pathname) { - int ret, mode, pathlen; + int ret, redo, mode, pathlen; struct nameidata old_nd, dir_nd; struct dentry *old_dentry, *new_dentry; struct dentry *res, *dir; @@ -2787,14 +2787,13 @@ 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); + ret = -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; @@ -2808,10 +2807,10 @@ struct dentry *cow_break_link(const char old_dentry->d_name.len, old_dentry->d_name.name, old_dentry->d_name.len); - to[pathlen+1] = 0; + to[pathlen + 1] = 0; retry: to[pathlen] = pad--; - res = ERR_PTR(-EMLINK); + ret = -EMLINK; if (pad <= '\240') goto out_rel_old; @@ -2845,16 +2844,13 @@ retry: path_release(&dir_nd); goto retry; } - else if (ret < 0) { - res = ERR_PTR(ret); + else if (ret < 0) goto out_unlock_new; - } - /* drop out early */ - if (d_unhashed(old_dentry)) { - res = ERR_PTR(-ENOENT); + /* drop out early, ret passes ENOENT */ + ret = -ENOENT; + if ((redo = d_unhashed(old_dentry))) goto out_unlock_new; - } new_mnt = dir_nd.mnt; dget(old_dentry); @@ -2874,19 +2870,18 @@ retry: new_file = dentry_open(new_dentry, new_mnt, O_WRONLY); vxdprintk(VXD_CBIT(misc, 2), "dentry_open(new): %p", new_file); - if (!new_file || IS_ERR(new_file)) { - res = IS_ERR(new_file) ? (void *) new_file : res; + + ret = IS_ERR(new_file) ? PTR_ERR(new_file) : -ENOENT; + if (!new_file || IS_ERR(new_file)) goto out_fput_old; - } 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); if (ret < 0) { - res = ERR_PTR(ret); goto out_fput_both; } else if (ret < size) { - res = ERR_PTR(-ENOSPC); + ret = -ENOSPC; goto out_fput_both; } else { struct inode *old_inode = old_dentry->d_inode; @@ -2898,15 +2893,15 @@ retry: }; ret = inode_setattr(new_inode, &attr); - if (ret) { - res = ERR_PTR(ret); + if (ret) goto out_fput_both; - } } mutex_lock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); + + /* drop out late */ ret = -ENOENT; - if (d_unhashed(old_dentry)) + if ((redo = d_unhashed(old_dentry))) goto out_unlock; vxdprintk(VXD_CBIT(misc, 2), @@ -2918,17 +2913,11 @@ retry: ret = vfs_rename(dir_nd.dentry->d_inode, new_dentry, old_nd.dentry->d_parent->d_inode, old_dentry); vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: %d", ret); + res = new_dentry; out_unlock: mutex_unlock(&old_dentry->d_inode->i_sb->s_vfs_rename_mutex); - if (!ret) { - res = new_dentry; - dget(new_dentry); - } - else - res = ERR_PTR(ret); - out_fput_both: vxdprintk(VXD_CBIT(misc, 3), "fput(new_file=%p[#%d])", new_file, @@ -2943,8 +2932,11 @@ out_fput_old: out_unlock_new: mutex_unlock(&dir->d_inode->i_mutex); - if (IS_ERR(res)) - vfs_unlink(dir->d_inode, new_dentry, &dir_nd); + if (!ret) + goto out_rel_both; + + /* error path cleanup */ + vfs_unlink(dir->d_inode, new_dentry, &dir_nd); dput(new_dentry); out_rel_both: path_release(&dir_nd); @@ -2953,6 +2945,8 @@ out_rel_old: out_free_path: kfree(path); out: + if (ret) + res = ERR_PTR(ret); return res; }