]> git.proxmox.com Git - pve-common.git/blobdiff - data/PVE/Tools.pm
implement shared file locks
[pve-common.git] / data / PVE / Tools.pm
index 27b4361f7f11c9a6d76d3a48b0a9a465bc86c074..235178a68cd68b4bebe08db263243905a46a48df 100644 (file)
@@ -1,7 +1,7 @@
 package PVE::Tools;
 
 use strict;
-use POSIX;
+use POSIX qw(EINTR);
 use IO::Socket::INET;
 use IO::Select;
 use File::Basename;
@@ -19,6 +19,7 @@ use String::ShellQuote;
 
 our @EXPORT_OK = qw(
 lock_file 
+lock_file_full
 run_command 
 file_set_contents 
 file_get_contents
@@ -79,20 +80,30 @@ sub run_with_timeout {
 
 my $lock_handles =  {};
 
-sub lock_file {
-    my ($filename, $timeout, $code, @param) = @_;
+sub lock_file_full {
+    my ($filename, $timeout, $shared, $code, @param) = @_;
 
     $timeout = 10 if !$timeout;
 
+    my $mode = $shared ? LOCK_SH : LOCK_EX;
+
     my $lock_func = sub {
         if (!$lock_handles->{$$}->{$filename}) {
             $lock_handles->{$$}->{$filename} = new IO::File (">>$filename") ||
                 die "can't open file - $!\n";
         }
 
-        if (!flock ($lock_handles->{$$}->{$filename}, LOCK_EX|LOCK_NB)) {
+        if (!flock ($lock_handles->{$$}->{$filename}, $mode|LOCK_NB)) {
             print STDERR "trying to aquire lock...";
-            if (!flock ($lock_handles->{$$}->{$filename}, LOCK_EX)) {
+           my $success;
+           while(1) {
+               $success = flock($lock_handles->{$$}->{$filename}, $mode);
+               # try again on EINTR (see bug #273)
+               if ($success || ($! != EINTR)) {
+                   last;
+               }
+           }
+            if (!$success) {
                 print STDERR " failed\n";
                 die "can't aquire lock - $!\n";
             }
@@ -127,6 +138,13 @@ sub lock_file {
     return $res;
 }
 
+
+sub lock_file {
+    my ($filename, $timeout, $code, @param) = @_;
+
+    return lock_file_full($filename, $timeout, 0, $code, @param);
+}
+
 sub file_set_contents {
     my ($filename, $data, $perm)  = @_;
 
@@ -228,6 +246,7 @@ sub run_command {
     my $logfunc;
     my $input;
     my $output;
+    my $afterfork;
 
     eval {
 
@@ -248,6 +267,8 @@ sub run_command {
                $errfunc = $param{$p};
            } elsif ($p eq 'logfunc') {
                $logfunc = $param{$p};
+           } elsif ($p eq 'afterfork') {
+               $afterfork = $param{$p};
            } else {
                die "got unknown parameter '$p' for run_command\n";
            }
@@ -308,6 +329,8 @@ sub run_command {
        local $SIG{ALRM} = sub { die "got timeout\n"; } if $timeout;
        $oldtimeout = alarm($timeout) if $timeout;
 
+       &$afterfork() if $afterfork;
+
        if (ref($writer)) {
            print $writer $input if defined $input;
            close $writer;
@@ -727,7 +750,7 @@ sub upid_read_status {
     my ($task, $filename) = upid_decode($upid);
     my $fh = IO::File->new($filename, "r");
     return "unable to open file - $!" if !$fh;
-    my $maxlen = 1024;
+    my $maxlen = 4096;
     sysseek($fh, -$maxlen, 2);
     my $readbuf = '';
     my $br = sysread($fh, $readbuf, $maxlen);