2

I try to access a file in android by native method, but i got "Invalid argument" after call read or write function. The data_ptr is align to 512 bytes and it is declared as byte array in java.

JNIEXPORT jint JNICALL

Java_com_aa_bb_NativeRead(JNIEnv* env, jobject clazz, jbyteArray data_ptr, jint length){
    int ret=0;
    jsize len = (*env)->GetArrayLength(env, data_ptr);
    jbyte *body = (*env)->GetByteArrayElements(env, data_ptr, 0);
    fd = open(filePath, O_CREAT | O_RDWR | O_DIRECT | O_SYNC, S_IRUSR | S_IWUSR);
    ret = read(fd, body, length);
    if(ret<0){
        LOGE("errno: %s\n", strerror(errno));
    }
    (*env)->ReleaseByteArrayElements(env, data_ptr, body, 0);
    return ret;
}

JNIEXPORT jint JNICALL

Java_com_aa_bb_NativeWrite(JNIEnv* env, jobject clazz, jbyteArray data_ptr, jint length){
    int ret=0;
    jsize len = (*env)->GetArrayLength(env, data_ptr);
    jbyte *body = (*env)->GetByteArrayElements(env, data_ptr, 0);
    fd = open(filePath, O_CREAT | O_RDWR | O_DIRECT | O_SYNC, S_IRUSR | S_IWUSR);
    ret = write(fd, body, length);
    if(ret<0){
        LOGE("errno: %s\n", strerror(errno));
    }
    (*env)->ReleaseByteArrayElements(env, data_ptr, body, 0);
    return ret;
}

Edit:

If I use open(filePath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); the error is disappear. But i want to use O_DIRECT for ignore cache&buffer to access hardware directly.

Hsin-Hsiang
  • 411
  • 1
  • 3
  • 13
  • And did the `open()`s succeed? – unwind Jan 27 '15 at 09:39
  • always (!) check the result of any open() function for success – Peter Miehle Jan 27 '15 at 09:42
  • Yes, open() is succeed. In the real function, i separate the open to anther function. – Hsin-Hsiang Jan 27 '15 at 09:44
  • Is `body` 512-byte aligned? Is `length` a multiple of 512 bytes? Are you sue that `GetByteArrayElements` will always return correctly aligned memory? Why do you want to use `O_DIRECT` anyway? "for ignore cache&buffer to access hardware directly" is not an explanation of why you want to use it, it's just restating what the flag does, but not why you want to do it. – Art Jan 27 '15 at 10:07
  • the len(it is data_ptr's length) is always multiple of 512 bytes. GetByteArrayElements I cannot sure... http://www.quora.com/How-can-I-bypass-the-OS-buffering-during-I-O-in-Linux I reference this link, which answered by Robert Love to add the O_DIRECT – Hsin-Hsiang Jan 27 '15 at 10:43

1 Answers1

1

O_DIRECT requires writes to be multiples of the underlying filesystem:

The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os. In Linux align‐ ment restrictions vary by filesystem and kernel version and might be absent entirely. However there is currently no filesystem-independent interface for an application to discover these restrictions for a given file or filesystem. Some filesystems provide their own interfaces for doing so, for example the XFS_IOC_DIOINFO operation in xfsctl(3).

Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file offset must all be multiples of the logical block size of the filesystem. Under Linux 2.6, alignment to 512-byte boundaries suffices.

GetByteArrayElements provides no such guarantees. It merely returns the address of the base of the primitive array of elements - in this case that's the address of the bytes in the byte array. These are allocated by the Java memory manager. You'll either have to copy the bytes (defeating the object of O_DIRECT), remove O_DIRECT or use some other strategy for allocation of the memory (such as allocating them yourself with mmap(..., MAP_ANON)).

abligh
  • 24,573
  • 4
  • 47
  • 84