Ru-Board.club
← Вернуться в раздел «UNIX»

» добавление диска в GEOM RAID 5

Автор: gryu
Дата сообщения: 17.12.2009 17:26
Собственно интересует возможно ли это и как это сделать. Желательно подробно.
ОС FreeNAS на базе FreeBSD 7.2 (порезанное ядро) http://freenas.org/doku.php
Автор: AnDySs1
Дата сообщения: 18.12.2009 07:14
gryu
Что Вы вкладываете в понятие
Цитата:

добавление диска в GEOM RAID 5

изменение структуры? размера? восстановление ?
общие словеса -
http://freenas.org/documentation:setup_and_user_guide:software_raid
Автор: gryu
Дата сообщения: 18.12.2009 11:33
AnDySs1
Добавленение, это не замена.
В данном случае я имею ввиду
Был райд из 4-х дисков. Хочу добавить пятый, для увеличения пространства.
Автор: AnDySs1
Дата сообщения: 18.12.2009 18:30
gryu
что-то типа http://palm.opennet.ru/tips/info/1992.shtml?skip=55
Автор: gryu
Дата сообщения: 18.12.2009 23:21
AnDySs1
Аха... пробежал глазками по тексту. На первый взгляд, очень похоже на то, что искал.
Спасибо.

Добавлено:
http://www.fluffles.net в дауне. Толи временно, толи совсем.
Автор: AnDySs1
Дата сообщения: 19.12.2009 07:17
gryu

Цитата:
Толи временно, толи совсем.

ну скрипт в cache google ещё присутствует
[more=graid5-expand]

#!/usr/local/bin/php

<?php

/**

*** GEOM RAID 5 (graid5)

*** Offline Capacity Expansion script

*** purpose: adding disks to an existing graid5-volume while preserving all data on the volume

***

*** script is copyright (C) 2007-2008, Fluffles.net (http://www.fluffles.net)

*** graid5 is copyright (C) 2006-2007, Arne Woerner (arne_woerner@yahoo.com)

***

*** This script is licensed to you under the BSD license

*** If you benefit from this script or have questions please email the author at

*** info@fluffles.net

**/

/**

*** ATTENTION:

*** o this script is still beta quality, needs testing!

*** o will not work with older versions of geom_raid5

*** o you will need sources in /usr/src

*** o will not work on FreeBSD 7.x, needs 6.x

**/

/**

*** Tunables: feel free to change these

*** tmp_dir is the temporary directory, it needs to be writable and have 1MB free space or so

*** debug will not actually perform dangerous commands, it will only display the commands to be executed.

*** stepbystep is also used for debugging purposes, it will pause after each step

*** verbose will display the commands as they are executed

**/

// temporary directory - should be writable!

$tmp_dir = '/tmp/';

// transfer x MiB's per second, do not set higher than 50% of memory size!

$datamapping_chunksize = 100*1024*1024; // 100MiB

// debugging options or verbose output

$debug = false;

$debug_calc = false;

$stepbystep = false;

$verbose = false;

// Calculator to use

// Either set to "auto" for autoselection or specify explicitly:

// "internal" - use internal PHP calculator (default for amd64 arch)

// "calc" - use external calc calculator (default for i386 arch)

// "bc" - unsupported

$calculator = 'auto';


/**

*** Initialization

*** WARNING: You are adviced not to change any of these unless you know what you are doing.

**/

$version = 3;

$version_date = 20080720;

$nl = chr(10);

$path_graid5_module = '/boot/kernel/geom_raid5.ko';

$path_graid5_lib = '/lib/geom/geom_raid5.so';

$default_sector_size = 512;

$math_scale_range = 0;

$minimum_date = mktime(0,0,0,02,18,2007); /* format: MM,DD,YYYY */

$min_free_space = 1024 * 1024;

$min_bsd_version = 6.0;

$max_bsd_version = 6.3;

$required_executables = array(

'/sbin/graid5',

'/sbin/kldstat',

'/sbin/gnop',

'/bin/dd',

'/sbin/mount',

'/sbin/sysctl',

'/usr/sbin/diskinfo');

$required_files = array(

'/boot/kernel/geom_raid5.ko',

'/boot/kernel/geom_nop.ko');


/**

*** Write banner

**/

echo($nl.'**'.$nl);

echo('*** GEOM RAID5 - Offline Capacity Expansion, version '.$version.' ('.$version_date.')'.$nl);

echo('***'.$nl);

echo('*** This script is: copyright (C) 2007-2008, Fluffles.net'.$nl);

echo('*** geom_raid5 is: copyright (C) 2006-2007, Arne Woerner'.$nl);

echo('*** License of this script: BSD'.$nl);

echo('*** For questions or help with expansion, please email to info@fluffles.net'.$nl);

echo('**'.$nl);

/**

*** Validate input

**/

// parse the command line variables

$graid5_volume = $argv[1];

$disks_to_be_added = array();

for ($i = 2; $i < 99; $i++)

if (strlen($argv[$i]) > 0)

{

$disks_to_be_added[] = $argv[$i];

$devpath = '/dev/'.$argv[$i];

if (!file_exists($devpath))

error('Could not find device "'.$devpath.'"');

if (!is_writable($devpath))

error('Could not open device "'.$devpath.'" for writing - maybe it is in use?');

}

// validate user input

if (!$graid5_volume)

usage();

if (!$disks_to_be_added)

usage();

/**

*** CHECK FREEBSD VERSION

**/

$bsdversion = trim(getcommand('sysctl -n kern.osrelease'));

echo($nl.'** Detected FreeBSD version '.$bsdversion.$nl);

$bsdversion_int = (int)substr($bsdversion,0,3);

if (($bsdversion_int < $min_bsd_version) OR ($bsdversion_int > $max_bsd_version))

error('You must be using FreeBSD version '.$min_bsd_version.' - '.$max_bsd_version.$nl);

echo('Your version of FreeBSD is supported!'.$nl);

// check system architecture too

$arch = trim(getcommand('sysctl -n hw.machine_arch'));

echo('** Detected architecture '.$arch.$nl);

if ($calculator == 'auto')

{

if ($arch == 'i386')

$calculator = 'calc';

elseif ($arch == 'amd64')

$calculator = 'internal';

else

error('Incompatible architecture: '.$arch.$nl);

echo('Using calculator '.$calculator.' based on automatic selection.'.$nl);

}

else

echo('Using explicitly defined calculator: '.$calculator.$nl);




/**

*** SANITY CHECKS

**/

if (!is_writable($tmp_dir))

error('Temporary directory "'.$tmp_dir.'" is not writable!');

if (disk_free_space($tmp_dir) < $min_free_space)

error('Temporary directory "'.$tmp_dir.'" has fewer than '.$min_free_space.' bytes of free disk space!');

// now check for all necessary external executables

echo($nl.'** Checking for required external executables'.$nl);

$missing_executables = array();

foreach ($required_executables as $exec)

{

if (!is_executable($exec))

$missing_executables[] = $exec;

}

if (count($missing_executables) > 0)

error('Your are missing executables: '.$nl.implode($nl,$missing_executables));

foreach ($required_executables as $exec)

echo('Found: '.$exec.$nl);

// now check for all necessary external files (non-executable)

echo($nl.'** Checking for required external files'.$nl);

$missing_files = array();

foreach ($required_files as $rfile)

{

if (!is_readable($rfile))

$missing_files[] = $rfile;

}

if (count($missing_files) > 0)

error('Your are missing files: '.$nl.implode($nl,$missing_files));

foreach ($required_files as $rfile)

echo('Found: '.$rfile.$nl);

echo($nl);

// now load the geom_nop kernel module

$cmd = getcommand('kldstat');

if (strpos($cmd,'geom_nop.ko') === false)

{

// geom_nop.ko unloaded; load the module

$cmd = getcommand('gnop load');

// check again if module is loaded

$cmd = getcommand('kldstat');

if (strpos($cmd,'geom_nop.ko') === false)

error('unable to load geom_nop.ko kernel module');

}

echo('** GNOP kernel module is activated'.$nl);

// make sure no GNOP devices exist yet

$cmd = getcommand('gnop status');

if ((strlen($cmd) > 0) OR (!is_string($cmd)))

error('it seems there are GNOP devices active, please make sure all GNOP devices are deactivated before expanding');

echo('** GNOP device list is clean'.$nl.$nl.$nl);


// make sure we use an up-to-date version of graid5

// because if we're using an older version, we will have total dataloss!

if (!file_exists($path_graid5_module))

error('Module "'.$path_graid5_module.'" not found!');

if (!file_exists($path_graid5_lib))

error('Library "'.$path_graid5_lib.'" not found!');

$mtime_module = filemtime($path_graid5_module);

$mtime_lib = filemtime($path_graid5_lib);

if ($mininum_date > $mtime_module)

error('Module "'.$path_graid5_module.'" is too old! Please update graid5 to >= 18-feb-2007');

if ($mininum_date > $mtime_lib)

error('Library "'.$path_graid5_lib.'" is too old! Please update graid5 to >= 18-feb-2007');

echo('** WARNING!'.$nl);

echo('It is absolutely imperative you are using an up-to-date version of geom_raid5. Please check the data below:'.$nl.$nl);

echo('Minimum date: '.date('d F Y',$minimum_date).$nl);

echo('Kernel module date: '.date('d F Y',$mtime_module).$nl);

echo('Library date: '.date('d F Y',$mtime_lib).$nl.$nl);

echo('Are you confident you are using the up-to-date version? (Y/N) ');

$line = trim(fgets(STDIN));

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

echo($nl.$nl);

// check if graid5 module is active

$cmd = getcommand('kldstat');

if (strpos($cmd,'geom_raid5.ko') === false)

error('graid5 module seems to be unloaded; please load it first');

// check if no rebuild is in progress

$cmd = getcommand('graid5 status '.$graid5_volume);

if (strpos($cmd,'REBUILDING') !== false)

error('there is a rebuild in progress; please finish the rebuild before running this script!');

// check if no FAILED/CRITICAL raid5 devices

$cmd = getcommand('graid5 status '.$graid5_volume);

if ((strpos($cmd,'FAILED') !== false) OR (strpos($cmd,'DEGRADED') !== false) OR (strpos($cmd,'CRITICAL') !== false))

error('some graid5 devices are in state FAILED, DEGRADED or CRITICAL. Expansion denied!');

// check if volume name exists

if (strpos($cmd,'raid5/'.$graid5_volume) === false)

error('there is no graid5 volume called "'.$graid5_volume.'"!');

// fetch the current members of the graid5 volume

$disk_members = array();

$lines = explode(chr(10),$cmd);

$i = false;

foreach ($lines as $line)

{

// skip first line

if ($i == false)

{

$i = true;

continue;

}

// get last part of line

$str = substr(strrchr($line,' '),1);

if (!file_exists('/dev/'.$str))

error('Member disk "'.$str.'" does not appear to exist');

if (strlen($str) > 0)

$disk_members[] = $str;

}

// check if user does not try to add a disk which is already part of the volume

foreach ($disks_to_be_added as $disk)

if (array_search($disk,$disk_members) !== false)

error('disk "'.$disk.'" is already a member of the volume you wish to expand!');

// check if volume is mounted

$cmd = getcommand('mount');

if (strpos($cmd,'/dev/raid5/'.$graid5_volume) !== false)

error('graid5 volume "'.$graid5_volume.'" is still mounted, please unmount it first!');

// fetch stripesize

$cmd = getcommand('graid5 list '.$graid5_volume);

$str = substr($cmd,strpos($cmd,$nl.'Stripesize: ')+strlen($nl.'Stripesize: '));

$stripesize = substr($str,0,strpos($str,chr(10)));

if ((int)$stripesize == 0)

error('Could not extract stripesize out of "graid5 list '.$graid5_volume.'" output');

// discover smallest consumer (disk member)

$smallest_disk_sectorcount = -1;

foreach ($disk_members as $disk)

{

// fetch disk size in sectors

$size_in_sectors = trim(`diskinfo $disk | cut -f4`);

// store is lowest size or first

if ((is_int($smallest_disk_sectorcount)) OR (!calc_sameorhigher($size_in_sectors,$smallest_disk_sectorcount)))

$smallest_disk_sectorcount = $size_in_sectors;

}

// calculate provider sectorcount and slack and report

$calculatedrawsectorcount = calc((count($disk_members)-1)." * $smallest_disk_sectorcount");

$calculatedusablesectorcount = calc($calculatedrawsectorcount." - ".(count($disk_members)));

$fullstripeblocksize = calc((count($disk_members)-1)." * $stripesize");

$fullstripeblockcount = calc_floor("$calculatedusablesectorcount / ($fullstripeblocksize / $default_sector_size)");

$calculatedprovidersectorcount = calc("($fullstripeblocksize * $fullstripeblockcount) / $default_sector_size");

$actualprovidersectorcount = trim(`diskinfo /dev/raid5/$graid5_volume | cut -f4`);

$minimalslacksectorcount = count($disk_members);

$calculatedslacksectorcount = calc("$calculatedusablesectorcount % ($fullstripeblocksize / $default_sector_size)");

$actualslacksectorcount = calc("$calculatedusablesectorcount - $actualprovidersectorcount");

echo('** Smallest disk size : '.$smallest_disk_sectorcount.' sectors ('.calc_round("$smallest_disk_sectorcount / (2 * 1024 * 1024)",1).' GB)'.$nl);

echo('** Stripe size : '.$stripesize.' bytes ('.calc("($stripesize / 1024)").' KB)'.$nl);

echo('** Full stripe block : '.$fullstripeblocksize.' bytes ('.calc("$fullstripeblocksize / 1024").' KB)'.$nl);

echo('** Full stripe block count : '.$fullstripeblockcount.' blocks'.$nl);

echo('** Calculated raw size : '.$calculatedrawsectorcount.' sectors'.$nl);

echo('** Calculated usable size : '.$calculatedusablesectorcount.' sectors'.$nl);

echo('** Calculated provider size : '.$calculatedprovidersectorcount.' sectors ('.calc_round("$calculatedprovidersectorcount / (2 * 1024 * 1024)",1).' GB)'.$nl);

echo('** Actual provider size : '.$actualprovidersectorcount.' sectors ('.calc_round("$actualprovidersectorcount / (2 * 1024 * 1024)",1).' GB)'.$nl);

echo('** Minimum slack size : '.($minimalslacksectorcount * 512).' bytes'.$nl);

echo('** Actual slack size : '.($actualslacksectorcount * 512).' bytes ('.calc_round("$actualslacksectorcount / 2",1).' KB)'.$nl);

// sanity checks: compare calculated provider sectorcount with actual count

if ($calculatedprovidersectorcount != $actualprovidersectorcount)

error('SANITY FAILURE! Calculated sector count deviates from actual provider size!'.$nl

.'Please report this to the author at info@fluffles.net!');

// sanity checks: make sure we have the slack space needed for safe expansion

if (!calc_sameorhigher($calculatedslacksectorcount, $minimalslacksectorcount))

error('EXPANSION IMPOSSIBLE: too little slack at end of provider "'.$graid5_volume.'", '

.'you need at least '.calc("$minimalslacksectorcount * 512").' bytes. Sorry.');

echo('** Result : OK'.$nl.$nl);

// sanity check if disks to be added are at least as big as the smallest disk

echo ('** Minimum disk size : '.$smallest_disk_sectorcount.' sectors ('.calc_round("$smallest_disk_sectorcount / (2 * 1024 * 1024)",1).' GB)'.$nl);

foreach ($disks_to_be_added as $disk)

{

// fetch disk size in sectors

$size_in_sectors = trim(`diskinfo $disk | cut -f4`);

// report

echo('** New disk '.$disk.' : '.$size_in_sectors.' sectors ('.calc_round("$size_in_sectors / (2 * 1024 * 1024)",1).' GB)'.$nl);

if (!calc_sameorhigher($size_in_sectors, $smallest_disk_sectorcount))

error('Disk '.$disk.' is smaller than '.$smallest_disk_sectorcount.' sectors ('.calc_round("$smallest_disk_sectorcount / (2 * 1024 * 1024)",1).' GB)'

.'. Expansion denied!');

}

echo('** Result : OK'.$nl.$nl);

// ask for new volume name

echo($nl.'Please enter a name for the new volume. Do not choose a volume name already in use.'.$nl.$nl);

echo('Name of new volume: ');

$line = trim(fgets(STDIN));

$new_volume = $line;

$status = getcommand('graid5 status');

if (!(strlen($new_volume) > 0))

error('Invalid volume name entered (too short)');

elseif (strpos($status,$new_volume) !== FALSE)

error('The chosen volume name appears to exist already!');

// present information

echo($nl.'Please check the information you provided below:'.$nl.$nl);

echo('graid5 volume: '.$graid5_volume.$nl);

echo('new volume name: '.$new_volume.$nl);

echo('Stripesize: '.$stripesize.$nl);

echo('Current disks: '.implode(' ',$disk_members).$nl);

echo('Disks to be added: '.implode(' ',$disks_to_be_added).$nl.$nl);

echo('Is the above information correct? (Y/N) ');

$line = trim(fgets(STDIN));

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

echo($nl.$nl);




/** Starting Expansion Procedure **/

echo('** Starting Expansion Procedure'.$nl);

echo('At this point we are ready to begin the procedure. Please make sure that:'.$nl.$nl);

echo('1. you have closed down each non-critical application (remember to keep sshd running if you login remotely)'.$nl);

echo('2. you do not turn off or reboot the system while expansion is running'.$nl);

echo('3. all disks are in good health and you have checked all disks for surface defects'.$nl.$nl);

echo('Do you wish to continue? (Y/N) ');

$line = trim(fgets(STDIN));

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

echo($nl.$nl);

// enable foot shooting permission

echo('** now setting geom debugflags'.$nl);

$command = 'sysctl kern.geom.debugflags=16';

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

echo($nl.$nl);

usleep(500000);

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// zero write second last metasector of each existing disk

foreach ($disk_members as $disk)

{

// fetch sectorsize

$sectorsize = trim(`diskinfo $disk | cut -f2`);

// fetch disk sector count

$sectorcount = trim(`diskinfo $disk | cut -f4`);

// do complex mathematics

$secondlastsector = calc("$sectorcount - 2");

// write zeroes to second last sector

echo('** writing zeros to sector '.$secondlastsector.' of disk '.$disk.$nl);

$command = 'dd if=/dev/zero of=/dev/'.$disk.' bs='.$sectorsize.' oseek='.$secondlastsector.' count=1 > /dev/null 2>&1';

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

usleep(200000);

}

// zero write two last sectors on each new disk

foreach ($disks_to_be_added as $disk)

{

// fetch sectorsize

$sectorsize = trim(`diskinfo $disk | cut -f2`);

// fetch disk sector count

$sectorcount = trim(`diskinfo $disk | cut -f4`);

// do complex mathematics

$secondlastsector = calc("$sectorcount - 2");

// write zeroes to second last TWO sectors

echo('** writing zeros to TWO sectors starting at #'.$secondlastsector.' of disk '.$disk.$nl);

$command = 'dd if=/dev/zero of=/dev/'.$disk.' bs='.$sectorsize.' oseek='.$secondlastsector.' count=2 > /dev/null 2>&1';

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

usleep(200000);

}

// create gnop containers for each disk

echo('** now creating GNOP devices'.$nl);

foreach ($disk_members as $disk)

{

// fetch sectorsize

$sectorsize = trim(`diskinfo $disk | cut -f2`);

// fetch disk size

$disksize = trim(`diskinfo $disk | cut -f3`);

// fetch disk sector count

$sectorcount = trim(`diskinfo $disk | cut -f4`);

// backup metadata

$command = 'dd if=/dev/'.$disk.' of=/graid5-metabackup-'.$disk.' bs='.$sectorsize.' iseek='.calc("$sectorcount - 1").' count=1 > /dev/null 2>&1';

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

usleep(200000);

// create GNOP device

$command = 'gnop create -s '.calc("$disksize - $sectorsize").' '.$disk;

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

// check if gnop is created as we would expect

if (!debug)

{

$sectorsize_nop = trim(`diskinfo ${disk}.nop | cut -f2`);

if ($sectorsize_nop != $sectorsize)

error('sector size of GNOP device ('.$disk.'.nop) and graid5 volume ('.$disk.') is different');

$disksize_nop = trim(`diskinfo ${disk}.nop | cut -f3`);

if ($disksize_nop != calc("$disksize - $sectorsize"))

error('disk size of GNOP device ('.$disk.'.nop) and graid5 volume ('.$disk.') is different');

}

// created succesfully

echo('created '.$disk.'.nop'.$nl);

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// activate new graid5 volume

echo($nl.'** now activating new graid5 volume ("expanded")'.$nl);

$nop_members = '';

foreach ($disk_members as $disk)

$nop_members .= $disk.'.nop ';

$command = 'graid5 label -h -n -s '.$stripesize.' '.$new_volume.' '.$nop_members.' '.implode(' ',$disks_to_be_added);

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'"');

usleep(500000);

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// now start copying data from old graid5 device to new graid5 device

// this implements the actual 'remapping' of data

echo($nl.'** Starting data remapping procedure'.$nl);

echo('WARNING: from this point the procedure is irreversable'.$nl.$nl);

echo('Do you wish to continue? (Y/N) ');

$line = trim(fgets(STDIN));

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

echo($nl.$nl);

// initialize remapping

$graid5_volume_size = trim(`diskinfo raid5/${graid5_volume} | cut -f3`);

if (calc_sameorhigher(0,$graid5_volume_size))

error('Could not properly detect graid5 volume size');

$i = 0;

$loopprotection = 10000000; // max 1PB

$starttime = time();

// remapping starts

echo('** Starting data transfer now...'.$nl);

while (true)

{

// execute remapping command

$command = 'dd if=/dev/raid5/'.$graid5_volume.' of=/dev/raid5/'.$new_volume.' bs='.$datamapping_chunksize.' '

.'iseek='.$i.' oseek='.$i.' count=1 conv=sync,noerror 2>&1';

if ($debug OR $verbose)

echo('executing: '.$command.$nl);

unset($output);

if (!$debug)

$txt = exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command "'.$command.'" -- OOPS! Contact an expert if you wish to keep your data!');

foreach ($output as $line)

if ($line == '0+0 records out')

{

// end reached

echo($nl.'Data transfer completed. Transferred between '.((($i-1)*$datamapping_chunksize)/(1024*1024)).' MB and '.(($i*$datamapping_chunksize)/(1024*1024)).' MB'.$nl);

// go to next step

break 2;

}

// display progress

$progress = calc_floor("(($i * $datamapping_chunksize) / $graid5_volume_size)*100",1);

if (calc_sameorhigher($progress,"100"))

{

if ($debug)

{

echo($nl.'Since we are running in debugmode, we cannot detect the transfer completion directly, '

.'so we will stop now by timer (100% progress)'.$nl);

break;

}

// overtime reached, this should not happen!

echo($nl);

var_dump($output);

echo($nl);

echo('Return value: '.$rv.$nl.$nl);

echo('WARNING: progress is exceeding 100%! This should not have happened. '

.'You may choose to continue with the next step or try to restore things manually. '

.'You are adviced to contact an expert if your data is important.'.$nl.$nl);

echo('Do you wish to continue? (Y/N) ');

$line = trim(fgets(STDIN));

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

else

echo($nl.'Data transfer completed. Transferred between '.calc("(($i-1)*$datamapping_chunksize)/(1024*1024)").' MB and '.calc("($i*$datamapping_chunksize)/(1024*1024)").' MB'.$nl);

break;

}

$currtime = time();

$deltatime = $currtime - $starttime;

if (($deltatime <= 0) OR (calc_sameorhigher("0",$progress)))

{

$eta = '?';

$progress = 0;

$speed = '?';

}

else

{

// speed is the total throughput (read + write)

$speed = calc_round("($i*$datamapping_chunksize) / (($deltatime*1024*1024) / 2)",1);

//oldcalc: $speed = round((real)($i*$datamapping_chunksize) / (real)(($deltatime*1024*1024) / 2),1);

$projectedtime = $deltatime / ((real)$progress / 100);

$remainingtime = (int)$projectedtime - $deltatime;

//newcalc: $projectedtime = calc("$deltatime / ($progress / 100)");

//newcalc: $remainingtime = calc("$projectedtime - $deltatime;

if ($remainingtime <= 60)

$eta = 'soon';

else

{

$hours = $remainingtime / 3600;

$minutes = ($remainingtime % 3600) / 60;

$eta = (int)$hours.' hours '.str_pad((int)$minutes,2,'0',STR_PAD_LEFT).' minutes';

}

}

if (strpos((string)$progress,'.') === false)

$progress .= '.0';

if ((int)($deltatime / 60) != $deltatime_old)

echo('=> data remapping in progress at '.$progress.'% (ETA: '.$eta.') @ '.$speed.' MB/s'.$nl);

$deltatime_old = (int)($deltatime / 60);

if ($i >= $loopprotection)

error('loop protection while remapping data -- OOPS! Contact an expert if you wish to keep your data!');

// next loop; increase $i

$i++;

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// remove old graid5 volume disks

echo($nl.$nl.'** stopping old graid5 volume'.$nl);

foreach ($disk_members as $disk)

{

$command = 'graid5 remove '.$graid5_volume.' '.$disk;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

echo('Removed disk '.$disk.' from volume "raid5/'.$graid5_volume.'"'.$nl);

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// destroy the old graid5 volume

$command = 'graid5 destroy '.$graid5_volume;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

echo('Destroyed old volume "raid5/'.$graid5_volume.'"'.$nl);

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// remove hardcoded property

echo($nl.'** Removing hardcoded property from new volume "raid5/'.$new_volume.'"'.$nl);

$command = 'graid5 configure -h '.$new_volume;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// sleep to let the change take effect

sleep(4);

// backup meta sectors of new volume

echo($nl.'** Backing up metasectors of new volume "raid5/'.$new_volume.'" disk members (excluding new members)'.$nl.$nl);

if ($debug)

echo('Since we are running in debugmode, please ignore any "diskinfo" errors as well as wrong dd parameters (bs and iseek) here.'.$nl);

foreach ($disk_members as $disk)

{

$disk = $disk.'.nop';

// fetch sectorsize

$sectorsize = trim(`diskinfo $disk | cut -f2`);

// fetch disk size

$disksize = trim(`diskinfo $disk | cut -f3`);

// fetch disk sector count

$sectorcount = trim(`diskinfo $disk | cut -f4`);

// backup metadata

$command = 'dd if=/dev/'.$disk.' of='.$tmp_dir.'graid5-newmetabackup-'.$disk.' '

.'bs='.$sectorsize.' count=1 iseek='.calc("$sectorcount - 1").' > /dev/null 2>&1';

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

echo('Metasector backup of '.$disk.' complete'.$nl);

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// removing GNOP disks in new volume

echo($nl.'** Removing GNOP disks from new volume "raid5/'.$new_volume.'" (does not include new members)'.$nl.$nl);

foreach ($disk_members as $disk)

{

$disk = $disk.'.nop';

// remove disk

$command = 'graid5 remove '.$new_volume.' '.$disk;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume)'.$nl

.'****** OOPS! Contact an expert if you wish to keep your data!');

echo('Removed '.$disk.' from new volume "raid5/'.$new_volume.'"'.$nl);

// now destroy gnop disk as well

$command = 'gnop destroy '.$disk;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (destroying gnop device)'.$nl

.'****** OOPS! Contact an expert if you wish to keep your data!');

echo('Destroyed GNOP device '.$disk.$nl);

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// restore metabackups

echo($nl.'** Restoring metasector backups (does not include new members)'.$nl.$nl);

foreach ($disk_members as $disk)

{

// fetch sectorsize

$sectorsize = trim(`diskinfo $disk | cut -f2`);

// fetch disk size

$disksize = trim(`diskinfo $disk | cut -f3`);

// fetch disk sector count

$sectorcount = trim(`diskinfo $disk | cut -f4`);

$command = 'dd if='.$tmp_dir.'graid5-newmetabackup-'.$disk.'.nop of=/dev/'.$disk.' '

.'bs='.$sectorsize.' count=1 oseek='.calc("$sectorcount - 1").' > /dev/null 2>&1';

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

echo('Restored metabackup of disk '.$disk.$nl);

}

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// unset NO HOT option for new volume

echo($nl.'** Removing "NO HOT" flag from new volume "'.$new_volume.'"'.$nl.$nl);

$command = 'graid5 configure -n '.$new_volume;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// sleep to let change take effect

sleep(4);

// zero write

echo('*** Starting zero-write at offset '.$actualprovidersectorsize.' sectors'.$nl);

echo('*** this could take a long time!'.$nl.$nl);

$newprovidersectorcount = trim(`diskinfo /dev/raid5/$new_volume | cut -f4`);

$sectorsgained = calc("$newprovidersectorcount - $actualprovidersectorcount");

// sanity

if (calc_sameorhigher(0,$sectorsgained))

error('Sectors gained ('.$sectorsgained.') is zero of negative. This should not have happened!');

// execute zero writing!

$command = 'dd if=/dev/zero of=/dev/raid5/'.$new_volume.' bs='.$fullstripeblocksize.' '

.'oseek='.$fullstripeblockcount.' count='.$sectorsgained.' conv=sync,noerror 2>&1';

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv > 1)

{

var_dump($output);

echo($nl.'Return value: '.$rv.$nl.$nl);

echo('** Got return value '.$rv.' on last command (zero write)'.$nl.$nl);

}

echo('*** Done with zero-write!'.$nl.$nl);

if ($stepbystep)

{

echo($nl.'---step-by-step marker---'.$nl);

$line = trim(fgets(STDIN));

}

// display device status

echo($nl.'Displaying current geom_raid5 volumes:'.$nl.$nl);

echo getcommand('graid5 status');

echo($nl.'You should now see a volume "'.$new_volume.'" with disk members '.implode(' ',$disk_members).' '.implode(' ',$disks_to_be_added).$nl);

echo('You should not see the old volume named "'.$graid5_volume.'" anymore.'.$nl);

echo('If you concur with the information above we can start the rebuild of the volume. '

.'If you see a problem, starting a rebuild may cause you to loose all data at this point.'.$nl);

echo('Do you wish to start the rebuild? (Y/N) ');

$line = trim(fgets(STDIN));

echo($nl);

if (strtoupper($line) != 'Y')

die('Aborting'.$nl.$nl);

// start rebuild

echo($nl.'** Starting rebuild of volume "'.$new_volume.'"'.$nl.$nl);

$command = 'graid5 configure -R '.$new_volume;

if ($debug OR $verbose)

echo('Executing: '.$command.$nl);

if (!$debug)

exec($command,$output,$rv);

if ($rv != 0)

error('Got return value '.$rv.' on last command (removing disk from old graid5 volume -- OOPS! Contact an expert if you wish to keep your data!');

sleep(1);

echo('Activated rebuild, check status below: '.$nl.$nl);

echo getcommand('graid5 status');

// the end

echo($nl.$nl);

echo('**'.$nl);

echo('*** geom_raid5 expansion has finished!'.$nl);

echo('*** =================================='.$nl);

echo('*** old size: '.calc("$actualprovidersectorcount / (1024*1024*1024 / $default_sector_size)").' GB'.$nl);

echo('*** new size: '.calc("$newprovidersectorcount / (1024*1024*1024 / $default_sector_size)").' GB'.$nl);

echo('*** size gained: '.calc("$sectorsgained / (1024*1024*1024 / $default_sector_size)").' GB'.$nl);

echo('**'.$nl.$nl);

echo('Expansion has finished. You should now do the following:'.$nl);

echo('1. check that your files are okay (fsck -t ufs /dev/raid5/'.$new_volume.')'.$nl);

echo('2. use growfs to enlarge the filesystem that still has the original size (growfs /dev/raid5/'.$new_volume.')'.$nl);

echo('3. check the filesystem again for errors (fsck -t ufs /dev/raid5/'.$new_volume.')'.$nl.$nl);

echo('Please remember that until the rebuild has finished, your array should be considered DEGRADED'.$nl

.'and does not gain the protection RAID5 offers. The author of this expansion script would very much'.$nl

.'like to hear feedback on your expansion experience. If anything went wrong, or if you have questions,'.$nl

.'or if you are just happy everything went as planned and are now enjoying a bigger graid5 volume, '.$nl

.'please contact:'.$nl.$nl);

echo('Author: Veronica ("Enlightenment")'.$nl);

echo('Email: info@fluffles.net'.$nl);

echo('Website: http://www.fluffles.net/ (lots of info about FreeNAS and geom_raid5 here)'.$nl);

echo('Have a nice day. '.$nl.$nl);

// tune in to http://fluffles.net for geom reviews, benchmarks, articles and our support forum!

// the end



/*** functions ***/

function error($string)

// exits the script because of an error

{

global $nl;

echo($nl);

echo('ERROR: '.$string.$nl.$nl);

die();

}

function usage()

// explains the usage of this script to the user

{

global $nl, $argv;

echo($nl);

echo('Usage: '.$argv[0].' <graid5-volume> <disks to be added>'.$nl);

echo('Example: '.$argv[0].' data ad6 ad8'.$nl.$nl);

die();

}

function getcommand($command)

// executes an external command and returns the output as a string

{

exec($command,$output);

$concat = '';

foreach ($output as $line)

$concat .= $line.chr(10);

return $concat;

}

function calc($calculation, $scale = false)

// do calculations (64-bit INT safe)

{

global $calculator, $math_scale_range, $debug_calc, $nl;

if (($scale < 0) OR (!is_int($scale)))

$scale = (int)$math_scale_range;

if ($calculator == 'bc')

{

$command = 'echo "scale = '.(int)$scale.'; '.$calculation.'" | bc';

exec($command,$output,$rv);

if ($debug_calc)

echo('Calculating: '.$command.' [result = '.$output[0].']'.$nl);

if ($rv != 0)

error('Calculation ('.$calculation.') gave return value '.$rv.' using external BC binary -- sorry!');

return (string)$output[0];

}

elseif ($calculator == 'calc')

{

$command = 'calc -p "'.$calculation.'"';

exec($command,$output,$rv);

if (strpos($output[0],'.') !== false)

$result = substr($output[0],0,strpos($output[0],'.') + 1 + $scale);

else

$result = $output[0];

$result = str_replace('~','',$result);

if ($debug_calc)

echo('Calculating: '.$command.' [result = '.$result.']'.$nl);

if ($rv != 0)

error('Calculation ('.$calculation.') gave return value '.$rv.' using external CALC binary -- sorry!');

return (string)$result;

}

elseif ($calculator == 'internal')

{

$calcfunction = create_function('','return round(('.$calculation.'),'.$scale.');');

$result = $calcfunction();

if ($debug_calc)

echo('Calculating: '.$calculation.' - result = '.$result.$nl);

return (string)$result;

}

}

function calc_sameorhigher($var1, $var2)

// returns boolean TRUE if $var1 is equal or higher than $var2

{

global $debug_calc,$nl;

$result = calc("$var1 - $var2");

if ($result{0} == '-')

{

if ($debug_calc)

echo('Calculation comparison: ('.$result{0}.') '.$var1.' is NOT equal or higher than '.$var2.$nl);

return false;

}

else

{

if ($debug_calc)

echo('Calculation comparison: ('.$result{0}.') '.$var1.' is equal or higher than '.$var2.$nl);

return true;

}

}

function calc_floor($calculation, $scale = 0)

// returns an integer with any fraction truncated. i.e. 4.7 returns 4

// scale sometimes misbehaves so not very dependable

{

global $debug_calc,$nl;

$result = calc($calculation, 10);

if (strpos($result,'.') !== false)

$floor = substr($result,0,strpos($result,'.'));

else

$floor = $result;

if ($debug_calc)

echo('Floor calculation : '.$floor.$nl);

return $floor;

}

function calc_round($calculation, $scale)

// returns a rounded integer, i.e. 4.7 returns 5. scale sets the precision, a scale of 2 means 4.317 will become 4.32

// scale sometimes misbehaves so not very dependable

{

global $debug_calc,$nl;

$result = calc($calculation, 0);

if (strpos($result,'.') !== false)

{

if ($scale > 0)

$rounded = substr($result,0,strpos($result,'.') + 1 + (int)$scale);

else

$rounded = substr($result,0,strpos($result,'.'));

}

else

$rounded = $result;

if ($debug_calc)

echo('Rounded calculation : '.$rounded.$nl);

return $rounded;

}

?>
[/more]

Страницы: 1

Предыдущая тема: linux на imac g3


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.