51 votes

dd produit un fichier aléatoire de 32 Mo au lieu de 1 Go

Je voulais produire un fichier aléatoire de 1 Go, j'ai donc utilisé la commande suivante.

dd if=/dev/urandom of=output bs=1G count=1

Mais à chaque fois que je lance cette commande, j'obtiens un fichier de 32 Mo :

<11:58:40>$ dd if=/dev/urandom of=output bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB, 32 MiB) copied, 0,288321 s, 116 MB/s

Qu'est-ce qui ne va pas ?

EDITAR:

Grâce aux excellentes réponses de ce sujet, j'ai trouvé une solution qui lit 32 chunks de 32 MB de large, ce qui fait 1GB :

dd if=/dev/urandom of=output bs=32M count=32

Une autre solution a été proposée, qui consiste à lire 1 Go directement dans la mémoire, puis à écrire sur le disque. Cette solution prend beaucoup de mémoire et n'est donc pas préférée :

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock

95voto

James Mertz Points 390

bs La taille de la mémoire tampon correspond à la taille d'une seule image. lire() appel effectué par le dd.

(Par exemple, les deux bs=1M count=1 y bs=1k count=1k aboutira à un fichier de 1 Mio, mais la première version le fera en une seule étape, tandis que la seconde le fera en 1024 petits morceaux).

Les fichiers ordinaires peuvent être lus à presque n'importe quelle taille de tampon (tant que ce tampon tient dans la RAM), mais les périphériques et les fichiers "virtuels" travaillent souvent très près des appels individuels et ont une restriction arbitraire de la quantité de données qu'ils produiront par appel read().

Para /dev/urandom Cette limite est définie dans urandom_read() en drivers/char/random.c :

#define ENTROPY_SHIFT 3

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ...
}

Cela signifie que chaque fois que la fonction est appelée, elle réduit la taille demandée à 33554431 octets.

Par défaut, contrairement à la plupart des autres outils, dd ne réessayera pas après avoir reçu moins de données que demandé - vous obtenez les 32 MiB et c'est tout. (Pour qu'il réessaie automatiquement, comme dans la réponse de Kamil, vous devrez spécifier iflag=fullblock .)


Notez également que "la taille d'un seul read()" signifie que l'ensemble du tampon doit tenir dans la mémoire en une seule fois, de sorte que les tailles de bloc massives correspondent également à une utilisation massive de la mémoire en dd .

Et tout cela est inutile car vous ne gagnerez généralement pas en performance lorsque vous dépasserez les blocs de ~16-32 MiB - les syscalls ne sont pas la partie lente ici, c'est le générateur de nombres aléatoires qui l'est.

Pour simplifier, il suffit donc d'utiliser head -c 1G /dev/urandom > output .

22voto

Kamil Maciorowski Points 57004

dd peut être inférieur à ibs (note : bs spécifie à la fois ibs y obs ), sauf si iflag=fullblock est spécifié. 0+1 records in indique que 0 blocs complets et 1 un bloc partiel a été lu. Cependant, tout bloc complet ou partiel augmente le compteur.

Je ne connais pas le mécanisme exact qui permet à la dd lire un bloc inférieur à 1G dans ce cas particulier. Je suppose que tout bloc est lu dans la mémoire avant d'être écrit, de sorte que la gestion de la mémoire peut interférer (mais ce n'est qu'une supposition). Edita: cette réponse simultanée explique le mécanisme qui fait que dd lire un bloc inférieur à 1G dans ce cas particulier.

Quoi qu'il en soit, je ne recommande pas de telles bs . J'utiliserais bs=1M count=1024 . Le plus important, c'est que sans iflag=fullblock tous La tentative de lecture peut être inférieure à ibs (sauf si ibs=1 (je pense que c'est assez inefficace).

Ainsi, si vous avez besoin de lire une quantité exacte de données, utilisez iflag=fullblock . Note iflag n'est pas requis par POSIX, votre dd peut ne pas le supporter. D'après le cette réponse ibs=1 est probablement le seul moyen POSIX de lire un nombre exact d'octets. Bien sûr, si vous modifiez ibs vous devrez alors recalculer la valeur de la count . Dans votre cas, l'abaissement ibs à 32M ou moins résoudra probablement le problème, même sans l'aide de la iflag=fullblock .

Dans mon Kubuntu, je corrigerais votre commande comme suit :

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X