Edit report at http://bugs.php.net/bug.php?id=53076&edit=1
ID: 53076
Updated by: cataphract@php.net
Reported by: admin at saltwaterc dot net
Summary: file_put_contents doesn't release the LOCK_EX
Status: Feedback
Type: Bug
Package: Scripting Engine problem
Operating System: Irrelevant
PHP Version: 5.3.3
Block user comment: N
New Comment:
I don't get an explicit LOCK_UN either, but it should be unnecessary, as
locks are released when the file is closed.
@crrodriguez
There's no need to call php_stream_flush as that is already done when
the stream is closed. See:
http://lxr.php.net/xref/PHP_TRUNK/main/streams/streams.c#_php_stream_free
Previous Comments:
------------------------------------------------------------------------
[2010-10-16 02:20:24] crrodriguez at opensuse dot org
Patch ACK'ed , looks correct.
BUT, you should also call php_stream_flush before closing the stream..
to make it
slightly more reliable though there is still no warranty that the file
is stored
on the filesystem...
article worth reading
http://thunk.org/tytso/blog/2009/03/12/delayed-allocation-
and-the-zero-length-file-problem/ ;)
------------------------------------------------------------------------
[2010-10-16 02:12:58] rasmus@php.net
Note the example code does an explicit unlock. Are you sure that isn't
what you
are seeing there?
If you try: strace php -r 'file_put_contents('foo', 'bar', LOCK_EX);'
Do you see an unlock still?
I get:
open("/home/rasmus/foo", O_WRONLY|O_CREAT, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
flock(3, LOCK_EX) = 0
ftruncate(3, 0) = 0
write(3, "bar", 3) = 3
close(3) = 0
------------------------------------------------------------------------
[2010-10-16 02:05:13] cataphract@php.net
I can't reproduce this. I get the output "bar".
File locks are released when the file are closed. Additionally, your
'actual result' section shows an unlock:
...
write(3, "bar", 3) = 3
flock(3, LOCK_UN) = 0 <<<<<---
Am I missing something?
------------------------------------------------------------------------
[2010-10-15 17:16:19] admin at saltwaterc dot net
Test script:
---------------
<?php
file_put_contents('foo', 'bar', LOCK_EX);
$fh = fopen('foo', 'rb'); // there, I messed up the first time
flock($fh, LOCK_SH);
$file_contents = stream_get_contents($fh);
flock($fh, LOCK_UN);
fclose($fh);
echo $file_contents.PHP_EOL;
------------------------------------------------------------------------
[2010-10-15 17:12:59] admin at saltwaterc dot net
Description:
------------
The name is pretty self explanatory. When the file_put_content function
is used along with the LOCK_EX flag, the file descriptor / file handle
doesn't get unlocked. Most of the time this won't be an issue, but
depending on the underlying file system, it could lead to severe
application crash. Such example is the GlusterFS version packaged for
the Ubuntu 10.04 which would block the PHP process in uninterruptible
sleep. I know that most of the time this situation won't affect real
life scenarios, but it already took down a virtual host from our
production cluster, based onto the above setup.
Test script:
---------------
<?php
file_put_contents('foo', 'bar', LOCK_EX);
$fh = fopen($file, 'rb');
flock($fh, LOCK_SH);
$file_contents = stream_get_contents($fh);
flock($fh, LOCK_UN);
fclose($fh);
echo $file_contents.PHP_EOL;
Expected result:
----------------
output: bar
strace:
getcwd("/media/glusterfs01/gluster-bug", 4096) = 31
lstat("/media/glusterfs01/gluster-bug/foo", {st_mode=S_IFREG|0644,
st_size=3, ...}) = 0
open("/media/glusterfs01/gluster-bug/foo", O_WRONLY|O_CREAT, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
flock(3, LOCK_EX) = 0
ftruncate(3, 0) = 0
write(3, "bar", 3) = 3
flock(3, LOCK_UN) = 0
close(3) = 0
getcwd("/media/glusterfs01/gluster-bug", 4096) = 31
open("/media/glusterfs01/gluster-bug/foo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
flock(3, LOCK_SH) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=3, ...}) = 0
read(3, "bar", 8192) = 3
read(3, "", 8192) = 0
read(3, "", 8192) = 0
flock(3, LOCK_UN) = 0
close(3) = 0
Actual result:
--------------
output: none
strace:
getcwd("/media/glusterfs01/gluster-bug", 4096) = 31
lstat("/media/glusterfs01/gluster-bug/foo", {st_mode=S_IFREG|0644,
st_size=3, ...}) = 0
open("/media/glusterfs01/gluster-bug/foo", O_WRONLY|O_CREAT, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
flock(3, LOCK_EX) = 0
ftruncate(3, 0) = 0
write(3, "bar", 3) = 3
flock(3, LOCK_UN) = 0
close(3) = 0
getcwd("/media/glusterfs01/gluster-bug", 4096) = 31
open("/media/glusterfs01/gluster-bug/foo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
flock(3, LOCK_SH
And then it blocks here ...
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/bug.php?id=53076&edit=1