changeset 6823:21528ae4d923

Merge
author coffeys
date Thu, 02 Jan 2014 15:26:53 +0000
parents a1f5b443727c 4e1095e23665
children 1331fa69ef12
files
diffstat 8 files changed, 229 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/nio/file/Files.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/share/classes/java/nio/file/Files.java	Thu Jan 02 15:26:53 2014 +0000
@@ -2978,13 +2978,13 @@
      *          method is invoked to check read access to the file.
      */
     public static byte[] readAllBytes(Path path) throws IOException {
-        try (FileChannel fc = FileChannel.open(path);
-             InputStream is = Channels.newInputStream(fc)) {
-            long size = fc.size();
+        try (SeekableByteChannel sbc = Files.newByteChannel(path);
+             InputStream in = Channels.newInputStream(sbc)) {
+            long size = sbc.size();
             if (size > (long)MAX_BUFFER_SIZE)
                 throw new OutOfMemoryError("Required array size too large");
 
-            return read(is, (int)size);
+            return read(in, (int)size);
         }
     }
 
--- a/src/windows/classes/sun/nio/fs/WindowsConstants.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/windows/classes/sun/nio/fs/WindowsConstants.java	Thu Jan 02 15:26:53 2014 +0000
@@ -100,6 +100,7 @@
     public static final int ERROR_INVALID_LEVEL         = 124;
     public static final int ERROR_DIR_NOT_EMPTY         = 145;
     public static final int ERROR_ALREADY_EXISTS        = 183;
+    public static final int ERROR_MORE_DATA             = 234;
     public static final int ERROR_DIRECTORY             = 267;
     public static final int ERROR_NOTIFY_ENUM_DIR       = 1022;
     public static final int ERROR_NONE_MAPPED           = 1332;
--- a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Thu Jan 02 15:26:53 2014 +0000
@@ -973,19 +973,19 @@
      * HANDLE CreateIoCompletionPort (
      *   HANDLE FileHandle,
      *   HANDLE ExistingCompletionPort,
-     *   DWORD CompletionKey,
+     *   ULONG_PTR CompletionKey,
      *   DWORD NumberOfConcurrentThreads
      * )
      */
     static native long CreateIoCompletionPort(long fileHandle, long existingPort,
-        int completionKey) throws WindowsException;
+        long completionKey) throws WindowsException;
 
 
     /**
      * GetQueuedCompletionStatus(
      *   HANDLE CompletionPort,
      *   LPDWORD lpNumberOfBytesTransferred,
-     *   LPDWORD lpCompletionKey,
+     *   PULONG_PTR lpCompletionKey,
      *   LPOVERLAPPED *lpOverlapped,
      *   DWORD dwMilliseconds
      */
@@ -999,12 +999,12 @@
     static class CompletionStatus {
         private int error;
         private int bytesTransferred;
-        private int completionKey;
+        private long completionKey;
         private CompletionStatus() { }
 
         int error() { return error; }
         int bytesTransferred() { return bytesTransferred; }
-        int completionKey() { return completionKey; }
+        long completionKey() { return completionKey; }
     }
     private static native void GetQueuedCompletionStatus0(long completionPort,
         CompletionStatus status) throws WindowsException;
@@ -1013,12 +1013,12 @@
      * PostQueuedCompletionStatus(
      *   HANDLE CompletionPort,
      *   DWORD dwNumberOfBytesTransferred,
-     *   DWORD dwCompletionKey,
+     *   ULONG_PTR dwCompletionKey,
      *   LPOVERLAPPED lpOverlapped
      * )
      */
     static native void PostQueuedCompletionStatus(long completionPort,
-        int completionKey) throws WindowsException;
+        long completionKey) throws WindowsException;
 
     /**
      * ReadDirectoryChangesW(
--- a/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Thu Jan 02 15:26:53 2014 +0000
@@ -41,6 +41,7 @@
 class WindowsWatchService
     extends AbstractWatchService
 {
+    private final static int WAKEUP_COMPLETION_KEY = 0;
     private final Unsafe unsafe = Unsafe.getUnsafe();
 
     // background thread to service I/O completion port
@@ -83,7 +84,7 @@
      */
     private class WindowsWatchKey extends AbstractWatchKey {
         // file key (used to detect existing registrations)
-        private FileKey fileKey;
+        private final FileKey fileKey;
 
         // handle to directory
         private volatile long handle = INVALID_HANDLE_VALUE;
@@ -223,8 +224,7 @@
             FileKey other = (FileKey)obj;
             if (this.volSerialNumber != other.volSerialNumber) return false;
             if (this.fileIndexHigh != other.fileIndexHigh) return false;
-            if (this.fileIndexLow != other.fileIndexLow) return false;
-            return true;
+            return this.fileIndexLow == other.fileIndexLow;
         }
     }
 
@@ -268,6 +268,7 @@
         private static final short OFFSETOF_FILENAME        = 12;
 
         // size of per-directory buffer for events (FIXME - make this configurable)
+        // Need to be less than 4*16384 = 65536. DWORD align.
         private static final int CHANGES_BUFFER_SIZE    = 16 * 1024;
 
         private final WindowsFileSystem fs;
@@ -275,27 +276,28 @@
         private final long port;
 
         // maps completion key to WatchKey
-        private final Map<Integer,WindowsWatchKey> int2key;
+        private final Map<Integer,WindowsWatchKey> ck2key;
 
         // maps file key to WatchKey
         private final Map<FileKey,WindowsWatchKey> fk2key;
 
         // unique completion key for each directory
+        // native completion key capacity is 64 bits on Win64.
         private int lastCompletionKey;
 
         Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
             this.fs = fs;
             this.watcher = watcher;
             this.port = port;
-            this.int2key = new HashMap<Integer,WindowsWatchKey>();
-            this.fk2key = new HashMap<FileKey,WindowsWatchKey>();
+            this.ck2key = new HashMap<>();
+            this.fk2key = new HashMap<>();
             this.lastCompletionKey = 0;
         }
 
         @Override
         void wakeup() throws IOException {
             try {
-                PostQueuedCompletionStatus(port, 0);
+                PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY);
             } catch (WindowsException x) {
                 throw new IOException(x.getMessage());
             }
@@ -322,7 +324,6 @@
             for (WatchEvent.Modifier modifier: modifiers) {
                 if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
                     watchSubtree = true;
-                    continue;
                 } else {
                     if (modifier == null)
                         return new NullPointerException();
@@ -333,7 +334,7 @@
             }
 
             // open directory
-            long handle = -1L;
+            long handle;
             try {
                 handle = CreateFile(dir.getPathForWin32Calls(),
                                     FILE_LIST_DIRECTORY,
@@ -347,7 +348,7 @@
             boolean registered = false;
             try {
                 // read attributes and check file is a directory
-                WindowsFileAttributes attrs = null;
+                WindowsFileAttributes attrs;
                 try {
                     attrs = WindowsFileAttributes.readAttributes(handle);
                 } catch (WindowsException x) {
@@ -370,9 +371,10 @@
                     return existing;
                 }
 
-                // unique completion key (skip 0)
+                // Can overflow the int type capacity.
+                // Skip WAKEUP_COMPLETION_KEY value.
                 int completionKey = ++lastCompletionKey;
-                if (completionKey == 0)
+                if (completionKey == WAKEUP_COMPLETION_KEY)
                     completionKey = ++lastCompletionKey;
 
                 // associate handle with completion port
@@ -418,13 +420,13 @@
                     // 1. remove mapping from old completion key to existing watch key
                     // 2. release existing key's resources (handle/buffer)
                     // 3. re-initialize key with new handle/buffer
-                    int2key.remove(existing.completionKey());
+                    ck2key.remove(existing.completionKey());
                     existing.releaseResources();
                     watchKey = existing.init(handle, events, watchSubtree, buffer,
                         countAddress, overlappedAddress, completionKey);
                 }
                 // map completion map to watch key
-                int2key.put(completionKey, watchKey);
+                ck2key.put(completionKey, watchKey);
 
                 registered = true;
                 return watchKey;
@@ -440,7 +442,7 @@
             WindowsWatchKey key = (WindowsWatchKey)obj;
             if (key.isValid()) {
                 fk2key.remove(key.fileKey());
-                int2key.remove(key.completionKey());
+                ck2key.remove(key.completionKey());
                 key.invalidate();
             }
         }
@@ -449,11 +451,11 @@
         @Override
         void implCloseAll() {
             // cancel all keys
-            for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) {
+            for (Map.Entry<Integer, WindowsWatchKey> entry: ck2key.entrySet()) {
                 entry.getValue().invalidate();
             }
             fk2key.clear();
-            int2key.clear();
+            ck2key.clear();
 
             // close I/O completion port
             CloseHandle(port);
@@ -517,7 +519,7 @@
         @Override
         public void run() {
             for (;;) {
-                CompletionStatus info = null;
+                CompletionStatus info;
                 try {
                     info = GetQueuedCompletionStatus(port);
                 } catch (WindowsException x) {
@@ -527,7 +529,7 @@
                 }
 
                 // wakeup
-                if (info.completionKey() == 0) {
+                if (info.completionKey() == WAKEUP_COMPLETION_KEY) {
                     boolean shutdown = processRequests();
                     if (shutdown) {
                         return;
@@ -536,7 +538,7 @@
                 }
 
                 // map completionKey to get WatchKey
-                WindowsWatchKey key = int2key.get(info.completionKey());
+                WindowsWatchKey key = ck2key.get((int)info.completionKey());
                 if (key == null) {
                     // We get here when a registration is changed. In that case
                     // the directory is closed which causes an event with the
@@ -544,38 +546,44 @@
                     continue;
                 }
 
-                // ReadDirectoryChangesW failed
-                if (info.error() != 0) {
+                boolean criticalError = false;
+                int errorCode = info.error();
+                int messageSize = info.bytesTransferred();
+                if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
                     // buffer overflow
-                    if (info.error() == ERROR_NOTIFY_ENUM_DIR) {
+                    key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
+                } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
+                    // ReadDirectoryChangesW failed
+                    criticalError = true;
+                } else {
+                    // ERROR_MORE_DATA is a warning about incomplite
+                    // data transfer over TCP/UDP stack. For the case
+                    // [messageSize] is zero in the most of cases.
+
+                    if (messageSize > 0) {
+                        // process non-empty events.
+                        processEvents(key, messageSize);
+                    } else if (errorCode == 0) {
+                        // insufficient buffer size
+                        // not described, but can happen.
                         key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
-                    } else {
-                        // other error so cancel key
-                        implCancelKey(key);
-                        key.signal();
                     }
-                    continue;
+
+                    // start read for next batch of changes
+                    try {
+                        ReadDirectoryChangesW(key.handle(),
+                                              key.buffer().address(),
+                                              CHANGES_BUFFER_SIZE,
+                                              key.watchSubtree(),
+                                              ALL_FILE_NOTIFY_EVENTS,
+                                              key.countAddress(),
+                                              key.overlappedAddress());
+                    } catch (WindowsException x) {
+                        // no choice but to cancel key
+                        criticalError = true;
+                    }
                 }
-
-                // process the events
-                if (info.bytesTransferred() > 0) {
-                    processEvents(key, info.bytesTransferred());
-                } else {
-                    // insufficient buffer size
-                    key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
-                }
-
-                // start read for next batch of changes
-                try {
-                    ReadDirectoryChangesW(key.handle(),
-                                          key.buffer().address(),
-                                          CHANGES_BUFFER_SIZE,
-                                          key.watchSubtree(),
-                                          ALL_FILE_NOTIFY_EVENTS,
-                                          key.countAddress(),
-                                          key.overlappedAddress());
-                } catch (WindowsException x) {
-                    // no choice but to cancel key
+                if (criticalError) {
                     implCancelKey(key);
                     key.signal();
                 }
--- a/src/windows/native/sun/nio/ch/SocketDispatcher.c	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/windows/native/sun/nio/ch/SocketDispatcher.c	Thu Jan 02 15:26:53 2014 +0000
@@ -192,45 +192,66 @@
                                          jobject fdo, jlong address, jint len)
 {
     /* set up */
-    int i = 0;
+    int next_index, next_offset, ret=0;
     DWORD written = 0;
     jint fd = fdval(env, fdo);
     struct iovec *iovp = (struct iovec *)address;
     WSABUF *bufs = malloc(len * sizeof(WSABUF));
-    jint rem = MAX_BUFFER_SIZE;
+    jlong count = 0;
 
     if (bufs == 0) {
         JNU_ThrowOutOfMemoryError(env, 0);
         return IOS_THROWN;
     }
 
-    /* copy iovec into WSABUF */
-    for(i=0; i<len; i++) {
-        jint iov_len = iovp[i].iov_len;
-        if (iov_len > rem)
-            iov_len = rem;
-        bufs[i].buf = (char *)iovp[i].iov_base;
-        bufs[i].len = (u_long)iov_len;
-        rem -= iov_len;
-        if (rem == 0) {
-            len = i+1;
+    // next buffer and offset to consume
+    next_index = 0;
+    next_offset = 0;
+
+    while (next_index  < len) {
+        DWORD buf_count = 0;
+
+        /* Prepare the WSABUF array to a maximum total size of MAX_BUFFER_SIZE */
+        jint rem = MAX_BUFFER_SIZE;
+        while (next_index < len && rem > 0) {
+            jint iov_len = iovp[next_index].iov_len - next_offset;
+            char* ptr = (char *)iovp[next_index].iov_base;
+            ptr += next_offset;
+            if (iov_len > rem) {
+                iov_len = rem;
+                next_offset += rem;
+            } else {
+                next_index ++;
+                next_offset = 0;
+            }
+
+            bufs[buf_count].buf = ptr;
+            bufs[buf_count].len = (u_long)iov_len;
+            buf_count++;
+
+            rem -= iov_len;
+        }
+
+        /* write the buffers */
+        ret = WSASend((SOCKET)fd,           /* Socket */
+                              bufs,         /* pointers to the buffers */
+                              buf_count,    /* number of buffers to process */
+                              &written,     /* receives number of bytes written */
+                              0,            /* no flags */
+                              0,            /* no overlapped sockets */
+                              0);           /* no completion routine */
+
+        if (ret == SOCKET_ERROR) {
             break;
         }
+
+        count += written;
     }
 
-    /* read into the buffers */
-    i = WSASend((SOCKET)fd, /* Socket */
-            bufs,           /* pointers to the buffers */
-            (DWORD)len,     /* number of buffers to process */
-            &written,       /* receives number of bytes written */
-            0,              /* no flags */
-            0,              /* no overlapped sockets */
-            0);             /* no completion routine */
-
     /* clean up */
     free(bufs);
 
-    if (i != 0) {
+    if (ret == SOCKET_ERROR && count == 0) {
         int theErr = (jint)WSAGetLastError();
         if (theErr == WSAEWOULDBLOCK) {
             return IOS_UNAVAILABLE;
@@ -239,7 +260,7 @@
         return IOS_THROWN;
     }
 
-    return convertLongReturnVal(env, (jlong)written, JNI_FALSE);
+    return convertLongReturnVal(env, count, JNI_FALSE);
 }
 
 JNIEXPORT void JNICALL
--- a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Thu Nov 21 13:39:01 2013 +0000
+++ b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Thu Jan 02 15:26:53 2014 +0000
@@ -162,7 +162,7 @@
     }
     completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
     completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
-    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I");
+    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
 
     clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
     if (clazz == NULL) {
@@ -1169,12 +1169,11 @@
 
 JNIEXPORT jlong JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
-    jlong fileHandle, jlong existingPort, jint completionKey)
+    jlong fileHandle, jlong existingPort, jlong completionKey)
 {
-    ULONG_PTR ck = completionKey;
     HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
                                          (HANDLE)jlong_to_ptr(existingPort),
-                                         ck,
+                                         (ULONG_PTR)completionKey,
                                          0);
     if (port == NULL) {
         throwWindowsException(env, GetLastError());
@@ -1203,21 +1202,20 @@
         (*env)->SetIntField(env, obj, completionStatus_error, ioResult);
         (*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
             (jint)bytesTransferred);
-        (*env)->SetIntField(env, obj, completionStatus_completionKey,
-            (jint)completionKey);
-
+        (*env)->SetLongField(env, obj, completionStatus_completionKey,
+            (jlong)completionKey);
     }
 }
 
 JNIEXPORT void JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
-    jlong completionPort, jint completionKey)
+    jlong completionPort, jlong completionKey)
 {
     BOOL res;
 
     res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
                                      (DWORD)0,  /* dwNumberOfBytesTransferred */
-                                     (DWORD)completionKey,
+                                     (ULONG_PTR)completionKey,
                                      NULL);  /* lpOverlapped */
     if (res == 0) {
         throwWindowsException(env, GetLastError());
@@ -1232,7 +1230,17 @@
     BOOL res;
     BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
 
-    ((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL;
+    /* Any unused members of [OVERLAPPED] structure should always be initialized to zero
+       before the structure is used in a function call.
+       Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
+       http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
+
+       The [Offset] and [OffsetHigh] members of this structure are not used.
+       http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
+
+       [hEvent] should be zero, other fields are the return values. */
+    ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED));
+
     res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
                                 (LPVOID)jlong_to_ptr(bufferAddress),
                                 (DWORD)bufferLength,
--- a/test/java/nio/channels/SocketChannel/ShortWrite.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/test/java/nio/channels/SocketChannel/ShortWrite.java	Thu Jan 02 15:26:53 2014 +0000
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 7176630
+ * @bug 7176630 7074436
  * @summary Check for short writes on SocketChannels configured in blocking mode
  */
 
@@ -40,9 +40,10 @@
     /**
      * Returns a checksum on the remaining bytes in the given buffer.
      */
-    static long computeChecksum(ByteBuffer bb) {
+    static long computeChecksum(ByteBuffer... bufs) {
         CRC32 crc32 = new CRC32();
-        crc32.update(bb.array());
+        for (int i=0; i<bufs.length; i++)
+            crc32.update(bufs[i].array());
         return crc32.getValue();
     }
 
@@ -71,15 +72,15 @@
     }
 
     /**
-     * Run test with a write of the given number of bytes.
+     * Exercise write(ByteBuffer) with given number of bytes.
      */
-    static void test(ExecutorService pool,
-                     SocketChannel source,
-                     SocketChannel sink,
-                     int size)
+    static void test1(ExecutorService pool,
+                      SocketChannel source,
+                      SocketChannel sink,
+                      int size)
         throws Exception
     {
-        System.out.println(size);
+        System.out.println("write(ByteBuffer), size=" + size);
 
         // random bytes in the buffer
         ByteBuffer buf = ByteBuffer.allocate(size);
@@ -101,6 +102,47 @@
             throw new RuntimeException("Checksum did not match");
     }
 
+    /**
+     * Exercise write(ByteBuffer[]) with buffers of the given sizes.
+     */
+    static void testN(ExecutorService pool,
+                      SocketChannel source,
+                      SocketChannel sink,
+                      int... sizes)
+        throws Exception
+    {
+        System.out.print("write(ByteBuffer[]), sizes=");
+        for (int size: sizes)
+            System.out.print(size + " ");
+        System.out.println();
+
+        int total = 0;
+        int len = sizes.length;
+        ByteBuffer[] bufs = new ByteBuffer[len];
+        for (int i=0; i<len; i++) {
+            int size = sizes[i];
+            ByteBuffer buf = ByteBuffer.allocate(size);
+            rand.nextBytes(buf.array());
+            bufs[i] = buf;
+            total += size;
+        }
+
+        // submit task to read the bytes
+        Future<Long> result = pool.submit(new Reader(sink, total));
+
+        // write the bytes
+        long n = source.write(bufs);
+        if (n != total)
+            throw new RuntimeException("Short write detected");
+
+        // check the bytes that were received match
+        for (int i=0; i<len; i++)
+            bufs[i].rewind();
+        long expected = computeChecksum(bufs);
+        long actual = result.get();
+        if (actual != expected)
+            throw new RuntimeException("Checksum did not match");
+    }
 
     public static void main(String[] args) throws Exception {
         ExecutorService pool = Executors.newSingleThreadExecutor();
@@ -114,17 +156,47 @@
                 try (SocketChannel source = SocketChannel.open(sa);
                      SocketChannel sink = ssc.accept())
                 {
-                    // run tests on sizes around 128k as that is the problem
-                    // area on Windows.
+                    // Exercise write(BufferBuffer) on sizes around 128k
                     int BOUNDARY = 128 * 1024;
                     for (int size=(BOUNDARY-2); size<=(BOUNDARY+2); size++) {
-                        test(pool, source, sink, size);
+                        test1(pool, source, sink, size);
                     }
 
-                    // run tests on random sizes
+                    // Exercise write(BufferBuffer) on random sizes
                     for (int i=0; i<20; i++) {
                         int size = rand.nextInt(1024*1024);
-                        test(pool, source, sink, size);
+                        test1(pool, source, sink, size);
+                    }
+
+                    // Exercise write(BufferBuffer[]) on sizes around 128k
+                    for (int i=BOUNDARY-2; i<=BOUNDARY+2; i++) {
+                        testN(pool, source, sink, i);
+                        testN(pool, source, sink, 0, i);
+                        testN(pool, source, sink, i, 0);
+                        for (int j=BOUNDARY-2; j<=BOUNDARY+2; j++) {
+                            testN(pool, source, sink, i, j);
+                            testN(pool, source, sink, 0, i, j);
+                            testN(pool, source, sink, i, 0, j);
+                            testN(pool, source, sink, i, j, 0);
+                            for (int k=BOUNDARY-2; k<=BOUNDARY+2; k++) {
+                                testN(pool, source, sink, i, j, k);
+                                testN(pool, source, sink, 0, i, j, k);
+                                testN(pool, source, sink, i, 0, j, k);
+                                testN(pool, source, sink, i, j, 0, k);
+                                testN(pool, source, sink, i, j, k, 0);
+                            }
+                        }
+                    }
+
+                    // Exercise write(BufferBuffer[]) on random sizes
+                    // (assumes IOV_MAX >= 8)
+                    for (int i=0; i<20; i++) {
+                        int n = rand.nextInt(9);
+                        int[] sizes = new int[n];
+                        for (int j=0; j<n; j++) {
+                            sizes[j] = rand.nextInt(1024*1024);
+                        }
+                        testN(pool, source, sink, sizes);
                     }
                 }
             }
--- a/test/java/nio/file/Files/BytesAndLines.java	Thu Nov 21 13:39:01 2013 +0000
+++ b/test/java/nio/file/Files/BytesAndLines.java	Thu Jan 02 15:26:53 2014 +0000
@@ -22,7 +22,9 @@
  */
 
 /* @test
- * @bug 7006126 8020669
+ * @bug 7006126 8020669 8024788
+ * @build BytesAndLines PassThroughFileSystem
+ * @run main BytesAndLines
  * @summary Unit test for methods for Files readAllBytes, readAllLines and
  *     and write methods.
  */
@@ -92,6 +94,16 @@
             byte[] data = Files.readAllBytes(pathStat);
             assertTrue(data.length > 0, "Files.readAllBytes('" + statFile + "') failed to read");
         }
+
+        // test readAllBytes on custom file system
+        Path myfile = PassThroughFileSystem.create().getPath(file.toString());
+        for (int size=0; size<=1024; size+=512) {
+            byte[] b1 = new byte[size];
+            rand.nextBytes(b1);
+            Files.write(myfile, b1);
+            byte[] b2 = Files.readAllBytes(myfile);
+            assertTrue(Arrays.equals(b1, b2), "bytes not equal");
+        }
     }