Req #35326 [Com]: Concurrency issue with recursive mkdir
| From: | me at vlastv dot ru | Date: | Mon, 30 Sep 2013 10:39:45 +0000 |
| Subject: | Req #35326 [Com]: Concurrency issue with recursive mkdir | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-181842@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=35326&edit=1
ID: 35326
Comment by: me at vlastv dot ru
Reported by: bugs dot php dot net at chsc dot dk
Summary: Concurrency issue with recursive mkdir
Status: Open
Type: Feature/Change Request
Package: Feature/Change Request
Operating System: Linux
PHP Version: 5.1.6
Block user comment: N
Private report: N
New Comment:
Problem still exists in PHP 5.4.1.
Previous Comments:
------------------------------------------------------------------------
[2013-07-23 22:55:07] gustavo dot straube at gmail dot com
Problem still exists in PHP 5.3.3.
------------------------------------------------------------------------
[2006-10-10 07:25:52] bugs dot php dot net at chsc dot dk
Problem still exists in PHP 5.1.6.
------------------------------------------------------------------------
[2005-11-22 13:52:24] bugs dot php dot net at chsc dot dk
Yes, it also occurs with the CVS snapshot (this time I tried with the CGI version).
AFAICS the problem is in php_plain_files_mkdir in main/streams/plain_wrapper.c. If php_mkdir() or
VCWD_MKDIR() returns false, the method gives up instead of checking whether directory exists anyway,
i.e. if it was created by another thread.
------------------------------------------------------------------------
[2005-11-22 12:13:10] tony2001@php.net
Please try using this CVS snapshot:
http://snaps.php.net/php5-latest.tar.gz
For Windows:
http://snaps.php.net/win32/php5-win32-latest.zip
------------------------------------------------------------------------
[2005-11-22 11:32:49] bugs dot php dot net at chsc dot dk
Description:
------------
There appears to be a concurrency issue when mkdir is called on two separate threads with the
following parameters:
Thread 1:
mkdir('/tmp/foo/bar/1', 0777, true);
Thread 2:
mkdir('/tmp/foo/bar/2', 0777, true);
Sometimes one of the threads (e.g. thread 2) two fails with "Warning: mkdir(): File
exists" and the directory /tmp/foo/bar/2 does not exist afterwards.
What I think is happening in thread 2 is is this:
PHP looks for /tmp/foo/bar/2 and sees that it does not exist. Neither does /tmp/foo/bar and
/tmp/foo. So it tries to create /tmp/foo, but that directory was just created a millisecond second
ago by another thread, so mkdir gives instead of just moving on to create /tmp/foo/bar and
/tmp/foo/bar/2.
Reproduce code:
---------------
This code reproduces the problem in about every second attempt. It consists of two files, index.php
and iframe.php.
index.php:
<?php
$fire = time() + 2;
?>
<h1>Nr. 1</h1>
<iframe src="iframe.php?fire=<?= $fire ?>&no=1"></iframe>
<h1>Nr. 2</h1>
<iframe src="iframe.php?fire=<?= $fire ?>&no=2"></iframe>
iframe.php:
<?php
$fire = $_GET['fire'];
$no = $_GET['no'];
// synchronize the two threads
while ($fire > time());
$dir = '/tmp/' . $fire . '/foo/bar/foo/bar/' . $no;
//sleep($no);
var_dump(is_dir($dir));
echo "Making $dir ";
mkdir($dir, 0777, true);
var_dump(is_dir($dir));
?>
Expected result:
----------------
Thread 2 should output this:
bool(false) Making /tmp/1132653651/foo/bar/foo/bar/2 bool(true)
Actual result:
--------------
Thread 2 sometimes outputs this:
bool(false) Making /tmp/1132655181/foo/bar/foo/bar/2 Warning: mkdir(): File exists in
/home/chsc/public_html/mkdir/iframe.php on line 10 bool(false)
Notice that the directory does not exist afterwards.
If I uncomment the sleep() call above, there are no problems.
A workaround:
$ok = mkdir($dir, 0777, true);
if (!$ok && !is_dir($dir)) {
sleep(1);
mkdir($dir, 0777, true);
}
In other words, it works if I try again. I hope that mkdir() can be changed so that it only returns
false if the directory cannot be created at all (e.g. because of lack of permissions or because it
already exists).
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=35326&edit=1