How to memory map (mmap) a linux block device (e.g. /dev/sdb) in Java?

依然范特西╮ 提交于 2019-12-04 05:13:10

According to the documentation the mechanics of actually mapping a file are left to the implementation. It appears that the implementation is attempting to truncate the file (maybe because the block device size is not the same as the size you specify?).

I am curious why you are reading from the block device directly (unless you are trying to write some sort of filesystem utility or something that needs to do raw I/O). If you need to read from the block device as a memory mapped file directly, you may need to write some C/C++ code to map the file and handle reading/writing to it and use a Java/JNI bridge class to bridge calls to your C/C++ code. That way you handle calling mmap() yourself and can specify any options you need. Looking at the mmap() documentation you may not be able to specify block devices on your platform (I'm guessing Linux but I could be wrong).

If you absolutely need to do this within Java you may need to do read() calls and write() calls of the appropriate length and offset.

I found that the easiest approach is to use JNA and a bit of sun.*/com.sun.* magic. First of all you need to wrap libc like this:

import com.sun.jna.LastErrorException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

public interface LibC extends Library {
    LibC instance = (LibC) Native.loadLibrary("c", LibC.class);

    Pointer mmap(Pointer address, long length, 
                 int protect, int flags, int fd, 
                 long offset) throws LastErrorException;
    // implement more methods if you like
}

And then you are almost done! All you need is to obtain file descriptor. It may be a bit tricky:

RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
int fd = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess()
                               .get(randomAccessFile.getFD());

That's it. Now you can call libc from java:

Pointer result = LibC.instance.mmap(
    /*pass your desired parameters along with obtained fd*/
);

FileChannel.map attempts to truncate the file to the specified size: See the implementation

You will need to get the size of the block device and pass that exact size to the map call.

Don't worry if the size of the actual device is larger than your available memory. The OS will handle swapping pages in and out of memory as needed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!