Поменять местами содержимое двух HDD (для промежуточного хранения - только ОЗУ)

IDE, SATA, SCSI, внешние USB-HDD, SSD, USB-Flash накопители

Модератор: Модераторы разделов

Аватара пользователя
rm_
Сообщения: 3340
Статус: It's the GNU Age
ОС: Debian

Поменять местами содержимое двух HDD

Сообщение rm_ »

Есть два винчестера по 1.5 ТБ, нужно чтобы все данные с первого диска оказались на втором, а со второго - на первом. Для промежуточного хранения данных третий диск не использовать, только оперативку. Такая вот интересная задачка.
Верификация записанного - приветствуется; проприетарщину (всякие акронисы) - не предлагать. Я понимаю, что можно шелл-скрипт написать на базе практически одного только dd, но может уже есть готовый (и оттестированный) инструмент для такой операции?
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

Можно (если система на третьем HDD) сделать скриптик (а еще проще - на сях программку написать): выделить процентов 90 оперативки (кстати, если в шелле - сделать /dev/shm на 90% оперативки) и гонять sdx->половина выделенной памяти, sdy->другая половина, вторая половина -> sdx, первая -> sdy; и так, пока все не скопируем :)

Но, честно говоря, меня эта задача вводит в ступор: ЗАЧЕМ?
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
rm_
Сообщения: 3340
Статус: It's the GNU Age
ОС: Debian

Re: Поменять местами содержимое двух HDD

Сообщение rm_ »

сделать скриптик (а еще проще - на сях программку написать): выделить процентов 90 оперативки (кстати, если в шелле - сделать /dev/shm на 90% оперативки)

Угу. Тем более что её 8 ГБ.

и гонять sdx->половина выделенной памяти, sdy->другая половина, вторая половина -> sdx, первая -> sdy;

Да можно проще:
1) sda -> RAM;
2) sdb -> sda;
3) RAM -> sdb.

Но, честно говоря, меня эта задача вводит в ступор: ЗАЧЕМ?

Винчестеры разных фирм/производительности/вибручести, я подумываю некоторым образом обменять их друг с другом в плане обязанностей.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

Понятно. Так вперед - выйдите в single, перемонтируйте /dev/shm, чтобы его размер был ~7.5Гб, и гоняйте данные...
Только если у вас смещение в lseek задается 32-битным, не забудьте прописать в начале файла

Код: Выделить всё

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE

Если хотите обойтись скриптом - придется использовать bc, чтобы вычислять смещение для очередного dd.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Поменять местами содержимое двух HDD

Сообщение drBatty »

eddy писал(а):
20.04.2010 21:44
Если хотите обойтись скриптом - придется использовать bc, чтобы вычислять смещение для очередного dd.

да вроде и bash может. ((такой конструкцией))

rm_ писал(а):
20.04.2010 21:11
Верификация записанного - приветствуется;

можно считать КС каждого блока, и писать их в два файла. Затем проверить. Вот только если не сойдётся...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

drBatty писал(а):
20.04.2010 22:56
да вроде и bash может. ((такой конструкцией))

А баш умеет long long? Не знал, я думал, он 32-битной арифметикой обходится.

Ух ты! Попробовал - и правда, баш, оказывается, с 64-битными числами работает!
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
rm_
Сообщения: 3340
Статус: It's the GNU Age
ОС: Debian

Re: Поменять местами содержимое двух HDD

Сообщение rm_ »

eddy писал(а):
20.04.2010 23:02
drBatty писал(а):
20.04.2010 22:56
да вроде и bash может. ((такой конструкцией))

А баш умеет long long? Не знал, я думал, он 32-битной арифметикой обходится.

Ух ты! Попробовал - и правда, баш, оказывается, с 64-битными числами работает!

Там не обязателен long long, смещение для dd задаётся в блоках, а размер блока указывается (bs=) произвольно, и нормальное значение - 1-8-16-32-64 мегабайт. Для простоты расчётов можно даже поставить 100.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

Тьфу ты, а я и забыл. Так можно еще больше упростить задачу: сказать, что размер блока равен, скажем, 7.5Гб :)
А не проще ли на сях написать? Хотя, честно говоря, я с такими объемами оперативки не работал. Но, думаю, уже давно есть способ сделать alloc больше, чем на 2Гб. Тогда делаем

Код: Выделить всё

unsigned char *mem = (unsigned char*)malloc(8053063680);
read(/dev/sdx, mem, 8053063680)

и дальше по смыслу...
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
rm_
Сообщения: 3340
Статус: It's the GNU Age
ОС: Debian

Re: Поменять местами содержимое двух HDD

Сообщение rm_ »

сказать, что размер блока равен, скажем, 7.5Гб

Не получится. Исходники не смотрел, но если я правильно прочувствовал его алгоритм (в том числе в процессе экспериментов с большими размерами блоков), dd сначала считывает с источника данные до заполнения буфера (равного тому самому размеру блока) в ОЗУ, потом сливает этот буфер на устройство-пункт назначения. Соотв-но прочитай он в буфер 7.5 ГБ, скинуть их (в ту же самую оперативку) будет уже некуда.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

Тогда пишите на С. Уложитесь максимум в страницу :)
У меня, к сожалению, ни дома, ни на работе нет компьютера с ОЗУ>2Гб, поэтому помочь вам не могу. А увеличение оперативки хотя бы до 6Гб у меня планируется только к осени :(
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Поменять местами содержимое двух HDD

Сообщение NickLion »

rm_ писал(а):
20.04.2010 21:35
и гонять sdx->половина выделенной памяти, sdy->другая половина, вторая половина -> sdx, первая -> sdy;

Да можно проще:
1) sda -> RAM;
2) sdb -> sda;
3) RAM -> sdb.

Не стоит. Так дольше скорее всего будет:
1) sda -> RAM; - sdb простаивает
2) sdb -> sda; - работают оба винта
3) RAM -> sdb. - sda простаивает
А если
1) sda -> RAM0 - 1 и 2 параллельно можно - память быстрее винтов
2) sdb -> RAM1
3) RAM0 -> sdb - опять же параллельно 3 и 4
4) RAM1 -> sda
простоев нет.
Спасибо сказали:
sciko
Сообщения: 1744
Статус: Ъ-участник
ОС: Debian/Ubuntu/etc

Re: Поменять местами содержимое двух HDD

Сообщение sciko »

rm_ писал(а):
20.04.2010 21:35
Винчестеры разных фирм/производительности/вибручести, я подумываю некоторым образом обменять их друг с другом в плане обязанностей.
Меня всегда удивляло на что люди идут лишь бы рейдом не пользоваться.
ИМХО, смысла в такой замене мало. Хотя бы потому, что повышение надёжности сопоставимо со статистической погрешностью.

По задаче рекомендую делать на всякий пожарный ещё и проверку целостности записанного (вероятность ошибки не нулевая).
Спасибо сказали:
Аватара пользователя
rm_
Сообщения: 3340
Статус: It's the GNU Age
ОС: Debian

Re: Поменять местами содержимое двух HDD

Сообщение rm_ »

ИМХО, смысла в такой замене мало. Хотя бы потому, что повышение надёжности

Про надёжность тут ничего не говорилось, дело в том, что хочу вынести Samsung, охотно вступающий в резонанс с другими винтами в корзине, в компьютер, где он будет стоять как первый и единственный винчестер.
Но про RAID Вы правы, всерьёз подумываю о том чтоб сделать, только "барьер для входа" получается далеко не нулевой, нужно разом выложить деньги на бочку за как минимум 3*2ТБ (ну либо делать на "полторашках", что может оказаться недальновидным).
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Поменять местами содержимое двух HDD

Сообщение drBatty »

NickLion писал(а):
21.04.2010 05:31
Не стоит. Так дольше скорее всего будет:

проще всего найти(одолжить) третий винт и не парится.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

drBatty писал(а):
21.04.2010 11:03
проще всего найти(одолжить) третий винт и не парится.

Проще, но ведь интереснее написать программку, и использовать ресурсы своего компьютера. Тем более, что время на копирование с использованием в качестве посредника оперативки будет меньше, чем если посредником будет выступать жесткий диск.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Поменять местами содержимое двух HDD

Сообщение drBatty »

eddy писал(а):
21.04.2010 11:23
Проще, но ведь интереснее написать программку, и использовать ресурсы своего компьютера.

я-бы башскриптом поменял. кусками по 1000Мб. и с проверкой

Код: Выделить всё

sda->mem
sdb->sda
cksum sda
mem->sdb
cksum sdb

ну и что, что долго? действие одноразовое.
Впрочем - пишите, я себе вашу программку тоже соберу, на всякий случай (:
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

drBatty писал(а):
21.04.2010 11:30
я себе вашу программку тоже соберу, на всякий случай (:

Так нет у меня оперативки >2Гб (я уже выше говорил), как проверить, что она работать будет?
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Поменять местами содержимое двух HDD

Сообщение drBatty »

eddy писал(а):
21.04.2010 11:34
Так нет у меня оперативки >2Гб (я уже выше говорил), как проверить, что она работать будет?

а вы программку задумали исключительно для случая 8Гб? тогда - не надо.
почему нельзя реализовать параметр - размер буфера в мб? У меня сейчас тоже 512Мб.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

drBatty писал(а):
21.04.2010 12:35
почему нельзя реализовать параметр - размер буфера в мб? У меня сейчас тоже 512Мб.

Можно. После обеда (если найду время) попробую что-нибудь подобное сделать. А с ОЗУ>2Гб не мешало бы потренироваться, чтобы узнать, может ли malloc выделять очень большие объемы памяти.
Кстати, не знаю, чего это я зацепился за malloc: с тем же успехом можно выделить память и shmget'ом :)
В общем, попробую и так, и эдак, потестирую на обмене содержимым двух файлов.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

Итак, как и обещал, привожу исходник:

Код: Выделить всё

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char** argv){
    int w1, w2, r1, r2, bytes1, bytes2, bytes;
    int memsize, id1, id2, Mb = 1024*1024;
    key_t key1, key2;
    unsigned char *data1, *data2;
    if(argc < 3){
        printf("\nUsage: %s <file1> <file2> [mem]\n", argv[0]);
        printf("\tswaps data in files <file1> & <file2>\n");
        printf("mem - shared memory segments size in Mb (by default: 100)\n\n");
        exit(1);
    }
    w1=open(argv[1], O_WRONLY);
    r1=open(argv[1], O_RDONLY);
    if(w1 < 1 || r1 < 1){
        perror("Cant open file1");
        exit(1);
    }
    w2=open(argv[2], O_WRONLY);
    r2=open(argv[2], O_RDONLY);
    if(w2 < 1 || r2 < 1){
        perror("Cant open file2");
        exit(1);
    }
    if(argc == 4) memsize = atoi(argv[3]);
    else memsize = 100;
    memsize *= Mb;
    key1 = ftok(argv[1], 22);
    key2 = ftok(argv[2], 22);
    id1 = shmget(key1, memsize, IPC_CREAT|0644|SHM_DEST);
    id2 = shmget(key2, memsize, IPC_CREAT|0644|SHM_DEST);
    if(id1 < 0 || id2 < 0){
        perror("Can't get shared memory");
        goto ex;
    }
    data1 = (unsigned char*)shmat(id1, NULL, 0);
    data2 = (unsigned char*)shmat(id2, NULL, 0);
    if(data1 == ((void*)-1) || data2 == ((void*)-1)){
        perror("Can't attach shared memory");
        exit(1);
    }
    do{
        bytes1 = read(r1, data1, memsize);
        bytes2 = read(r2, data2, memsize);
        if(bytes1 < 0 || bytes2 < 0){
            perror("Can't read data from files");
            goto ex;
        }
        bytes = (bytes1 > bytes2) ? bytes2:bytes1;
        bytes1 = write(w1, data2, bytes);
        bytes2 = write(w2, data1, bytes);
        if(bytes1 != bytes || bytes2 != bytes){
            perror("Can't write data to files");
            goto ex;
        }
    }while(bytes == memsize);
ex:
    shmdt(data2);
    shmctl(id2, IPC_RMID, NULL);
    shmdt(data1);
    shmctl(id1, IPC_RMID, NULL);
}

Используем: a.out file1 file2 [size], на блочных устройствах еще не проверял, содержимое обычных файлов местами меняет. Аргумент size - размер выделяемой области оперативки (в мегабайтах). По умолчанию - 100Мб.
Заранее от рута выполните

Код: Выделить всё

echo SIZE > /proc/sys/kernel/shmmax

Где SIZE - размер оперативки, которую вы позволите выделить под буферы (как минимум в 2 раза больше параметра size.

Проверял на файлах разных размеров. Работает. Оперативки, правда, у меня всего лишь 2Гб, так что под буферы выделял по 500Мб.

Да, система у меня 32битная, на 64-битной не знаю, как будет себя вести size_t при чтении/записи, если работать сразу с куском, скажем, 7Гб (если у вас, к примеру, 16Гб оперативки на домашнем компьютере).

Ну, а если на домашнем компьютере оперативки гигов на 128, можно небольшие жесткие диски целыми разделами за "присест" копировать :)

P.S. если размеры файлов отличаются, излишки данных у более объемного файла так и остаются при нем.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Поменять местами содержимое двух HDD

Сообщение NickLion »

eddy писал(а):
21.04.2010 22:53
Заранее от рута выполните

Код: Выделить всё

echo SIZE > /proc/sys/kernel/shmmax

Где SIZE - размер оперативки, которую вы позволите выделить под буферы (как минимум в 2 раза больше параметра size.

Зачем? У меня там и так 264-1 :)

eddy писал(а):
21.04.2010 22:53
Да, система у меня 32битная, на 64-битной не знаю, как будет себя вести size_t при чтении/записи, если работать сразу с куском, скажем, 7Гб (если у вас, к примеру, 16Гб оперативки на домашнем компьютере).

Посмотрим, система 64 битная :)

Потестил. В программе была парочка ошибочек, вот изменённый код (я там расчёт мб изменил заодно :D)

Код: Выделить всё

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>

int main( int argc, char** argv ) {
    int w1, w2, r1, r2;
    int id1, id2;//, Mb = 1024*1024;
    size_t memsize;
    ssize_t bytes1, bytes2, bytes;
    key_t key1, key2;
    unsigned char *data1, *data2;
    if(argc < 3){
        printf("\nUsage: %s <file1> <file2> [mem]\n", argv[0]);
        printf("\tswaps data in files <file1> & <file2>\n");
        printf("mem - shared memory segments size in Mb (by default: 100)\n\n");
        exit(1);
    }
    w1=open(argv[1], O_WRONLY);
    r1=open(argv[1], O_RDONLY);
    if(w1 < 1 || r1 < 1){
        perror("Cant open file1");
        exit(1);
    }
    w2=open(argv[2], O_WRONLY);
    r2=open(argv[2], O_RDONLY);
    if(w2 < 1 || r2 < 1){
        perror("Cant open file2");
        exit(1);
    }
    if(argc == 4) memsize = atoi(argv[3]);
    else memsize = 4608;
    //memsize *= Mb;
    memsize <<= 20; // (* 2^20) ^_^
    key1 = ftok(argv[1], 22);
    key2 = ftok(argv[2], 22);
    id1 = shmget(key1, memsize, IPC_CREAT|0644|SHM_DEST);
    id2 = shmget(key2, memsize, IPC_CREAT|0644|SHM_DEST);
    if(id1 < 0 || id2 < 0){
        perror("Can't get shared memory");
        goto ex;
    }
    data1 = (unsigned char*)shmat(id1, NULL, 0);
    data2 = (unsigned char*)shmat(id2, NULL, 0);
    if(data1 == ((void*)-1) || data2 == ((void*)-1)){
        perror("Can't attach shared memory");
        exit(1);
    }
    do{
        bytes1 = read(r1, data1, memsize);
        bytes2 = read(r2, data2, memsize);
        if(bytes1 < 0 || bytes2 < 0){
            perror("Can't read data from files");
            goto ex;
        }
        bytes = (bytes1 > bytes2) ? bytes2:bytes1;
        bytes1 = write(w1, data2, bytes);
        bytes2 = write(w2, data1, bytes);
        if(bytes1 != bytes || bytes2 != bytes){
            perror("Can't write data to files");
            goto ex;
        }
    } while( (size_t) bytes == memsize );
ex:
    shmdt(data2);
    shmctl(id2, IPC_RMID, NULL);
    shmdt(data1);
    shmctl(id1, IPC_RMID, NULL);
}

Но на тесте оказалось, что в строке:

Код: Выделить всё

        bytes1 = read(r1, data1, memsize);

При memsize = 4608 << 20; (4.5 Гб)
Всё равно считывает меньше 2 гиг :( Конкретно у меня ушло 2147479552 байт в буфер. В принципе, буфер вполне достаточного размера, большей скорости не получишь. (только тут чтение/запись последовательные и на файлах, а если разные устройства, то параллельно можно)
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Поменять местами содержимое двух HDD

Сообщение eddy »

NickLion писал(а):
22.04.2010 07:17
Всё равно считывает меньше 2 гиг

Вот про это я и говорил: мне негде проверить, чему равен размер size_t на 64-битных системах. Оказывается - 32 бита. Поэтому максимум 2Гб он и считывает.
Ну, а раз так, то возможны два варианта: не выделять памяти больше 2Гб на каждый файл, или считывать в цикле кусками по 2Гб (если, скажем, вы выделили по 4Гб на файл).
Если задачу распараллелить (при помощи thread или fork), то придется как-то контролировать, что оба потока или процесса уже заполнили свои буферы. Здесь уже либо вводить flock, либо семафоры, либо отображать память в файл и хранить там данные о завершении, либо в той же разделяемой памяти сделать общую область, куда помещать флаги готовности/неготовности. Еще вариант (если делать fork): обмениваться сигналами, SIG_USR1 и SIG_USR2 вполне на эти задачи хватит. Тогда где-то в два раза скорость обмена возрастет.

NickLion писал(а):
22.04.2010 07:17
При memsize = 4608 << 20; (4.5 Гб)

Кстати, а у вас что, >10Гб оперативки?
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Поменять местами содержимое двух HDD

Сообщение NickLion »

eddy писал(а):
22.04.2010 08:46
NickLion писал(а):
22.04.2010 07:17
Всё равно считывает меньше 2 гиг

Вот про это я и говорил: мне негде проверить, чему равен размер size_t на 64-битных системах. Оказывается - 32 бита. Поэтому максимум 2Гб он и считывает.

Нет, memsize да и любая size_t - 64 бита (причём unsigned) (правда у Вас был тип int почему-то, это я поменял). Но вот считывает всё равно только до 2 гиг - т.е. это особенность реализации read/write. Они ведь не гарантируют, что будет считано/записано ровно столько, сколько указано.

eddy писал(а):
22.04.2010 08:46
NickLion писал(а):
22.04.2010 07:17
При memsize = 4608 << 20; (4.5 Гб)

Кстати, а у вас что, >10Гб оперативки?

Нет, только (:D) 6Гб, я просто закоментировал на время тестирования всё, что связано со вторым блоком.
Спасибо сказали: