Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid argument for read-write mmap?

I'm getting -EINVAL for some reason, and it's not clear to me why. Here's where I open and attempt to mmap the file:

if ((fd = open(argv[1], O_RDWR)) < 0)
{
    fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno));
    return 1;
}

struct stat statbuf;
if (fstat(fd, &statbuf))
{
    fprintf(stderr, "stat filed: %s\n", strerror(errno));
    return 1;
}

char* fbase = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (fbase == MAP_FAILED)
{
    fprintf(stderr, "mmap failed: %s\n", strerror(errno));
    return 1;
}

EDIT: I should add, the error is occurring in the mmap.

like image 834
alexgolec Avatar asked Aug 24 '13 16:08

alexgolec


People also ask

Can mmap fail?

The mmap() function will fail if: [EACCES] The fildes argument is not open for read, regardless of the protection specified, or fildes is not open for write and PROT_WRITE was specified for a MAP_SHARED type mapping.

What does mmap do in Linux?

The mmap() function establishes a mapping between a process' address space and a stream file. The address space of the process from the address returned to the caller, for a length of len, is mapped onto a stream file starting at offset off.

What does mmap return?

Return Value Upon successful completion, the mmap() function returns the address at which the mapping was placed; otherwise, it returns a value of MAP_FAILED, which has a value of 0, and sets errno to indicate the error. The symbol MAP_FAILED is defined in the header <sys/mman.

Is mmap persistent?

mmap'd memory is not persistent between application executions (unless it is backed by a file).


2 Answers

Turns out changing the MAP_SHARED to MAP_PRIVATE allows this to succeed.

This reason this was failing is subtle: My code is running inside a VirtualBox VM, and the file I was attempting to mmap was in a shared directory on my host machine. The VirtualBox virtual filesystem apparently doesn't implement mmap with the MAP_SHARED option across the boundary of the hypervisor.

If you'll read jxh's helpful comments on both my question and on his answer, it turns out that this code was working for him because he was likely attempting to mmap a host filesystem file into the host memory.

My observation that switching from MAP_SHARED to MAP_PRIVATE is also consistent with this: since privately mapped memory is invisible to other processes, the virtual filesystem driver will probably have no objection to mapping the memory.

The solution was to move the file I wanted to map into the guest's hard drive and perform manipulation from there.

like image 160
alexgolec Avatar answered Nov 07 '22 13:11

alexgolec


Your statbuf.st_size is 0. mmap() will fail if the length parameter is 0.

There are 3 listed reasons for EINVAL error mmap():

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

...

  • We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).
  • (since Linux 2.6.12) length was 0.
  • flags contained neither MAP_PRIVATE or MAP_SHARED, or contained both of these values.
like image 16
jxh Avatar answered Nov 07 '22 11:11

jxh