LINUX.ORG.RU

История изменений

Исправление firkax, (текущая версия) :

Ну проверь. Выключи свап, создай tmpfs, в него запиши что-нить и проверь через месяц. Хотя я бы вместо md5 использовал сидированный рандом-генератор. Даже сделал такую прогу когда-то, правда для жёстких дисков, но с файлом в tmpfs она так же сможет работать.

/* (c) firk 2012-2022 */
#define _FILE_OFFSET_BITS 64
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char uchar;
typedef unsigned int uint32;
typedef unsigned long long uint64;

/*************************************************************************************************/
/*************************************************************************************************/
static void r4(uint32 * d0, uint32 * d1, uint32 * d2, uint32 * d3) {
  uint32 a, b, c, d;
  a=*d0;b=*d1;c=*d2;d=*d3;
  a+=b;d^=a;d=(d<<16)|(d>>16);
  c+=d;b^=c;b=(b<<12)|(b>>20);
  a+=b;d^=a;d=(d<<8)|(d>>24);
  c+=d;b^=c;b=(b<<7)|(b>>25);
  *d0=a;*d1=b;*d2=c;*d3=d;
}
static void r16(uint32 * d) {
  r4(d+0,d+4,d+8,d+12);
  r4(d+1,d+5,d+9,d+13);
  r4(d+2,d+6,d+10,d+14);
  r4(d+3,d+7,d+11,d+15);
  r4(d+0,d+5,d+10,d+15);
  r4(d+1,d+6,d+11,d+12);
  r4(d+2,d+7,d+8,d+13);
  r4(d+3,d+4,d+9,d+14);
}
static void genrandom512(uint32 * res, uint32 * key, uint32 * nonce, uint32 * seq) {
  uint32 tmp[16], i;
  tmp[0] = 0x61707865;
  tmp[1] = 0x3320646E;
  tmp[2] = 0x79622D32;
  tmp[3] = 0x6B206574;
  tmp[4] = key[0];
  tmp[5] = key[1];
  tmp[6] = key[2];
  tmp[7] = key[3];
  tmp[8] = key[4];
  tmp[9] = key[5];
  tmp[10] = key[6];
  tmp[11] = key[7];
  tmp[14] = nonce[0];
  tmp[15] = nonce[1];
  tmp[12] = seq[0];
  tmp[13] = seq[1];
  for(i=0;i<16;i++) res[i]=tmp[i];
  for(i=0;i<10;i++) r16(tmp);
  for(i=0;i<16;i++) res[i]+=tmp[i];
}
static void genrandom1M(uchar * res, uint32 * key, uint64 seq, uint32 blocksize) {
  unsigned i;
  uint32 s[2];
  if(blocksize==1048576) {
    s[0] = (uint32)(seq << 14);
    s[1] = (uint32)(seq >> 18);
    for(i=0; i<16384; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==65536) {
    s[0] = (uint32)(seq << 10);
    s[1] = (uint32)(seq >> 22);
    for(i=0; i<1024; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==4096) {
    s[0] = (uint32)(seq << 6);
    s[1] = (uint32)(seq >> 26);
    for(i=0; i<64; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==512) {
    s[0] = (uint32)(seq << 3);
    s[1] = (uint32)(seq >> 29);
    for(i=0; i<8; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  }
}
static void str2key(uint32 * r, uchar const * src) {
  unsigned i;
  uchar c;
  for(i=0; i<10; i++) {
    if(c = *src) src++;
    r[i] = (i*2038074133) ^ c;
  }
  i = 0;
  while(c=*(src++)) { r[i] = (r[i] * 1294471) ^ c; i = (i+1)%10; }
}

/*************************************************************************************************/
/*************************************************************************************************/
static unsigned long get_ticks(void) {
  static time_t begintime = 0;
#ifndef OLD_TIME
  struct timespec ts;
  if(!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    if(!begintime) begintime = ts.tv_sec;
    return ((unsigned long)(ts.tv_sec-begintime))*1000 + (unsigned long)(ts.tv_nsec/1000000);
  }
#endif
  {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    if(!begintime) begintime = tv.tv_sec;
    return ((unsigned long)(tv.tv_sec-begintime))*1000 + (unsigned long)(tv.tv_usec/1000);
  }
}

/*************************************************************************************************/
/*************************************************************************************************/
static int mode;
static uint32 key[10];
static int device_fd;

static int process_block(uint64 seq, uint32 bs, unsigned loglatency) {
  static uchar buf[1048576];
  static uchar wbuf[1048576];
  long n;
  unsigned long t1, t2, t3;

  if(mode & 2) genrandom1M(wbuf, key, seq, bs);

  t1 = get_ticks();
  if(lseek(device_fd, seq*bs, SEEK_SET)<0) { printf("lseek(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  t2 = get_ticks();
  if(!(mode & 1)) {
    n = read(device_fd, buf, bs);
    if(n<0) { printf("read(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  } else {
    n = write(device_fd, wbuf, bs);
    if(n<0) { printf("write(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  }
  t3 = get_ticks();

  if(n!=(long)bs) {
    uint64 totbytes;
    totbytes = seq*bs+n;
    printf("%s(blk=%llu) processed only %ld bytes of %ld\n", (mode & 1)?"write":"read", seq, n, (long)bs);
    printf("it seems that total size of hdd is %llu bytes\n", totbytes);
  }

  if(t3-t1 > loglatency) printf("block %llu has latency %lu (%lu+%lu)\n", seq, t3-t1, t2-t1, t3-t2);
  
  if(mode==2 && n && memcmp(buf, wbuf, n)) {
    printf("block %llu mismatched!\n", seq);
    return -1;
  }

  if(n!=(long)bs) return 0;
  return 1;
}

int main(int argc, char ** argv) {
  int r;
  char const * device;
  int blocksize;
  long long startblock;
  long long currblock;
  int loglatency;
  if(argc!=6) {
usage:  printf("Usage: hddwscan <mode> <device> <blocksize> <starting block> <loglatency>\n"
               "  <mode> is read|write:key|verify:key\n"
               "  <blocksize> only 1048576 supported\n"
               "  <loglatency> is minimum latency to log\n");
        return 0;
  }
  if(!strcmp(argv[1],"read")) mode = 0;
  else if(!strcmp(argv[1],"write")) mode = 1;
  else if(!strncmp(argv[1],"verify:",7)) { mode = 2; str2key(key,(uchar*)argv[1]+7); }
  else if(!strncmp(argv[1],"write:",6)) { mode = 3; str2key(key,(uchar*)argv[1]+6); }
  else goto usage;
  device = argv[2];
  blocksize = atoi(argv[3]);
  startblock = atoll(argv[4]);
  loglatency = atoi(argv[5]);
  if(blocksize!=512 && blocksize!=4096 && blocksize!=65536 && blocksize!=1048576) {
    printf("Valid block size is 512, 4096, 65536, 1048576\n");
    return 0;
  }
  if(startblock<0) startblock = 0;
  if(loglatency<0) loglatency = 0;
  if(mode & 2) printf("using key %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\n", key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9]);
  printf("Starting \"%s\" for %s, blocksize %d, starting block %lld, logging when latency >%d ms\nWaiting 10 seconds...\n", argv[1], device, blocksize, startblock, loglatency);
  sleep(10);

  currblock = startblock;
  device_fd = open(device, (mode & 1)?O_RDWR:O_RDONLY);
  if(device_fd<0) { printf("open(%s) error %d (%s)\n", device, errno, strerror(errno)); return 0; }

  while(1) {

    if(!(currblock%10)) {
      if(mode==0) printf("Reading %s block %lld\r", device, currblock);
      else if(mode==1) printf("Zero-writing %s block %lld\r", device, currblock);
      else if(mode==2) printf("Verifying %s block %lld\r", device, currblock);
      else if(mode==3) printf("Writing %s block %lld\r", device, currblock);
      fflush(stdout);
    }

    r = process_block(currblock, blocksize, loglatency);
    if(r<=0) { close(device_fd); return r; }
    currblock++;
  }
}

В начале

./hddwscan write:h45wh543h34 /path/to/tmpfs/file 1048576 0 1000
оно будет писать пока место не закончится или пока ctrl-c не нажмёшь

проверка

./hddwscan verify:h45wh543h34 /path/to/tmpfs/file 1048576 0 1000

Исходная версия firkax, :

Ну проверь. Выключи свап, создай tmpfs, в него запиши что-нить и проверь через месяц. Хотя я бы вместо md5 использовал сидированный рандом-генератор. Даже сделал такую прогу когда-то, правда для жёстких дисков, но с файлом в tmpfs она так же сможет работать.

/* (c) firk 2012-2022 */
#define _FILE_OFFSET_BITS 64
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char uchar;
typedef unsigned int uint32;
typedef unsigned long long uint64;

/*************************************************************************************************/
/*************************************************************************************************/
static void r4(uint32 * d0, uint32 * d1, uint32 * d2, uint32 * d3) {
  uint32 a, b, c, d;
  a=*d0;b=*d1;c=*d2;d=*d3;
  a+=b;d^=a;d=(d<<16)|(d>>16);
  c+=d;b^=c;b=(b<<12)|(b>>20);
  a+=b;d^=a;d=(d<<8)|(d>>24);
  c+=d;b^=c;b=(b<<7)|(b>>25);
  *d0=a;*d1=b;*d2=c;*d3=d;
}
static void r16(uint32 * d) {
  r4(d+0,d+4,d+8,d+12);
  r4(d+1,d+5,d+9,d+13);
  r4(d+2,d+6,d+10,d+14);
  r4(d+3,d+7,d+11,d+15);
  r4(d+0,d+5,d+10,d+15);
  r4(d+1,d+6,d+11,d+12);
  r4(d+2,d+7,d+8,d+13);
  r4(d+3,d+4,d+9,d+14);
}
static void genrandom512(uint32 * res, uint32 * key, uint32 * nonce, uint32 * seq) {
  uint32 tmp[16], i;
  tmp[0] = 0x61707865;
  tmp[1] = 0x3320646E;
  tmp[2] = 0x79622D32;
  tmp[3] = 0x6B206574;
  tmp[4] = key[0];
  tmp[5] = key[1];
  tmp[6] = key[2];
  tmp[7] = key[3];
  tmp[8] = key[4];
  tmp[9] = key[5];
  tmp[10] = key[6];
  tmp[11] = key[7];
  tmp[14] = nonce[0];
  tmp[15] = nonce[1];
  tmp[12] = seq[0];
  tmp[13] = seq[1];
  for(i=0;i<16;i++) res[i]=tmp[i];
  for(i=0;i<10;i++) r16(tmp);
  for(i=0;i<16;i++) res[i]+=tmp[i];
}
static void genrandom1M(uchar * res, uint32 * key, uint64 seq, uint32 blocksize) {
  unsigned i;
  uint32 s[2];
  if(blocksize==1048576) {
    s[0] = (uint32)(seq << 14);
    s[1] = (uint32)(seq >> 18);
    for(i=0; i<16384; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==65536) {
    s[0] = (uint32)(seq << 10);
    s[1] = (uint32)(seq >> 22);
    for(i=0; i<1024; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==4096) {
    s[0] = (uint32)(seq << 6);
    s[1] = (uint32)(seq >> 26);
    for(i=0; i<64; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  } else if(blocksize==512) {
    s[0] = (uint32)(seq << 3);
    s[1] = (uint32)(seq >> 29);
    for(i=0; i<8; i++,s[0]++) genrandom512((uint32*)(res+i*64), key, key+8, s);
  }
}
static void str2key(uint32 * r, uchar const * src) {
  unsigned i;
  uchar c;
  for(i=0; i<10; i++) {
    if(c = *src) src++;
    r[i] = (i*2038074133) ^ c;
  }
  i = 0;
  while(c=*(src++)) { r[i] = (r[i] * 1294471) ^ c; i = (i+1)%10; }
}

/*************************************************************************************************/
/*************************************************************************************************/
static unsigned long get_ticks(void) {
  static time_t begintime = 0;
#ifndef OLD_TIME
  struct timespec ts;
  if(!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    if(!begintime) begintime = ts.tv_sec;
    return ((unsigned long)(ts.tv_sec-begintime))*1000 + (unsigned long)(ts.tv_nsec/1000000);
  }
#endif
  {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    if(!begintime) begintime = tv.tv_sec;
    return ((unsigned long)(tv.tv_sec-begintime))*1000 + (unsigned long)(tv.tv_usec/1000);
  }
}

/*************************************************************************************************/
/*************************************************************************************************/
static int mode;
static uint32 key[10];
static int device_fd;

static int process_block(uint64 seq, uint32 bs, unsigned loglatency) {
  static uchar buf[1048576];
  static uchar wbuf[1048576];
  long n;
  unsigned long t1, t2, t3;

  if(mode & 2) genrandom1M(wbuf, key, seq, bs);

  t1 = get_ticks();
  if(lseek(device_fd, seq*bs, SEEK_SET)<0) { printf("lseek(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  t2 = get_ticks();
  if(!(mode & 1)) {
    n = read(device_fd, buf, bs);
    if(n<0) { printf("read(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  } else {
    n = write(device_fd, wbuf, bs);
    if(n<0) { printf("write(blk=%llu) error %d (%s)\n", seq, errno, strerror(errno)); return -1; }
  }
  t3 = get_ticks();

  if(n!=(long)bs) {
    uint64 totbytes;
    totbytes = seq*bs+n;
    printf("%s(blk=%llu) processed only %ld bytes of %ld\n", (mode & 1)?"write":"read", seq, n, (long)bs);
    printf("it seems that total size of hdd is %llu bytes\n", totbytes);
  }

  if(t3-t1 > loglatency) printf("block %llu has latency %lu (%lu+%lu)\n", seq, t3-t1, t2-t1, t3-t2);
  
  if(mode==2 && n && memcmp(buf, wbuf, n)) {
    printf("block %llu mismatched!\n", seq);
    return -1;
  }

  if(n!=(long)bs) return 0;
  return 1;
}

int main(int argc, char ** argv) {
  int r;
  char const * device;
  int blocksize;
  long long startblock;
  long long currblock;
  int loglatency;
  if(argc!=6) {
usage:  printf("Usage: hddwscan <mode> <device> <blocksize> <starting block> <loglatency>\n"
               "  <mode> is read|write:key|verify:key\n"
               "  <blocksize> only 1048576 supported\n"
               "  <loglatency> is minimum latency to log\n");
        return 0;
  }
  if(!strcmp(argv[1],"read")) mode = 0;
  else if(!strcmp(argv[1],"write")) mode = 1;
  else if(!strncmp(argv[1],"verify:",7)) { mode = 2; str2key(key,(uchar*)argv[1]+7); }
  else if(!strncmp(argv[1],"write:",6)) { mode = 3; str2key(key,(uchar*)argv[1]+6); }
  else goto usage;
  device = argv[2];
  blocksize = atoi(argv[3]);
  startblock = atoll(argv[4]);
  loglatency = atoi(argv[5]);
  if(blocksize!=512 && blocksize!=4096 && blocksize!=65536 && blocksize!=1048576) {
    printf("Valid block size is 512, 4096, 65536, 1048576\n");
    return 0;
  }
  if(startblock<0) startblock = 0;
  if(loglatency<0) loglatency = 0;
  if(mode & 2) printf("using key %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\n", key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9]);
  printf("Starting \"%s\" for %s, blocksize %d, starting block %lld, logging when latency >%d ms\nWaiting 10 seconds...\n", argv[1], device, blocksize, startblock, loglatency);
  sleep(10);

  currblock = startblock;
  device_fd = open(device, (mode & 1)?O_RDWR:O_RDONLY);
  if(device_fd<0) { printf("open(%s) error %d (%s)\n", device, errno, strerror(errno)); return 0; }

  while(1) {

    if(!(currblock%10)) {
      if(mode==0) printf("Reading %s block %lld\r", device, currblock);
      else if(mode==1) printf("Zero-writing %s block %lld\r", device, currblock);
      else if(mode==2) printf("Verifying %s block %lld\r", device, currblock);
      else if(mode==3) printf("Writing %s block %lld\r", device, currblock);
      fflush(stdout);
    }

    r = process_block(currblock, blocksize, loglatency);
    if(r<=0) { close(device_fd); return r; }
    currblock++;
  }
}