Há duas coisas acontecendo aqui - os arquivos maiores do que o esperado são devidos a metadados dos armazenamentos de sistema de arquivos que estão sendo contados em relação ao tamanho do arquivo. Os arquivos menores do que o esperado são devidos a um recurso do UNIX chamado "arquivos esparsos".
Arquivos maiores
Para ext2 / ext3, o uso em disco do arquivo inclui o espaço usado pelas estruturas do sistema de arquivos que controlam onde os blocos de dados estão no disco. Dê uma olhada em a estrutura de inode Ext2 - um inode é a estrutura de dados que controla as permissões de um arquivo, tamanho, etc, bem como onde seus blocos de dados estão no disco. O próprio inode não é contado para o uso (é pré-alocado na criação do sistema de arquivos), mas os blocos indiretos são.
Cálculo
Assim, o seu arquivo com tamanho 2390172kB recebe 597543 blocos de dados, como você disse. Os locais de 12 desses blocos são armazenados no próprio inode, então eles são gratuitos. O 13º local armazenado no inode é para um bloco indireto - um bloco recém-alocado que armazena os locais de 1024 blocos de dados. Então, isso adiciona 1 bloco ao seu tamanho de arquivo e nos deixa com 596507 blocos.
O 14º ponteiro de localização no inode é para um bloco duplamente indireto - um bloco alocado que contém espaço para os locais de 1024 blocos indiretos. 596507/1024 ~ = 582.52, então precisaremos de 583 blocos indiretos para conter o resto dos blocos de dados, além do bloco duplamente indireto.
Então:
1 (indirect from inode)
+ 1 (doubly-indirect from inode)
+ 583 (indirect from doubly-indirect)
-----
= 585
= 598128 - 597543
E isso representa o tamanho 2392512 (= 598128 * 4).
Arquivos menores
Eu suspeito que os arquivos menores (2389824kB) sejam arquivos esparsos, o que significa que alguns dos blocos nunca foram gravados e, portanto, não foram alocados - blocos não alocados são definidos como preenchidos com zeros. Veja a resposta de Dennis Williamson para referências. Arquivos esparsos podem ocorrer se a gravação do programa mover o ponteiro do arquivo e gravar em posições diferentes no arquivo, em vez de gravar o arquivo do início ao fim. Para um exemplo extremo de um arquivo esparso, tente o seguinte:
du if=/dev/zero of=my_sparse_file bs=1000 count=1 seek=1000000
Se você ls
do arquivo resultante, o tamanho aparente será 1000001000. No entanto, como apenas 1000 bytes foram gravados, apenas um bloco de dados é usado, portanto, apenas um bloco de dados é alocado. du
relatará 12kB usado - um bloco de 4k para os dados, um para o bloco duplamente indireto e um para um único bloco indireto ao qual o bloco duplamente indireto aponta com seu 976º ponteiro. Nenhum dos blocos restantes do arquivo foi alocado, seja dados ou metadados.
Quando o bloco duplamente indireto acabar, o sistema de arquivos começa a usar um bloco triplo indireto. Seu arquivo atingirá o tamanho máximo possível do sistema de arquivos ext3 antes de preenchê-lo.