[stgt] [PATCH 1/2] tgt-admin: user/system check if the device is in use
Tomasz Chmielewski
mangoo at wpkg.org
Mon Oct 6 16:59:19 CEST 2008
Don't allow to allocate used devices (unless overridden).
Signed-off-by: Tomasz Chmielewski <mangoo at wpkg.org>
diff --git a/scripts/tgt-admin b/scripts/tgt-admin
index df81112..186d612 100755
--- a/scripts/tgt-admin
+++ b/scripts/tgt-admin
@@ -125,7 +125,7 @@ sub process_targets {
sub parse_configs {
# Parse the config
if ($alternate_conf ne 0) {
- # Check if alternative configuration file exist
+ # Check if alternative configuration file exists
if (-e "$alternate_conf") {
execute("# Using $alternate_conf as configuration file\n");
%conf = ParseConfig(-ConfigFile => "$alternate_conf", -UseApacheInclude => 1, -IncludeGlob => 1,);
@@ -219,7 +219,7 @@ sub add_targets {
check_value($value);
$target_options{$option} = $value;
$target_options_ref = \%target_options;
- $data_key = make_key("lun", $target_options_ref);
+ $data_key = make_key($target_options_ref, "lun", "allow-in-use");
}
if (not defined $target_options{"driver"}) {
@@ -262,17 +262,20 @@ sub add_targets {
# Pre-parse the config and get some values we need
sub make_key {
- my $action = $_[0];
- my $target_options_ref = $_[1];
+ my $target_options_ref = shift;
+ my @actions = @_;
my %data_key;
- if (ref $$target_options_ref{'backing-store'} eq "HASH") {
- foreach my $testlun (keys %{$$target_options_ref{'backing-store'}}) {
- $data_key{$testlun}{'lun'} = $$target_options_ref{'backing-store'}{$testlun}{$action};
+
+ foreach my $action (@actions) {
+ if (ref $$target_options_ref{'backing-store'} eq "HASH") {
+ foreach my $testlun (keys %{$$target_options_ref{'backing-store'}}) {
+ $data_key{$testlun}{$action} = $$target_options_ref{'backing-store'}{$testlun}{$action};
+ }
}
- }
- if (ref $$target_options_ref{'direct-store'} eq "HASH") {
- foreach my $testlun (keys %{$$target_options_ref{'direct-store'}}) {
- $data_key{$testlun}{'lun'} = $$target_options_ref{'direct-store'}{$testlun}{$action};
+ if (ref $$target_options_ref{'direct-store'} eq "HASH") {
+ foreach my $testlun (keys %{$$target_options_ref{'direct-store'}}) {
+ $data_key{$testlun}{$action} = $$target_options_ref{'direct-store'}{$testlun}{$action};
+ }
}
}
return \%data_key;
@@ -305,9 +308,15 @@ sub check_exe {
foreach my $path (@path) {
if ( -x "$path/$command" && -f "$path/$command" ) { $exists = 1 }
}
- if ( $exists == 0 ) {
- print "Command $command (needed by $option option in your config file) is not in your path - can't continue!\n";
- exit 1;
+ if ($exists == 0) {
+ if ($command eq "sg_inq") {
+ print "Command '$command' (needed by '$option') is not in your path - can't continue!\n";
+ exit 1;
+ } elsif ($command eq "lsof") {
+ execute("# Command '$command' is not in your path.");
+ execute("# Can't reliably check if device is not in use.");
+ return 1;
+ }
}
}
@@ -371,9 +380,12 @@ sub add_backing_direct {
my $driver = $$target_options_ref{"driver"};
# Is the device in use?
- (my $can_alloc, my $dev) = check_device($backing_store);
+ my $can_alloc = 1;
+ if ($force != 1 && $$target_options_ref{'allow-in-use'} ne "yes") {
+ $can_alloc = check_device($backing_store,$data_key_ref);
+ }
- if (-e $backing_store && $can_alloc == 1) {
+ if (-e $backing_store && ! -d $backing_store && $can_alloc == 1) {
my @exec_commands;
my $device_type;
my %luns;
@@ -517,7 +529,9 @@ sub add_backing_direct {
$lun += 1;
return $lun;
} elsif ($can_alloc == 0) {
- execute("# Skipping device $backing_store ($dev is mounted / in use)");
+ execute("# Skipping device $backing_store - it is in use.");
+ execute("# You can override it with --force or 'allow-in-use yes' config option.");
+ execute("# Note - do so only if you know what you're doing, you may damage your data.");
} else {
execute("# Skipping device: $backing_store");
execute("# $backing_store does not exist - please check the configuration file");
@@ -532,7 +546,7 @@ sub process_options {
if ($option eq "backing-store" || $option eq "direct-store") {
my $direct_store = 0;
if ($option eq "direct-store") {
- check_exe("sg_inq", "direct-store");
+ check_exe("sg_inq", "option direct-store");
$direct_store = 1;
}
@@ -632,7 +646,7 @@ sub dump_config {
my @all_targets = keys %tgtadm_output_tid;
- # If all targets use the same driver, us it only once in the config
+ # If all targets use the same driver, use it only once in the config
my $skip_driver = 0;
my @drivers_combined;
foreach my $current_target (@all_targets) {
@@ -1039,63 +1053,43 @@ sub check_connected {
}
# Check if a device can be allocated
-my @rootfs_dev;
+# Device can be used "by system" (i.e. mounted, used as swap, as a part of
+# a RAID array etc.) or "by user" - i.e., already by tgtd, or someone doing:
+# dd if=/dev/1st_device of=/dev/2nd_device
+# We shouldn't allow a device to be used more than one time, as it could
+# cause corruption when written several times. Unless the user really wants to.
sub check_device {
- my $tmp_dev = $_[0];
-
- # Check if force flag is set
- if ( $force == 0) {
- # Check for rootfs devices
- &find_rootfs_device();
- $tmp_dev =~ s/\d//g;
- # Check if device is on the same disk as rootfs
- if (grep {$_ eq $tmp_dev} @rootfs_dev) {
- return (0,$tmp_dev);
- }
- }
- return 1;
-}
-
-# finds all the devices that rootfs is mounted on
-sub find_rootfs_device {
- my @files=("/etc/mtab","/proc/mounts");
- my @lines;
- # read files
- foreach my $file (@files){
- if (open(FH,"$file")) {
- @lines=(@lines,<FH>);
- close (FH);
- }
- }
+ my $backing_store = $_[0];
+ my $data_key_ref = $_[1];
- # parse files and finds all the device which mounted on /
- foreach my $line (@lines){
- chomp $line;
- if (($line=~/^\/dev\//) && ($line=~/ \/ /)){
- my @ln=split(' ',$line);
- $ln[0]=~s/\d//g;
- push(@rootfs_dev,$ln[0]);
- }
+ # If allow-in-use is "yes", there is no need to do
+ # farther tests
+ if ($$data_key_ref{$backing_store}{'allow-in-use'} eq "yes") {
+ return 1;
}
- # read swap file
- my $swap_file="/proc/swap";
- if (open(FH,"$swap_file")) {
- @lines=<FH>;
- close (FH);
+ # Check if the system uses this device
+ use Fcntl qw(O_RDONLY O_EXCL);
+ use Errno;
+ sysopen(FH, $backing_store, O_RDONLY | O_EXCL);
+ if ($!{EBUSY}) {
+ execute("# Device $backing_store is used by the system (mounted, used by swap?).");
+ return 0;
}
- # parse swap file and finds all the swap devices
- foreach my $line (@lines){
- chomp $line;
- if ($line=~/^\/dev\//) {
- my @ln=split(' ',$line);
- $ln[0]=~s/\d//g;
- push(@rootfs_dev,$ln[0]);
+ close(FH);
+
+ # Check if userspace uses this device
+ my $lsof_check = check_exe("lsof");
+ if ($lsof_check ne 1) {
+ system("lsof $backing_store &>/dev/null");
+ my $exit_value = $? >> 8;
+ if ($exit_value eq 0) {
+ execute("# Device $backing_store is used (already tgtd target?).");
+ execute("# Run 'lsof $backing_store' to see the details.");
+ return 0;
}
}
- # remove duplicate entries from @rootfs_dev
- my %seen = ();
- @rootfs_dev = grep { ! $seen{ $_ }++ } @rootfs_dev;
+ return 1;
}
# Execute or just print (or both) everything we start or would start
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list