He estado trabajando con grandes archivos dispersos en openSUSE 11.2 x86_64. Cuando trato de mmap() un archivo escaso de 1TB, falla con ENOMEM. Hubiera pensado que el espacio de direcciones de 64 bits sería adecuado para mapear en un terabyte, pero parece que no. Experimentando aún más, un archivo de 1GB funciona bien, pero un archivo de 2GB (y algo más grande) falla. Supongo que podría haber un entorno en el que ajustar, pero una búsqueda exhaustiva no arroja nada.¿Por qué mmap() falla con ENOMEM en un archivo disperso de 1TB?
Aquí hay un código de muestra que muestra el problema, ¿alguna pista?
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char * filename = argv[1];
int fd;
off_t size = 1UL << 40; // 30 == 1GB, 40 == 1TB
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
ftruncate(fd, size);
printf("Created %ld byte sparse file\n", size);
char * buffer = (char *)mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("Done mmap - returned 0x0%lx\n", (unsigned long)buffer);
strcpy(buffer, "cafebabe");
printf("Wrote to start\n");
strcpy(buffer + (size - 9), "deadbeef");
printf("Wrote to end\n");
if (munmap(buffer, (size_t)size) < 0) {
perror("munmap");
exit(1);
}
close(fd);
return 0;
}
Como punto de interés, su programa funciona para mí hasta un tamaño de 256 GB ('1 << 38 '), con algo más alto que devuelve' EINVAL'. Esto está en RHEL4 (kernel 2.6.9-42.0.3.ELsmp). – caf
¿Qué dice ulimit -a? – bmargulies
Gracias, bmargulies, eso fue todo. ulimit: memoria virtual informada como 1804800 kbytes (poco más de 1,7 GB). ulimit -v 1610612736 (1.5TB) me permite mapear mi archivo disperso de 1TB. Responderé a mi propia pregunta para poder 'cerrarla' ... – metadaddy