Atualize o dispositivo de bloco com a imagem enquanto escreve apenas o Delta, é possível?

3

Eu uso dd extensivamente como um meio de controle de configuração de software. As imagens são normalmente implantadas no disco flash para atualizar dispositivos. Muitas vezes, estou fazendo pequenas atualizações incrementais nos arquivos de imagem e tendo que copiar novamente a imagem inteira para o dispositivo de bloco. Isso consome bastante tempo, já que as imagens geralmente têm 8 GB de tamanho. Para agravar o problema, as imagens (uma vez montadas) não estão em um formato facilmente montável. Em outras palavras, fazer a alteração diretamente no bloco não é possível.

Estou tentando determinar se existe um método para comparar um arquivo de imagem a um dispositivo de bloco e atualizar apenas os blocos que exigem uma atualização. Eu suspeito que isso seria muito mais rápido do que gravar todo o disco para o que provavelmente equivale a um delta de 10kb no arquivo de imagem.

    
por Jeff Mootrey 09.02.2017 / 16:12

3 respostas

3

O seguinte é um hack rápido para um pequeno programa em C capaz de comparar dois arquivos (file1, file2) em bloco e, se os blocos forem diferentes, copia o bloco correspondente de file1 para file2. Funciona também para arquivos e dispositivos de bloco. Faça com o que quiser, mas a seu próprio risco!

/*
Small program to blockwise compare two files and write different
blocks from file1 to file2.

Arguments: file1, file2, blocksize in bytes
If blocksize is not given, it is set to 512 (minimum)

No error checking, no intensive tests run - use at your own risk! 

*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(argc, argv)
int argc;
char *argv[];
{

  char *fnamein;                  /* Input file name */
  char *fnameout;                 /* Output file name */
  char *bufin;                    /* Input buffer */
  char *bufout;                   /* Output buffer */
  int bufsize;                    /* Buffer size (blocksize) */
  int fdin;                       /* Input file descriptor*/
  int fdout;                      /* Output file descriptor*/
  int cnt;                        /* Current block # */

  /* Argument processing */

  if (argc < 3 || argc > 4) {
    fprintf(stderr,"Usage: %s infile outfile [bufsize]\n", argv[0]);
    exit(1);
  }

  fnamein = argv[1];
  fnameout = argv[2];
  if (argc == 4) {
    bufsize = atoi(argv[3]);
    if (bufsize < 512) {
      fprintf(stderr,"Error: Illegal value for [bufsize]: %s\n", argv[3]);
      exit(1);
    }
  } else {
    bufsize = 512;
  }

  fprintf(stderr, "Copying differing blocks from '%s' to '%s', blocksize is %i\n", fnamein, fnameout, bufsize);

  if (! ((bufin = malloc(bufsize)) && (bufout = malloc(bufsize)))) {
    fprintf(stderr,"Error: Can't allocate buffers: %i\n", bufsize);
    exit(1);  
  }
  fdin = open(fnamein, O_RDONLY);
  if (fdin < 0) {
    fprintf(stderr,"Error: Can't open input file: %s\n", fnamein);
    exit(1);  
  }

  fdout = open(fnameout, O_RDWR | O_SYNC);
  if (fdout < 0) {
    fprintf(stderr,"Error: Can't open ouput file: %s\n", fnameout);
    exit(1);  
  }

  cnt = 0;
  while (read(fdin, bufin, bufsize) == bufsize) {
    if (read(fdout, bufout, bufsize) == bufsize) {
      if (memcmp(bufin, bufout, bufsize) != 0) {
        fprintf(stderr, "Differing blocks at block # %i; writing block to %s\n", cnt, fnameout);
        if (lseek(fdout, -bufsize, SEEK_CUR) > -1) {
          if (write(fdout, bufin, bufsize) != bufsize) {
            fprintf(stderr,"Error: Unable to write to output file %s block # %i\n", fnameout, cnt);
            exit(1);
          }
        } else {
          fprintf(stderr,"Error: Unable to seek to output file %s block # %i\n", fnameout, cnt);
          exit(1);
        }
      }
    } else {
      fprintf(stderr,"Error: Unable to read from ouput file %s block # %i\n", fnameout, cnt);
      exit(1);
    }
    cnt++;
  }

  exit(0);
}
    
por 09.02.2017 / 22:09
2

Procure no qemu-img, usando o original como arquivo de apoio, e criando um disco diferencial no formato qcow2.

Acesse como um dispositivo de bloco usando qemu-nbd (para convertê-lo em um dispositivo nbd).

Isso registrará os deltas no disco de diferenciação qcow2 e deixará o original sozinho. O disco diferencial cresce em pequenos valores para cada bloco alterado.

Para aplicar esses deltas a um ou mais "originais", use a operação "commit" do qemu-img.

    
por 13.02.2017 / 05:51
0

Bem, como mencionado em um comentário sobre sua pergunta, dd parameters bs , seek , skip e count são seus amigos. Além disso, dividiria logicamente suas imagens em uma lista de blocos de tamanho adequado (digamos, 10MB cada) e manteria o md5sum de cada fragmento (ou um hash mais longo, se você tem medo de colisões, o que eu não faria). Quando uma nova imagem aparece, você só precisa verificar a nova imagem contra os hashes (praticamente metade do tempo de comparação) e copiar para o disco apenas os pedaços alterados. Você pode até descobrir que alguns de seus fragmentos são idênticos (provavelmente todos os zeros) e executar otimizações adicionais de acordo.

    
por 09.02.2017 / 18:26