X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdclass%2Fobdcontrol;h=8bdfd02bb6324fd267c9a4c47a29b6d77f02ed95;hb=d2af72e46de8b349dc7356e2acdae375b257f6d0;hp=ab31b6447846309146a9d02ab46a2dab2961c1da;hpb=03e10888c589ef46adbb92e8eb9d47886e5a6271;p=fs%2Flustre-release.git diff --git a/lustre/obdclass/obdcontrol b/lustre/obdclass/obdcontrol index ab31b64..8bdfd02 100755 --- a/lustre/obdclass/obdcontrol +++ b/lustre/obdclass/obdcontrol @@ -21,10 +21,10 @@ BEGIN { require "asm/ioctl.ph" }; # p2ph generated invalid macros for ioctl stuff, so I override some of it here eval 'sub OBD_IOC_CREATE () { &_IOC(2, ord(\'f\'), 3, 4);}' unless defined(&OBD_IOC_CREATE); -eval 'sub OBD_IOC_SETUP_SUPER () { &_IOC(1, ord(\'f\'), 4, 4);}' unless - defined(&OBD_IOC_SETUP_SUPER); -eval 'sub OBD_IOC_CLEANUP_SUPER () { &_IOC(0, ord(\'f\'), 5, 0);}' unless - defined(&OBD_IOC_CLEANUP_SUPER); +eval 'sub OBD_IOC_SETUP () { &_IOC(1, ord(\'f\'), 4, 4);}' unless + defined(&OBD_IOC_SETUP); +eval 'sub OBD_IOC_CLEANUP () { &_IOC(0, ord(\'f\'), 5, 0);}' unless + defined(&OBD_IOC_CLEANUP); eval 'sub OBD_IOC_DESTROY () { &_IOC(1, ord(\'f\'), 6, 4);}' unless defined(&OBD_IOC_DESTROY); eval 'sub OBD_IOC_PREALLOCATE () { &_IOC(3, ord(\'f\'), 7, 4);}' unless @@ -47,6 +47,27 @@ eval 'sub OBD_IOC_STATFS () { &_IOC(3, ord(\'f\'), 15, 4);}' unless defined(&OBD_IOC_STATFS); eval 'sub OBD_IOC_SYNC () { &_IOC(2, ord(\'f\'), 16, 4);}' unless defined(&OBD_IOC_SYNC); +eval 'sub OBD_IOC_READ2 () { &_IOC(3, ord(\'f\'), 17, 4);}' unless + defined(&OBD_IOC_READ2); +eval 'sub OBD_IOC_FORMATOBD () { &_IOC(3, ord(\'f\'), 18, 4);}' unless + defined(&OBD_IOC_FORMATOBD); +eval 'sub OBD_IOC_PARTITION () { &_IOC(3, ord(\'f\'), 19, 4);}' unless + defined(&OBD_IOC_PARTITION); +eval 'sub OBD_IOC_ATTACH () { &_IOC(3, ord(\'f\'), 20, 4);}' unless + defined(&OBD_IOC_ATTACH); +eval 'sub OBD_IOC_DETACH () { &_IOC(3, ord(\'f\'), 21, 4);}' unless + defined(&OBD_IOC_DETACH); +eval 'sub OBD_IOC_COPY () { &_IOC(3, ord(\'f\'), 22, 4);}' unless + defined(&OBD_IOC_COPY); +eval 'sub OBD_IOC_MIGR () { &_IOC(3, ord(\'f\'), 23, 4);}' unless + defined(&OBD_IOC_MIGR); +eval 'sub OBD_SNAP_SETTABLE () { &_IOC(3, ord(\'f\'), 40, 4);}' unless + defined(&OBD_SNAP_SETTABLE); +eval 'sub OBD_SNAP_PRINTTABLE () { &_IOC(3, ord(\'f\'), 41, 4);}' unless + defined(&OBD_SNAP_PRINTTABLE); + +eval 'sub OBD_EXT2_RUNIT () { &_IOC(3, ord(\'f\'), 61, 4);}' unless + defined(&OBD_EXT2_RUNIT); eval 'sub ATTR_MODE () {1;}' unless defined(&ATTR_MODE); eval 'sub ATTR_UID () {2;}' unless defined(&ATTR_UID); @@ -63,37 +84,44 @@ use Carp; use Term::ReadLine; use IO::Handle; -my ($device, $filesystem); -# startup options (I'll replace these when I have some to replace with) -GetOptions("device=s" => \$device, "fs=s" => $filesystem) || die "Getoptions"; -# genuine new simulated OBD device -$device = "/dev/obd" unless $device; -# object store in the ext2 formatted block device -$filesystem = "/dev/loop0" unless $filesystem; +my ($file); + +GetOptions("f!" => \$file, "device=s" => \$::device, "fs=s" => $::filesystem) || die "Getoptions"; -# get a console for the app -my $term = new Term::ReadLine 'obdcontrol '; -my $attribs = $term->Attribs; -$term->ornaments('md,me,,'); # bold face prompt -# make sure stdout is not buffered -STDOUT->autoflush(1); +# get a console for the app my $line; my $command; my $arg; my %commands = - ('create' => {func => "Create", doc => "create: creates a new inode"}, + ('device' => {func => "Device", doc => "device : open another OBD device"}, + 'filesystem' => {func => "Filesystem", doc => "filesystem : partition for direct OBD device"}, + 'create' => {func => "Create", doc => "create: creates a new inode"}, + 'attach' => {func => "Attach", doc => "attach type [adapter bus tid lun]"}, + 'detach' => {func => "Detach", doc => "detach this device"}, + 'snapattach' => {func => "SnapAttach", doc => "snapattach snapno table"}, + 'snapset' => {func => "SnapSetTable", doc => "snapset tableno file" }, + 'snapprint' => {func => "SnapPrint", doc => "snapprint tableno"}, + + 'testiterator' => {func => "TestIterator", doc => ""}, + + 'snaptable' => {func => "SnapShotTable", doc => "snaptable: build a snapshot table (interactive)"}, + 'copy' => {func => "Copy", doc => "copy srcid tgtid"}, + 'migrate' => {func => "Migrate", doc => "migrate srcid tgtid"}, + 'format' => {func => "Format", doc => "format type adapter bus tid lun size"}, + 'partition' => {func => "Partition", doc => "partition type adapter bus tid lun partition size"}, 'setup' => {func => "Setup", doc => "setup: link the ext2 partition (default /dev/loop0) to this obddev"}, 'connect' => {func => "Connect", doc => "connect: allocates client ID for this session"}, 'disconnect' => {func => "Disconnect", doc => "disconnect [id]: frees client resources"}, 'sync' => {func => "Sync", doc => "sync: flushes buffers to disk"}, 'destroy' => {func => "Destroy", doc => "setup: destroys an inode"}, - 'cleanup' => {func => "Cleanup", doc => "detach the superblock from this minor obd dev"}, + 'cleanup' => {func => "Cleanup", doc => "cleanup the minor obd device"}, 'dec_use_count' => {func => "Decusecount", doc => "decreases the module use count so that the module can be removed following an oops"}, 'read' => {func => "Read", doc => "read [offset]"}, + 'fsread' => {func => "Read2", doc => "read [offset]"}, 'write' => {func => "Write", doc => "write "}, 'setattr' => {func => "Setattr", doc => "setattr [mode [uid [gid [size [atime [mtime [ctime]]]]]]]"}, 'getattr' => {func => "Getattr", doc => "getattr : displays inode object attributes"}, @@ -109,17 +137,45 @@ my %commands = # my @jcm_cmd_list = keys %commands; -$attribs->{attempted_completion_function} = \&completeme; -#------------------------------------------------------------------------------ -# Open the device, as we need an FD for the ioctl -sysopen(DEV_OBD, $device, 0) || die "Cannot open $device"; +my $term, $attribs; -if (!defined($::st = stat($filesystem))) { - die "Unable to stat $filesystem.\n"; + +# Get going.... + +Device($::device); +Filesystem($::filesystem); + +sub readl { + if ( $file ) { + my $str = ; + chop($str); + return $str; + } else { + return $term->readline(@_); + } } -# Get on with the show -process_line(); + + +if ( $file ) { + while ( ) { + print $_; + execute_line($_); + } + exit 0; +} else { + $term = new Term::ReadLine 'obdcontrol '; + $attribs = $term->Attribs; + $attribs->{attempted_completion_function} = \&completeme; + $term->ornaments('md,me,,'); # bold face prompt + + # make sure stdout is not buffered + STDOUT->autoflush(1); + + + # Get on with the show + process_line(); +} #------------------------------------------------------------------------------ sub completeme { @@ -156,7 +212,12 @@ sub execute_line { my @arg = split(' ', $line); my $word = shift @arg; - my $cmd = find_command($word); + my $cmd; + if ( $file ) { + $cmd = $word; + } else { + $cmd = find_command($word); + } unless ($cmd) { printf STDERR "$word: No such command, or not unique.\n"; return (-1); @@ -170,11 +231,401 @@ sub execute_line { return (&{$commands{$cmd}->{func}}(@arg)); } +# set the object store in the ext2 formatted block device +sub Filesystem { + my $filesystem = shift; + $filesystem = "/dev/loop0" unless $filesystem; + + $::filesystem = $filesystem; + if (!defined($::st = stat($filesystem))) { + die "Unable to stat $filesystem.\n"; + } +} + +# select the OBD device we talk to +sub Device { + my $device = shift; + + if (! $device ) { + $device = "/dev/obd0"; + } + $::device = $device; + # Open the device, as we need an FD for the ioctl + sysopen(DEV_OBD, $device, 0) || die "Cannot open $device"; + print "Device now $device\n"; +} + + + +sub Attach { + my $err = 0; + my $type = shift; + my $data; + my $datalen = 0; + + if ($type eq "obdscsi" ) { + my $adapter = shift; + my $bus = shift; + my $tid = shift; + my $lun = shift; + $data = pack("iiiii", $adapter, $bus, $tid, $lun, $size); + $datalen = 4 * 4; + } + + my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data); + + my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + +sub Detach { + my $err = 0; + my $data = ""; + my $rc = ioctl(DEV_OBD, &OBD_IOC_DETACH, $data); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + + + +sub TestIterator { + my $err = 0; + my $type = "ext2_obd"; + + $data = pack("i", 4711); + $datalen = 4; + + my $len = length($type); + my $cl = length($data); + my $add = pack("p", $data); + print "type $type (len $len), datalen $datalen ($cl)\n"; + my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data); + + my $rc = ioctl(DEV_OBD, &OBD_EXT2_RUNIT, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + +sub SnapPrint { + my $err = 0; + my $type = "snap_obd"; + my $snaptableno = shift; + + $data = pack("i", $snaptableno); + $datalen = 4; + + my $len = length($type); + my $cl = length($data); + my $add = pack("p", $data); + print "type $type (len $len), datalen $datalen ($cl)\n"; + my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data); + + my $rc = ioctl(DEV_OBD, &OBD_SNAP_PRINTTABLE, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + +sub SnapSetTable { + my $err = 0; + my $type = "snap_obd"; + my $snaptableno = shift; + my $file = shift; + my $snapcount; + my $table = {}; + my $data; + my $datalen = 0; + + if ( ! -f $file ) { + print "No such file $file\n"; + } + + $table = ReadSnapShotTable($file); + + $snapcount = keys %{$table}; + print "Snapcount $snapcount\n"; + + if ( ! defined $table->{0} ) { + print "No current snapshot in table! First make one\n"; + return ; + } + $data = pack("ii", $snaptableno, $snapcount); + $datalen = 2 * 4; + foreach my $time (sort keys %{$table}) { + $data .= pack("Ii", $time, $table->{$time}); + $datalen += 8; + } + + my $len = length($type); + my $cl = length($data); + my $add = pack("p", $data); + print "type $type (len $len), datalen $datalen ($cl)\n"; + my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data); + + my $rc = ioctl(DEV_OBD, &OBD_SNAP_SETTABLE, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + + +sub SnapAttach { + my $err = 0; + my $type = "snap_obd"; + my $snapdev = shift; + my $snapno = shift; + my $tableno = shift; + my $snapcount; + my $data; + my $datalen = 0; + +# if ( ! -f $file ) { +# print "No such file $file\n"; +# } + +# $table = ReadSnapShotTable($file); + $data = pack("iii", $snapdev, $snapno, $tableno); + $datalen = 3 * 4; + + my $len = length($type); + my $cl = length($data); + my $add = pack("p", $data); + print "type $type (len $len), datalen $datalen ($cl)\n"; + my $packed = pack("Lipip", $::client_id, length($type), $type, $datalen, $data); + + my $rc = ioctl(DEV_OBD, &OBD_IOC_ATTACH, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + + +sub SnapShotTable { + + my $file = &readl("enter file name: "); + if ( ! -f $file ) { + `touch $file`; + } + my $table = ReadSnapShotTable($file); + + again: + PrintSnapShotTable($table); + my $action = &readl("Add, Delete or Quit [adq]: "); + goto done if ($action =~ "^q.*" ); + goto add if ($action =~ "^a.*"); + goto del if ($action =~ "^d.*"); + goto again; + + add: + my $idx = &readl("enter index where you want this snapshot: "); + my $time = &readl("enter time or 'now' or 'current': "); + my $oldtime = SnapFindTimeFromIdx($idx, $table); + if (defined $oldtime) { + print "This already exists, first clean up\n"; + goto again; + } + + if ( $time eq 'now' ) { + $time = time; + } elsif ( $time eq 'current' ) { + $time = 0; + } + $table->{$time} = $idx; + goto again; + + del: + $didx = &readl("Enter index to delete: "); + my $deltime = SnapFindTimeFromIdx($didx, $table); + delete $table->{$deltime} if defined $deltime; + goto again; + + done: + my $ok = &readl("OK with new table? [Yn]: "); + unless ( $ok eq "no" ) { + WriteSnapShotTable($file, $table); + } +} + +sub SnapFindTimeFromIdx { + my $idx = shift; + my $table = shift; + + foreach my $time ( keys %{$table} ) { + if ( $table->{$time} == $idx ) { + return $time; + } + } + undef; +} + +sub PrintSnapShotTable { + my $table = shift; + my $time; + + foreach $time ( sort keys %{$table} ) { + my $stime = localtime($time); + if ( ! $time ) { + $stime = "current"; + } + printf "Time: %s -- Index %d\n", $stime, $table->{$time}; + } +} + +sub ReadSnapShotTable { + + my $file = shift; + my $table = {}; + + open FH, "<$file"; + while ( ) { + my ($time, $index) = split ; + $table->{$time} = $index; + } + close FH; + + PrintSnapShotTable($table); + + return $table; +} + +sub WriteSnapShotTable { + my $file = shift; + my $table = shift; + + open FH, ">$file"; + foreach my $time ( sort keys %{$table} ) { + print FH "$time $table->{$time}\n"; + } + close FH; +} + +sub Copy { + my $err = 0; + my $srcid = shift; + my $tgtid = shift; + my $data = pack("III", $::client_id, $srcid, $tgtid); + my $datalen = 12; + + my $packed = pack("ip", $datalen, $data); + my $rc = ioctl(DEV_OBD, &OBD_IOC_COPY, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + +sub Migrate { + my $err = 0; + my $srcid = shift; + my $tgtid = shift; + my $data = pack("III", $::client_id, $srcid, $tgtid); + my $datalen = 12; + + my $packed = pack("ip", $datalen, $data); + my $rc = ioctl(DEV_OBD, &OBD_IOC_MIGR, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + + +sub Format { + my $err = 0; + my $size = shift; + my $data = pack("i", $size); + my $datalen = 4; + + my $packed = pack("ip", $datalen, $data); + my $rc = ioctl(DEV_OBD, &OBD_IOC_FORMATOBD, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + +sub Partition { + my $err = 0; + my $partno = shift; + my $size = shift; + my $data = pack("ii", $partno, $size); + my $datalen = 2 * 4; + + my $packed = pack("ip", $datalen, $data); + my $rc = ioctl(DEV_OBD, &OBD_IOC_PARTITION, $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + print "Finished (success)\n"; + } else { + print "ioctl returned error code $rc.\n"; + } +} + sub Setup { my $err = 0; + my $type = shift; + my $data; + my $datalen = 0; - my $packed = pack("La24", $::st->rdev(), "sim_obd"); - my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP_SUPER, $packed); + $type = "ext2_obd" unless $type; + + if ( $type eq "ext2_obd" ) { + my $dev = shift; + $dev = $::st->rdev() unless $dev; + $data = pack("i", $dev); + $datalen = 4; + } + + my $packed = pack("ip", $datalen, $data); + my $rc = ioctl(DEV_OBD, &OBD_IOC_SETUP, $packed); if (!defined $rc) { print STDERR "ioctl failed: $!\n"; @@ -187,12 +638,13 @@ sub Setup { sub Cleanup { my $err = "0"; - my $rc = ioctl(DEV_OBD, &OBD_IOC_CLEANUP_SUPER, $err); + my $rc = ioctl(DEV_OBD, &OBD_IOC_CLEANUP, $err); if (!defined $rc) { print STDERR "ioctl failed: $!\n"; } elsif ($rc eq "0 but true") { print "Finished (success)\n"; + $::client_id = 0; } else { print "ioctl returned error code $rc.\n"; } @@ -200,29 +652,17 @@ sub Cleanup { sub Connect { - my $id = 0; - my $ino = 0; - my $bs = 0; - my $bs_b = 0; my $rc; - # unsigned int conn_id; - # unsigned long conn_ino; - # unsigned long conn_blocksize; - # unsigned char conn_blocksize_bits; - - my $packed = pack("ILLC", $id, $ino, $bs, $bs_b); + my $packed = ""; $rc = ioctl(DEV_OBD, &OBD_IOC_CONNECT, $packed); - ($id, $ino, $bs, $bs_b) = unpack("ILLC", $packed); + $id = unpack("I", $packed); if (!defined $rc) { print STDERR "ioctl failed: $!\n"; } elsif ($rc eq "0 but true") { $::client_id = $id; print "Client ID : $id\n"; - print "Root inode : $ino\n"; - print "Blocksize : $bs\n"; - print "Blocksize bits: $bs_b\n"; print "Finished (success)\n"; } else { print "ioctl returned error code $rc.\n"; @@ -260,16 +700,16 @@ sub Create { my $arg = shift; my $quiet = shift; my $rc; + my $prealloc = 0; if (defined($quiet) && !($quiet eq "quiet")) { print "syntax: create [number of objects [quiet]]\n"; return; } - my $packed = pack("I", $::client_id); + my $packed = pack("IL", $::client_id, $prealloc); if (!defined($arg) || scalar($arg) < 2) { print "Creating 1 object...\n"; - my $packed = pack("I", 0); $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed); if (!defined($quiet)) { my $ino = unpack("L", $packed); @@ -282,9 +722,11 @@ sub Create { for ($i = 0; $i < scalar($arg); $i++) { $rc = ioctl(DEV_OBD, &OBD_IOC_CREATE, $packed); my $ino = unpack("L", $packed); - if (!($rc eq "0 but true") || $packed == 0) { + if (!($rc eq "0 but true")) { last; + $packed = pack("IL", $::client_id, $prealloc); } elsif (!defined($quiet)) { + $packed = pack("IL", $::client_id, $prealloc); print "Created object #$ino.\n"; } } @@ -494,6 +936,55 @@ sub Read { } } +sub Read2 { + if (!defined($::client_id)) { + print "You must first ``connect''.\n"; + return; + } + + my $inode = shift; + my $count = shift; + my $offset = shift; + + if (!defined($inode) || scalar($inode) < 1 || !defined($count) || + $count < 1 || (defined($offset) && $offset < 0)) { + print "invalid arguments; type \"help read\" for a synopsis\n"; + return; + } + + if (!defined($offset)) { + $offset = 0; + } + + print("Reading $count bytes starting at byte $offset from object " . + "$inode...\n"); + + # "allocate" a large enough buffer + my $buf = sprintf("%${count}s", " "); + die "suck" if (length($buf) != $count); + + # the perl we're using doesn't support pack type Q, and offset is 64 bits + my $packed = pack("ILpLLL", $::client_id, $inode, $buf, $count, $offset, 0); + + my $rc = ioctl(DEV_OBD, &OBD_IOC_READ2, $packed); + + $retval = unpack("l", $packed); + + if (!defined $rc) { + print STDERR "ioctl failed: $!\n"; + } elsif ($rc eq "0 but true") { + if ($retval >= 0) { + print substr($buf, 0, $retval); + print "\nRead $retval of an attempted $count bytes.\n"; + print "Finished (success)\n"; + } else { + print "Finished (error $retval)\n"; + } + } else { + print "ioctl returned error code $rc.\n"; + } +} + sub Write { if (!defined($::client_id)) { print "You must first ``connect''.\n";