28
28
#include "jvm.h"
29
29
#include "jlong.h"
30
30
31
+ #include "nio.h"
32
+
31
33
#include <stdio.h>
32
34
#include <string.h>
33
35
#include <dlfcn.h>
34
36
#include <errno.h>
35
37
#include <mntent.h>
36
38
#include <fcntl.h>
37
39
40
+ #include <sys/sendfile.h>
41
+
38
42
#include "sun_nio_fs_LinuxNativeDispatcher.h"
39
43
40
44
static jfieldID entry_name ;
41
45
static jfieldID entry_dir ;
42
46
static jfieldID entry_fstype ;
43
47
static jfieldID entry_options ;
44
48
49
+ typedef ssize_t copy_file_range_func (int , loff_t * , int , loff_t * , size_t ,
50
+ unsigned int );
51
+ static copy_file_range_func * my_copy_file_range_func = NULL ;
52
+
53
+ #define RESTARTABLE (_cmd , _result ) do { \
54
+ do { \
55
+ _result = _cmd; \
56
+ } while((_result == -1) && (errno == EINTR)); \
57
+ } while(0)
58
+
45
59
static void throwUnixException (JNIEnv * env , int errnum ) {
46
60
jobject x = JNU_NewObjectByName (env , "sun/nio/fs/UnixException" ,
47
61
"(I)V" , errnum );
@@ -63,6 +77,9 @@ Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz)
63
77
CHECK_NULL (entry_fstype );
64
78
entry_options = (* env )-> GetFieldID (env , clazz , "opts" , "[B" );
65
79
CHECK_NULL (entry_options );
80
+
81
+ my_copy_file_range_func =
82
+ (copy_file_range_func * ) dlsym (RTLD_DEFAULT , "copy_file_range" );
66
83
}
67
84
68
85
JNIEXPORT jlong JNICALL
@@ -150,3 +167,70 @@ Java_sun_nio_fs_LinuxNativeDispatcher_posix_1fadvise(JNIEnv* env, jclass this,
150
167
{
151
168
return posix_fadvise64 ((int )fd , (off64_t )offset , (off64_t )len , (int )advice );
152
169
}
170
+
171
+ // Copy all bytes from src to dst, within the kernel if possible,
172
+ // and return zero, otherwise return the appropriate status code.
173
+ //
174
+ // Return value
175
+ // 0 on success
176
+ // IOS_UNAVAILABLE if the platform function would block
177
+ // IOS_UNSUPPORTED_CASE if the call does not work with the given parameters
178
+ // IOS_UNSUPPORTED if direct copying is not supported on this platform
179
+ // IOS_THROWN if a Java exception is thrown
180
+ //
181
+ JNIEXPORT jint JNICALL
182
+ Java_sun_nio_fs_LinuxNativeDispatcher_directCopy0
183
+ (JNIEnv * env , jclass this , jint dst , jint src , jlong cancelAddress )
184
+ {
185
+ volatile jint * cancel = (jint * )jlong_to_ptr (cancelAddress );
186
+
187
+ // Transfer within the kernel
188
+ const size_t count = cancel != NULL ?
189
+ 1048576 : // 1 MB to give cancellation a chance
190
+ 0x7ffff000 ; // maximum number of bytes that sendfile() can transfer
191
+
192
+ ssize_t bytes_sent ;
193
+ if (my_copy_file_range_func != NULL ) {
194
+ do {
195
+ RESTARTABLE (my_copy_file_range_func (src , NULL , dst , NULL , count , 0 ),
196
+ bytes_sent );
197
+ if (bytes_sent < 0 ) {
198
+ switch (errno ) {
199
+ case EINVAL :
200
+ case ENOSYS :
201
+ case EXDEV :
202
+ // ignore and try sendfile()
203
+ break ;
204
+ default :
205
+ JNU_ThrowIOExceptionWithLastError (env , "Copy failed" );
206
+ return IOS_THROWN ;
207
+ }
208
+ }
209
+ if (cancel != NULL && * cancel != 0 ) {
210
+ throwUnixException (env , ECANCELED );
211
+ return IOS_THROWN ;
212
+ }
213
+ } while (bytes_sent > 0 );
214
+
215
+ if (bytes_sent == 0 )
216
+ return 0 ;
217
+ }
218
+
219
+ do {
220
+ RESTARTABLE (sendfile64 (dst , src , NULL , count ), bytes_sent );
221
+ if (bytes_sent < 0 ) {
222
+ if (errno == EAGAIN )
223
+ return IOS_UNAVAILABLE ;
224
+ if (errno == EINVAL || errno == ENOSYS )
225
+ return IOS_UNSUPPORTED_CASE ;
226
+ throwUnixException (env , errno );
227
+ return IOS_THROWN ;
228
+ }
229
+ if (cancel != NULL && * cancel != 0 ) {
230
+ throwUnixException (env , ECANCELED );
231
+ return IOS_THROWN ;
232
+ }
233
+ } while (bytes_sent > 0 );
234
+
235
+ return 0 ;
236
+ }
0 commit comments