web-dev-qa-db-fra.com

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

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

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

Mais chaque fois que je lance cette commande, je reçois 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?

MODIFIER:

Merci à de bonnes réponses dans ce sujet, je suis venu avec une solution qui lit 32 morceaux de 32 Mo de large qui fait 1 Go:

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

Une autre solution a été donnée qui lit 1 Go directement dans la mémoire, puis écrit sur le disque. Cette solution nécessite beaucoup de mémoire, elle n’est donc pas recommandée:

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

bs, la taille du tampon, signifie la taille d'un seul appel read () effectué par dd.

(Par exemple, bs=1M count=1 et bs=1k count=1k donneront un fichier de 1 MiB, mais la première version le fera en une seule étape, tandis que la seconde le fera en 1024 petits morceaux.)

Les fichiers normaux peuvent être lus à presque toutes les tailles de mémoire tampon (à condition que la mémoire tampon puisse tenir dans la RAM), mais les périphériques et les fichiers "virtuels" fonctionnent souvent très près des appels individuels et ont une restriction arbitraire quant à la quantité de données produite. read () appelle.

Pour /dev/urandom, cette limite est définie dans urandom_read () dans 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 serre 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 Mo et c'est tout. (Pour le réessayer 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'intégralité de la mémoire tampon doit tenir simultanément dans la mémoire. Par conséquent, les tailles de bloc massives correspondent également à une utilisation massive de la mémoire par dd.

Et tout cela est inutile, car vous n'obtiendrez généralement aucune performance lorsque vous dépassez environ 16 à 32 blocs MiB - les appels système ne sont pas la partie la plus lente ici, mais le générateur de nombres aléatoires.

Donc, pour simplifier, utilisez simplement head -c 1G /dev/urandom > output.

92
grawity

dd peut lire moins que ibs (remarque: bs spécifie à la fois ibs et obs), sauf si iflag=fullblock est spécifié. 0+1 records in indique que des blocs complets 0 et un bloc partiel 1 ont été lus. Cependant, tout blocage total ou partiel augmente le compteur.

Je ne connais pas le mécanisme exact qui permet à dd de lire un bloc inférieur à 1G dans ce cas particulier. J'imagine que tout bloc est lu dans la mémoire avant son écriture, la gestion de la mémoire peut donc interférer (mais ce n'est qu'une supposition). Edit: Cette réponse simultanée explique le mécanisme qui permet à dd de lire un bloc inférieur à 1G dans ce cas particulier.

Quoi qu'il en soit, je ne recommande pas un si grand bs. Je voudrais utiliser bs=1M count=1024. La chose la plus importante est: sans iflag=fullblock toute tentative de lecture peut lire moins que ibs (sauf si ibs=1, je pense, cela est assez inefficace cependant).

Donc, si vous avez besoin de lire une quantité exacte de données, utilisez iflag=fullblock. Note iflag n'est pas requis par POSIX, il est possible que votre dd ne le prenne pas en charge. Selon cette réponseibs=1 est probablement le seul moyen POSIX de lire un nombre exact d’octets. Bien sûr, si vous changez ibs, vous devrez alors recalculer la count. Dans votre cas, abaisser ibs à 32M ou moins résoudra probablement le problème, même sans iflag=fullblock.

Dans mon Kubuntu, je corrigerais votre commande comme ceci:

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