cpusets: fix race in cpuset_add_file()

From: Paul Jackson
Date: Fri Sep 17 2004 - 06:35:10 EST


This patch fixes a missing down()/up() pair in cpuset_add_file().

Without this patch, sometimes it is possible to have two duplicate
dentries for a single file of a cpuset, with one of them being invalid,
and thus the file is present but cannot be opened...

By holding the cpuset directory inode (after the directory is created,
while each file in it is being populated), we prevent a stat(2) or
open(2) from creating a second, invalid directory entry for one of the
files in a cpuset directory, while cpuset_populate_dir is trying to
create the same file.

Signed-off-by: Simon Derr <simon.derr@xxxxxxxx>
Signed-off-by: Paul Jackson <pj@xxxxxxx>

Index: 2.6.9-rc2-mm1/kernel/cpuset.c
===================================================================
--- 2.6.9-rc2-mm1.orig/kernel/cpuset.c 2004-09-17 02:12:26.000000000 -0700
+++ 2.6.9-rc2-mm1/kernel/cpuset.c 2004-09-17 04:19:18.000000000 -0700
@@ -991,13 +991,12 @@ static int cpuset_create_dir(struct cpus
return error;
}

-/* MUST be called with dir->d_inode->i_sem held */
-
static int cpuset_add_file(struct dentry *dir, const struct cftype *cft)
{
struct dentry *dentry;
int error;

+ down(&dir->d_inode->i_sem);
dentry = cpuset_get_dentry(dir, cft->name);
if (!IS_ERR(dentry)) {
error = cpuset_create_file(dentry, 0644 | S_IFREG);
@@ -1006,6 +1005,7 @@ static int cpuset_add_file(struct dentry
dput(dentry);
} else
error = PTR_ERR(dentry);
+ up(&dir->d_inode->i_sem);
return error;
}

@@ -1197,7 +1197,6 @@ static struct cftype cft_notify_on_relea
.private = FILE_NOTIFY_ON_RELEASE,
};

-/* MUST be called with ->d_inode->i_sem held */
static int cpuset_populate_dir(struct dentry *cs_dentry)
{
int err;
@@ -1254,9 +1253,16 @@ static long cpuset_create(struct cpuset
err = cpuset_create_dir(cs, name, mode);
if (err < 0)
goto err;
+
+ /*
+ * Release cpuset_sem before cpuset_populate_dir() because it
+ * will down() this new directory's i_sem and if we race with
+ * another mkdir, we might deadlock.
+ */
+ up(&cpuset_sem);
+
err = cpuset_populate_dir(cs->dentry);
/* If err < 0, we have a half-filled directory - oh well ;) */
- up(&cpuset_sem);
return 0;
err:
list_del(&cs->sibling);

--
I won't rest till it's the best ...
Programmer, Linux Scalability
Paul Jackson <pj@xxxxxxx> 1.650.933.1373
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/