From 1b4d5b5081d9732e0761abf1b592efc979679b00 Mon Sep 17 00:00:00 2001 From: Herbert Poetzl Date: Sat, 20 Oct 2007 01:03:33 +0200 Subject: [PATCH] minor redesign for the CoW Link Break locking, to avoid lower layer problems with unhashed dentries the locking is now quite similar to the one done in do_rename() except for the fact that the splice operation is done outside the lock, but will be avoided completely if the dentry is invalidated [ delta-cow-fix17.diff ] --- fs/namei.c | 37 +++++++++++++++++++++++-------------- fs/super.c | 1 - include/linux/fs.h | 1 - 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 319af2e..5b7b17f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2772,7 +2772,7 @@ struct dentry *cow_break_link(const char *pathname) 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; @@ -2796,12 +2796,9 @@ struct dentry *cow_break_link(const char *pathname) 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); @@ -2815,7 +2812,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) @@ -2824,19 +2821,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; @@ -2846,8 +2844,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 */ @@ -2891,11 +2894,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, @@ -2904,8 +2911,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); @@ -2926,14 +2936,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 --git a/fs/super.c b/fs/super.c index 2903ecf..8ee97d3 100644 --- a/fs/super.c +++ b/fs/super.c @@ -87,7 +87,6 @@ static struct super_block *alloc_super(struct file_system_type *type) 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 --git a/include/linux/fs.h b/include/linux/fs.h index 9418ab3..5605b8f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -979,7 +979,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 */ -- 1.5.2.5