From 1ebdb5d96c3acb16a20821b694f551466913e986 Mon Sep 17 00:00:00 2001 From: immarvin Date: Wed, 26 Oct 2016 20:54:39 +0800 Subject: [PATCH] add lock in rh/genimage to avoid multiple genimage processes on same rootimg directory;add guard code before umount/remove mount points under rootimg directory --- perl-xCAT/xCAT/Utils.pm | 50 ++++++++++++++++++++-- xCAT-server/lib/xcat/plugins/packimage.pm | 13 +++++- xCAT-server/lib/xcat/plugins/rmimage.pm | 43 ++++++++++++++----- xCAT-server/share/xcat/netboot/rh/genimage | 40 ++++++++++++++--- 4 files changed, 125 insertions(+), 21 deletions(-) diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm index d158858f2..d28ea58ae 100644 --- a/perl-xCAT/xCAT/Utils.pm +++ b/perl-xCAT/xCAT/Utils.pm @@ -32,6 +32,7 @@ else { use IPC::Open3; use IO::Select; use xCAT::GlobalDef; +use Digest::MD5 qw(md5_hex); eval { require xCAT::RemoteShellExp; }; @@ -2394,19 +2395,21 @@ sub acquire_lock { use Fcntl ":flock"; my $tlock; $tlock->{path} = "/var/lock/xcat/" . $lock_name; - open($tlock->{fd}, ">", $tlock->{path}) or return undef; + sysopen($tlock->{fd}, $tlock->{path}, POSIX::O_CREAT | POSIX::O_WRONLY) or return undef; unless ($tlock->{fd}) { return undef; } - if ($nonblock_mode) { flock($tlock->{fd}, LOCK_EX | LOCK_NB) or return undef; } else { flock($tlock->{fd}, LOCK_EX) or return undef; } - print { $tlock->{fd} } $$; + + truncate $tlock->{fd},0; + syswrite $tlock->{fd} ,$$; $tlock->{fd}->autoflush(1); return $tlock; } + #--------------------- =head3 release_lock @@ -4781,4 +4784,45 @@ sub get_nmapversion { return $nmap_version; } + +#-------------------------------------------------------------------------------- + +=head3 acquire_lock_imageop + acquire lock for the image related operations on specific rootimg dir + the image related operation includes genimage,packimage,rmimage... + Arguments: + $rootimg_dir: the full path of osimage rootimage dir + lock mode: 0-block, 1-non-block + Returns: + a list with format (, or ) + + the : 0 on success, 1 on fail + the : available on fail + the : available on success +=cut + +#-------------------------------------------------------------------------------- + +sub acquire_lock_imageop { + my $self=shift; + my $rootimg_dir=shift; + my $NON_BLOCK=shift; + + $NON_BLOCK=1 unless(defined $NON_BLOCK); + my $mylockfile=Cwd::realpath($rootimg_dir); + my $mymd5=md5_hex($mylockfile); + $mylockfile=~s/\//./g; + $mylockfile=$mylockfile.".".$mymd5; + + my $lock = xCAT::Utils->acquire_lock("$mylockfile", $NON_BLOCK); + unless ($lock){ + my $pidfd; + open($pidfd,"<","/var/run/lock/xcat/$mylockfile"); + my $pid=<$pidfd>; + close($pidfd); + return (1, "failed to acquire lock, seems there is another genimage/packimage/rmimage process $pid running on root image dir \"$rootimg_dir\""); + } + return (0,$lock); +} + 1; diff --git a/xCAT-server/lib/xcat/plugins/packimage.pm b/xCAT-server/lib/xcat/plugins/packimage.pm index d5ab79c76..929f2d578 100755 --- a/xCAT-server/lib/xcat/plugins/packimage.pm +++ b/xCAT-server/lib/xcat/plugins/packimage.pm @@ -37,6 +37,8 @@ use File::Path; use xCAT::Utils; use xCAT::TableUtils; use xCAT::SvrUtils; +use Digest::MD5 qw(md5_hex); + Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); @@ -97,7 +99,8 @@ sub process_request { my $provmethod; my $help; my $version; - + my $lock; + GetOptions( "profile|p=s" => \$profile, "arch|a=s" => \$arch, @@ -199,6 +202,14 @@ sub process_request { } $rootimg_dir = "$destdir/rootimg"; + + my $retcode; + ($retcode,$lock)=xCAT::Utils->acquire_lock_imageop($rootimg_dir); + if($retcode){ + $callback->({ error => ["$lock"], errorcode => [1]}); + return 1; + } + my $distname = $osver; until (-r "$::XCATROOT/share/xcat/netboot/$distname/" or not $distname) { chop($distname); diff --git a/xCAT-server/lib/xcat/plugins/rmimage.pm b/xCAT-server/lib/xcat/plugins/rmimage.pm index 586fa785c..ad35bd605 100644 --- a/xCAT-server/lib/xcat/plugins/rmimage.pm +++ b/xCAT-server/lib/xcat/plugins/rmimage.pm @@ -10,9 +10,11 @@ BEGIN use lib "$::XCATROOT/lib/perl"; use Getopt::Long; use File::Path; +use Cwd qw(realpath); use xCAT::Utils; use xCAT::TableUtils; use xCAT::DBobjUtils; +use Digest::MD5 qw(md5_hex); Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); @@ -41,7 +43,8 @@ sub process_request { my $xcatdef; my $imagename; my $imagedir; - + my $lock; + if (!xCAT::Utils->isLinux()) { $callback->({ error => ["The rmimage command is only supported on Linux."], errorcode => [1] }); return; @@ -175,8 +178,17 @@ sub process_request { $callback->({ error => ["Image directory $imagedir does not exist"], errorcode => [1] }); return; } + - # Doing this extra check now because we now have a method and arch from either the node or the image name. + my $retcode; + ($retcode,$lock)=xCAT::Utils->acquire_lock_imageop("$imagedir/rootimg"); + if($retcode){ + $callback->({ error => ["$lock"], errorcode => [1]}); + return 1; + } + + + # Doing this extra check now because we now have a method and arch from either the node or the image namee if (($method eq "sysclone") && ($arch ne "s390x")) { # Only supporting removing sysclone images for s390x at this time. @@ -184,17 +196,28 @@ sub process_request { return; } - my @filestoremove = ("$imagedir/rootimg.gz", "$imagedir/kernel", "$imagedir/initrd-stateless.gz", "$imagedir/initrd-statelite.gz"); + my @filestoremove = ("$imagedir/kernel", "$imagedir/initrd-stateless.gz", "$imagedir/initrd-statelite.gz"); + my @rootimgtars=glob "$imagedir/rootimg.{tar,cpio}.{xz,gz}"; + push @filestoremove,@rootimgtars; + #unmount all the mount points under rootimg directory + #to avoid removing the directory/files on management node by mistake + $realimagedir=realpath("$imagedir/rootimg"); + my @mntptlist; + my $FILEHD=undef; + open($FILEHD,"<","/proc/mounts"); + while(<$FILEHD>){ + my @arr=split / /; + push @mntptlist,$arr[1] if(substr($arr[1],0,length($realimagedir)) eq $realimagedir); + } + close($FILEHD); + foreach my $mntpt (@mntptlist){ + system("umount -l $mntpt >/dev/null 2>&1") + } - #some rpms like atftp mount the rootimg/proc to /proc, we need to make sure rootimg/proc is free of junk - `umount -l $imagedir/rootimg/proc 2>&1 1>/dev/null`; - - # also umount the rootimg/sys - `umount -l $imagedir/rootimg/sys 2>&1 1>/dev/null`; # umount the rootimg/dev - my $devmount = `cat /proc/mounts |grep "$imagedir/rootimg/dev"`; - if ($devmount) { + my $devmount = system("findmnt $imagedir/rootimg/dev/ >/dev/null 2>&1"); + if (!$devmount) { xCAT::Utils->runcmd("umount -l $imagedir/rootimg/dev"); if ($?) { $callback->({ error => ["$imagedir/rootimg/dev mount on /dev, and can't umount. remove $imagename will lead to unpredictable result, please umount manualy before try again"], errorcode => [1] }); diff --git a/xCAT-server/share/xcat/netboot/rh/genimage b/xCAT-server/share/xcat/netboot/rh/genimage index ea50b4a6c..72c45871a 100755 --- a/xCAT-server/share/xcat/netboot/rh/genimage +++ b/xCAT-server/share/xcat/netboot/rh/genimage @@ -19,6 +19,8 @@ use File::Temp qw/mkdtemp/; use FindBin; use lib "$FindBin::Bin/../imgutils"; use imgutils; +use xCAT::Utils; +use Digest::MD5 qw(md5_hex); #use strict; Getopt::Long::Configure("bundling"); @@ -66,6 +68,8 @@ my $tempfile; my $prompt; my $ignorekernelchk; my $noupdate; +my $lock; + sub xdie { @@ -112,17 +116,30 @@ sub mount_chroot { sub umount_chroot { my $rootimage_dir = shift; - if ($rootimage_dir eq "") { + + $rootimage_dir=realpath($rootimage_dir); + if ($rootimage_dir eq "/") { print "\n\n\n\nWARNING: /proc and /sys may still be mounted in the rootimgdir\n\n\n\n"; return 1; } - + + #unmount all the mount points under rootimg directory + #to avoid removing the direcoty/files on managemment node by mistake + my @mntptlist; + my $FILEHD=undef; + open($FILEHD,"<","/proc/mounts"); + while(<$FILEHD>){ + my @arr=split / /; + push @mntptlist,$arr[1] if(substr($arr[1],0,length($rootimage_dir)) eq $rootimage_dir); + } + close($FILEHD); + foreach my $mntpt (@mntptlist){ + system("umount -l $mntpt >/dev/null 2>&1") + } + if (majversion($osver) > 6) { - system("umount -l $rootimage_dir/proc"); - system("umount -l $rootimage_dir/sys"); - - #system("umount -l $rootimage_dir/dev"); - system("rm -rf $rootimage_dir/dev/*"); + #only remove the /dev in rootimg directory if it is not a mount point + system("findmnt $rootimage_dir/dev/ >/dev/null 2>&1 || rm -rf $rootimage_dir/dev/*"); } } @@ -194,6 +211,7 @@ $srcdir_otherpkgs = "$installroot/post/otherpkgs/$osver/$arch" unless ($srcdir_o $destdir = "$installroot/netboot/$osver/$arch/$profile" unless ($destdir); $updates{'rootimgdir'} = $destdir if ($tempfile); + $rootimg_dir = "$destdir/rootimg"; $kerneldir = "$installroot/kernels" unless ($kerneldir); # the default directory for 3rd-party kernel is "$installroot/kernels"; @@ -348,6 +366,14 @@ unless ($onlyinitrd) { exit 1; } + my $retcode; + ($retcode,$lock)=xCAT::Utils->acquire_lock_imageop($rootimg_dir); + if($retcode){ + print "$lock"; + exit 1; + } + + mount_chroot($rootimg_dir); my %pkg_hash = imgutils::get_package_names($pkglist);