8164900: Add support for O_DIRECT
authorbpb
Tue, 17 Oct 2017 16:51:11 -0700
changeset 47428 d72d7d55c765
parent 47427 251676148c62
child 47429 aa31c0a9ebca
8164900: Add support for O_DIRECT Summary: Add support for Direct I/O in FileChannel Reviewed-by: alanb, bpb, alanbur, coffeys, aph, clanger, plevart, mli, psandoz, simonis Contributed-by: Lucy Lu <yingqi.lu@intel.com>, Volker Simonis <volker.simonis@gmail.com>
make/gensrc/GensrcMisc.gmk
make/jprt.properties
make/mapfiles/libnio/mapfile-linux
make/mapfiles/libnio/mapfile-solaris
make/test/JtregNativeJdk.gmk
src/java.base/share/classes/java/nio/file/FileStore.java
src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java
src/java.base/share/classes/sun/nio/ch/FileDispatcher.java
src/java.base/share/classes/sun/nio/ch/IOUtil.java
src/java.base/share/classes/sun/nio/ch/Util.java
src/java.base/share/classes/sun/nio/fs/ExtendedOptions.java
src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java
src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java
src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java
src/java.base/unix/native/libnio/ch/FileChannelImpl.c
src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java
src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java
src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java
src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c
src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c
src/jdk.unsupported/share/classes/com/sun/nio/file/ExtendedOpenOption.java
test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java
test/jdk/java/nio/channels/FileChannel/directio/PreadDirect.java
test/jdk/java/nio/channels/FileChannel/directio/PwriteDirect.java
test/jdk/java/nio/channels/FileChannel/directio/ReadDirect.java
test/jdk/java/nio/channels/FileChannel/directio/WriteDirect.java
test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c
--- a/make/gensrc/GensrcMisc.gmk	Fri Oct 20 11:08:18 2017 -0700
+++ b/make/gensrc/GensrcMisc.gmk	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,7 @@
 define generate-preproc-src
 	$(call MakeDir, $(@D))
 	( $(NAWK) '/@@END_COPYRIGHT@@/{exit}1' $< && \
-	  $(CPP) $(CPP_FLAGS) $(SYSROOT_CFLAGS) $< \
+	  $(CPP) $(CPP_FLAGS) $(SYSROOT_CFLAGS) $(CFLAGS_JDKLIB) $< \
 	      2> >($(GREP) -v '^$(<F)$$' >&2) \
 	      | $(NAWK) '/@@START_HERE@@/,0' \
 	      |  $(SED) -e 's/@@START_HERE@@/\/\/ AUTOMATICALLY GENERATED FILE - DO NOT EDIT/' \
--- a/make/jprt.properties	Fri Oct 20 11:08:18 2017 -0700
+++ b/make/jprt.properties	Tue Oct 17 16:51:11 2017 -0700
@@ -180,7 +180,8 @@
   ${my.make.rule.test.targets.hotspot.reg}, \
   ${my.make.rule.test.targets.hotspot.gtest} \
   ${my.make.rule.test.targets.nativesanity} \
-  ${my.test.target.set:TESTNAME=jdk_lang}
+  ${my.test.target.set:TESTNAME=jdk_lang} \
+  ${my.test.target.set:TESTNAME=jdk_nio}
 
 # 7155453: Work-around to prevent popups on OSX from blocking test completion
 # but the work-around is added to all platforms to be consistent
--- a/make/mapfiles/libnio/mapfile-linux	Fri Oct 20 11:08:18 2017 -0700
+++ b/make/mapfiles/libnio/mapfile-linux	Tue Oct 17 16:51:11 2017 -0700
@@ -75,6 +75,7 @@
 		Java_sun_nio_ch_FileDispatcherImpl_truncate0;
                 Java_sun_nio_ch_FileDispatcherImpl_write0;
                 Java_sun_nio_ch_FileDispatcherImpl_writev0;
+                Java_sun_nio_ch_FileDispatcherImpl_setDirect0;
                 Java_sun_nio_ch_FileKey_init;
                 Java_sun_nio_ch_FileKey_initIDs;
 		Java_sun_nio_ch_InheritedChannel_close0;
--- a/make/mapfiles/libnio/mapfile-solaris	Fri Oct 20 11:08:18 2017 -0700
+++ b/make/mapfiles/libnio/mapfile-solaris	Tue Oct 17 16:51:11 2017 -0700
@@ -63,6 +63,7 @@
 		Java_sun_nio_ch_FileDispatcherImpl_truncate0;
                 Java_sun_nio_ch_FileDispatcherImpl_write0;
                 Java_sun_nio_ch_FileDispatcherImpl_writev0;
+                Java_sun_nio_ch_FileDispatcherImpl_setDirect0;
                 Java_sun_nio_ch_FileKey_init;
                 Java_sun_nio_ch_FileKey_initIDs;
 		Java_sun_nio_ch_InheritedChannel_close0;
--- a/make/test/JtregNativeJdk.gmk	Fri Oct 20 11:08:18 2017 -0700
+++ b/make/test/JtregNativeJdk.gmk	Tue Oct 17 16:51:11 2017 -0700
@@ -47,6 +47,10 @@
     $(TOPDIR)/test/jdk/java/lang/String/nativeEncoding \
     #
 
+ifneq ($(OPENJDK_TARGET_OS), windows)
+    BUILD_JDK_JTREG_NATIVE_SRC += $(TOPDIR)/test/jdk/java/nio/channels/FileChannel/directio
+endif
+
 BUILD_JDK_JTREG_OUTPUT_DIR := $(OUTPUTDIR)/support/test/jdk/jtreg/native
 
 BUILD_JDK_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/jdk/jtreg
@@ -56,8 +60,10 @@
     BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := $(WIN_LIB_JAVA)
 else ifeq ($(OPENJDK_TARGET_OS), solaris)
     BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava -lc
+    BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava -lc
 else
     BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
+    BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
 endif
 
 $(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \
--- a/src/java.base/share/classes/java/nio/file/FileStore.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/java/nio/file/FileStore.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -112,6 +112,31 @@
     public abstract long getUsableSpace() throws IOException;
 
     /**
+     * Returns the number of bytes per block in this file store.
+     *
+     * <p> File storage is typically organized into discrete sequences of bytes
+     * called <i>blocks</i>. A block is the smallest storage unit of a file store.
+     * Every read and write operation is performed on a multiple of blocks.
+     *
+     * @implSpec The implementation in this class throws an
+     *         {@code UnsupportedOperationException}.
+     *
+     * @return  a positive value representing the block size of this file store,
+     *          in bytes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     *
+     * @throws  UnsupportedOperationException
+     *          if the operation is not supported
+     *
+     * @since 10
+     */
+    public long getBlockSize() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Returns the number of unallocated bytes in the file store.
      *
      * <p> The returned number of unallocated bytes is a hint, but not a
--- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java	Tue Oct 17 16:51:11 2017 -0700
@@ -41,6 +41,11 @@
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.WritableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystemException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -87,6 +92,12 @@
     // Positional-read is not interruptible
     private volatile boolean uninterruptible;
 
+    // DirectIO flag
+    private final boolean direct;
+
+    // IO alignment value for DirectIO
+    private final int alignment;
+
     // Cleanable with an action which closes this channel's file descriptor
     private final Cleanable closer;
 
@@ -103,14 +114,22 @@
     }
 
     private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
-                            boolean writable, Object parent)
+                            boolean writable, boolean direct, Object parent)
     {
         this.fd = fd;
         this.readable = readable;
         this.writable = writable;
         this.parent = parent;
         this.path = path;
+        this.direct = direct;
         this.nd = new FileDispatcherImpl();
+        if (direct) {
+            assert path != null;
+            this.alignment = nd.setDirectIO(fd, path);
+        } else {
+            this.alignment = -1;
+        }
+
         // Register a cleaning action if and only if there is no parent
         // as the parent will take care of closing the file descriptor.
         // FileChannel is used by the LambdaMetaFactory so a lambda cannot
@@ -125,7 +144,14 @@
                                    boolean readable, boolean writable,
                                    Object parent)
     {
-        return new FileChannelImpl(fd, path, readable, writable, parent);
+        return new FileChannelImpl(fd, path, readable, writable, false, parent);
+    }
+
+    public static FileChannel open(FileDescriptor fd, String path,
+                                   boolean readable, boolean writable,
+                                   boolean direct, Object parent)
+    {
+        return new FileChannelImpl(fd, path, readable, writable, direct, parent);
     }
 
     private void ensureOpen() throws IOException {
@@ -181,6 +207,8 @@
         if (!readable)
             throw new NonReadableChannelException();
         synchronized (positionLock) {
+            if (direct)
+                Util.checkChannelPositionAligned(position(), alignment);
             int n = 0;
             int ti = -1;
             try {
@@ -189,7 +217,7 @@
                 if (!isOpen())
                     return 0;
                 do {
-                    n = IOUtil.read(fd, dst, -1, nd);
+                    n = IOUtil.read(fd, dst, -1, direct, alignment, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
                 return IOStatus.normalize(n);
             } finally {
@@ -209,6 +237,8 @@
         if (!readable)
             throw new NonReadableChannelException();
         synchronized (positionLock) {
+            if (direct)
+                Util.checkChannelPositionAligned(position(), alignment);
             long n = 0;
             int ti = -1;
             try {
@@ -217,7 +247,8 @@
                 if (!isOpen())
                     return 0;
                 do {
-                    n = IOUtil.read(fd, dsts, offset, length, nd);
+                    n = IOUtil.read(fd, dsts, offset, length,
+                            direct, alignment, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
                 return IOStatus.normalize(n);
             } finally {
@@ -233,6 +264,8 @@
         if (!writable)
             throw new NonWritableChannelException();
         synchronized (positionLock) {
+            if (direct)
+                Util.checkChannelPositionAligned(position(), alignment);
             int n = 0;
             int ti = -1;
             try {
@@ -241,7 +274,7 @@
                 if (!isOpen())
                     return 0;
                 do {
-                    n = IOUtil.write(fd, src, -1, nd);
+                    n = IOUtil.write(fd, src, -1, direct, alignment, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
                 return IOStatus.normalize(n);
             } finally {
@@ -261,6 +294,8 @@
         if (!writable)
             throw new NonWritableChannelException();
         synchronized (positionLock) {
+            if (direct)
+                Util.checkChannelPositionAligned(position(), alignment);
             long n = 0;
             int ti = -1;
             try {
@@ -269,7 +304,8 @@
                 if (!isOpen())
                     return 0;
                 do {
-                    n = IOUtil.write(fd, srcs, offset, length, nd);
+                    n = IOUtil.write(fd, srcs, offset, length,
+                            direct, alignment, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
                 return IOStatus.normalize(n);
             } finally {
@@ -752,6 +788,8 @@
             throw new IllegalArgumentException("Negative position");
         if (!readable)
             throw new NonReadableChannelException();
+        if (direct)
+            Util.checkChannelPositionAligned(position, alignment);
         ensureOpen();
         if (nd.needsPositionLock()) {
             synchronized (positionLock) {
@@ -774,7 +812,7 @@
             if (!isOpen())
                 return -1;
             do {
-                n = IOUtil.read(fd, dst, position, nd);
+                n = IOUtil.read(fd, dst, position, direct, alignment, nd);
             } while ((n == IOStatus.INTERRUPTED) && isOpen());
             return IOStatus.normalize(n);
         } finally {
@@ -791,6 +829,8 @@
             throw new IllegalArgumentException("Negative position");
         if (!writable)
             throw new NonWritableChannelException();
+        if (direct)
+            Util.checkChannelPositionAligned(position, alignment);
         ensureOpen();
         if (nd.needsPositionLock()) {
             synchronized (positionLock) {
@@ -811,7 +851,7 @@
             if (!isOpen())
                 return -1;
             do {
-                n = IOUtil.write(fd, src, position, nd);
+                n = IOUtil.write(fd, src, position, direct, alignment, nd);
             } while ((n == IOStatus.INTERRUPTED) && isOpen());
             return IOStatus.normalize(n);
         } finally {
--- a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,4 +61,6 @@
     abstract boolean canTransferToDirectly(SelectableChannel sc);
 
     abstract boolean transferToDirectlyNeedsPositionLock();
+
+    abstract int setDirectIO(FileDescriptor fd, String path);
 }
--- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,22 +47,38 @@
                      NativeDispatcher nd)
         throws IOException
     {
-        if (src instanceof DirectBuffer)
-            return writeFromNativeBuffer(fd, src, position, nd);
+        return write(fd, src, position, false, -1, nd);
+    }
+
+    static int write(FileDescriptor fd, ByteBuffer src, long position,
+                     boolean directIO, int alignment, NativeDispatcher nd)
+        throws IOException
+    {
+        if (src instanceof DirectBuffer) {
+            return writeFromNativeBuffer(fd, src, position,
+                                         directIO, alignment, nd);
+        }
 
         // Substitute a native buffer
         int pos = src.position();
         int lim = src.limit();
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
-        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+        ByteBuffer bb;
+        if (directIO) {
+            Util.checkRemainingBufferSizeAligned(rem, alignment);
+            bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
+        } else {
+            bb = Util.getTemporaryDirectBuffer(rem);
+        }
         try {
             bb.put(src);
             bb.flip();
             // Do not update src until we see how many bytes were written
             src.position(pos);
 
-            int n = writeFromNativeBuffer(fd, bb, position, nd);
+            int n = writeFromNativeBuffer(fd, bb, position,
+                    directIO, alignment, nd);
             if (n > 0) {
                 // now update src
                 src.position(pos + n);
@@ -74,7 +90,8 @@
     }
 
     private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
-                                             long position, NativeDispatcher nd)
+                                             long position, boolean directIO,
+                                             int alignment, NativeDispatcher nd)
         throws IOException
     {
         int pos = bb.position();
@@ -82,6 +99,11 @@
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
 
+        if (directIO) {
+            Util.checkBufferPositionAligned(bb, pos, alignment);
+            Util.checkRemainingBufferSizeAligned(rem, alignment);
+        }
+
         int written = 0;
         if (rem == 0)
             return 0;
@@ -100,13 +122,20 @@
     static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
         throws IOException
     {
-        return write(fd, bufs, 0, bufs.length, nd);
+        return write(fd, bufs, 0, bufs.length, false, -1, nd);
     }
 
     static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
                       NativeDispatcher nd)
         throws IOException
     {
+        return write(fd, bufs, offset, length, false, -1, nd);
+    }
+
+    static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+                      boolean directIO, int alignment, NativeDispatcher nd)
+        throws IOException
+    {
         IOVecWrapper vec = IOVecWrapper.get(length);
 
         boolean completed = false;
@@ -122,12 +151,20 @@
                 int lim = buf.limit();
                 assert (pos <= lim);
                 int rem = (pos <= lim ? lim - pos : 0);
+                if (directIO)
+                    Util.checkRemainingBufferSizeAligned(rem, alignment);
+
                 if (rem > 0) {
                     vec.setBuffer(iov_len, buf, pos, rem);
 
                     // allocate shadow buffer to ensure I/O is done with direct buffer
                     if (!(buf instanceof DirectBuffer)) {
-                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+                        ByteBuffer shadow;
+                        if (directIO)
+                            shadow = Util.getTemporaryAlignedDirectBuffer(rem,
+                                    alignment);
+                        else
+                            shadow = Util.getTemporaryDirectBuffer(rem);
                         shadow.put(buf);
                         shadow.flip();
                         vec.setShadow(iov_len, shadow);
@@ -186,15 +223,32 @@
                     NativeDispatcher nd)
         throws IOException
     {
+        return read(fd, dst, position, false, -1, nd);
+    }
+
+    static int read(FileDescriptor fd, ByteBuffer dst, long position,
+                    boolean directIO, int alignment, NativeDispatcher nd)
+        throws IOException
+    {
         if (dst.isReadOnly())
             throw new IllegalArgumentException("Read-only buffer");
         if (dst instanceof DirectBuffer)
-            return readIntoNativeBuffer(fd, dst, position, nd);
+            return readIntoNativeBuffer(fd, dst, position,
+                    directIO, alignment, nd);
 
         // Substitute a native buffer
-        ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
+        ByteBuffer bb;
+        int rem = dst.remaining();
+        if (directIO) {
+            Util.checkRemainingBufferSizeAligned(rem, alignment);
+            bb = Util.getTemporaryAlignedDirectBuffer(rem,
+                                                      alignment);
+        } else {
+            bb = Util.getTemporaryDirectBuffer(rem);
+        }
         try {
-            int n = readIntoNativeBuffer(fd, bb, position, nd);
+            int n = readIntoNativeBuffer(fd, bb, position,
+                    directIO, alignment,nd);
             bb.flip();
             if (n > 0)
                 dst.put(bb);
@@ -205,7 +259,8 @@
     }
 
     private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
-                                            long position, NativeDispatcher nd)
+                                            long position, boolean directIO,
+                                            int alignment, NativeDispatcher nd)
         throws IOException
     {
         int pos = bb.position();
@@ -213,6 +268,11 @@
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
 
+        if (directIO) {
+            Util.checkBufferPositionAligned(bb, pos, alignment);
+            Util.checkRemainingBufferSizeAligned(rem, alignment);
+        }
+
         if (rem == 0)
             return 0;
         int n = 0;
@@ -230,13 +290,20 @@
     static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
         throws IOException
     {
-        return read(fd, bufs, 0, bufs.length, nd);
+        return read(fd, bufs, 0, bufs.length, false, -1, nd);
     }
 
     static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
                      NativeDispatcher nd)
         throws IOException
     {
+        return read(fd, bufs, offset, bufs.length, false, -1, nd);
+    }
+
+    static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+                     boolean directIO, int alignment, NativeDispatcher nd)
+        throws IOException
+    {
         IOVecWrapper vec = IOVecWrapper.get(length);
 
         boolean completed = false;
@@ -255,12 +322,21 @@
                 assert (pos <= lim);
                 int rem = (pos <= lim ? lim - pos : 0);
 
+                if (directIO)
+                    Util.checkRemainingBufferSizeAligned(rem, alignment);
+
                 if (rem > 0) {
                     vec.setBuffer(iov_len, buf, pos, rem);
 
                     // allocate shadow buffer to ensure I/O is done with direct buffer
                     if (!(buf instanceof DirectBuffer)) {
-                        ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+                        ByteBuffer shadow;
+                        if (directIO) {
+                            shadow = Util.getTemporaryAlignedDirectBuffer(rem,
+                                    alignment);
+                        } else {
+                            shadow = Util.getTemporaryDirectBuffer(rem);
+                        }
                         vec.setShadow(iov_len, shadow);
                         buf = shadow;
                         pos = shadow.position();
--- a/src/java.base/share/classes/sun/nio/ch/Util.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/Util.java	Tue Oct 17 16:51:11 2017 -0700
@@ -37,7 +37,7 @@
 import java.util.Set;
 import jdk.internal.misc.Unsafe;
 import sun.security.action.GetPropertyAction;
-
+import java.io.IOException;
 
 public class Util {
 
@@ -237,6 +237,33 @@
     }
 
     /**
+     * Returns a temporary buffer of at least the given size and
+     * aligned to the alignment
+     */
+    public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
+                                                             int alignment) {
+        if (isBufferTooLarge(size)) {
+            return ByteBuffer.allocateDirect(size + alignment - 1)
+                    .alignedSlice(alignment);
+        }
+
+        BufferCache cache = bufferCache.get();
+        ByteBuffer buf = cache.get(size);
+        if (buf != null) {
+            if (buf.alignmentOffset(0, alignment) == 0) {
+                return buf;
+            }
+        } else {
+            if (!cache.isEmpty()) {
+                buf = cache.removeFirst();
+                free(buf);
+            }
+        }
+        return ByteBuffer.allocateDirect(size + alignment - 1)
+                .alignedSlice(alignment);
+    }
+
+    /**
      * Releases a temporary buffer by returning to the cache or freeing it.
      */
     public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
@@ -459,4 +486,37 @@
         }
         return dbb;
     }
+
+    static void checkBufferPositionAligned(ByteBuffer bb,
+                                                     int pos, int alignment)
+        throws IOException
+    {
+        if (bb.alignmentOffset(pos, alignment) != 0) {
+            throw new IOException("Current location of the bytebuffer ("
+                + pos + ") is not a multiple of the block size ("
+                + alignment + ")");
+        }
+    }
+
+    static void checkRemainingBufferSizeAligned(int rem,
+                                                          int alignment)
+        throws IOException
+    {
+        if (rem % alignment != 0) {
+            throw new IOException("Number of remaining bytes ("
+                + rem + ") is not a multiple of the block size ("
+                + alignment + ")");
+        }
+    }
+
+    static void checkChannelPositionAligned(long position,
+                                                      int alignment)
+        throws IOException
+    {
+        if (position % alignment != 0) {
+           throw new IOException("Channel position (" + position
+               + ") is not a multiple of the block size ("
+               + alignment + ")");
+        }
+    }
 }
--- a/src/java.base/share/classes/sun/nio/fs/ExtendedOptions.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/fs/ExtendedOptions.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -137,6 +137,8 @@
 
     public static final InternalOption<Void> FILE_TREE = new InternalOption<>();
 
+    public static final InternalOption<Void> DIRECT = new InternalOption<>();
+
     public static final InternalOption<Integer> SENSITIVITY_HIGH = new InternalOption<>();
     public static final InternalOption<Integer> SENSITIVITY_MEDIUM = new InternalOption<>();
     public static final InternalOption<Integer> SENSITIVITY_LOW = new InternalOption<>();
--- a/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java	Tue Oct 17 16:51:11 2017 -0700
@@ -122,6 +122,17 @@
         return false;
     }
 
+    int setDirectIO(FileDescriptor fd, String path) {
+        int result = -1;
+        try {
+            result = setDirect0(fd);
+        } catch (IOException e) {
+            throw new UnsupportedOperationException
+                ("Error setting up DirectIO", e);
+        }
+        return result;
+    }
+
     // -- Native methods --
 
     static native int read0(FileDescriptor fd, long address, int len)
@@ -167,6 +178,8 @@
 
     static native void closeIntFD(int fd) throws IOException;
 
+    static native int setDirect0(FileDescriptor fd) throws IOException;
+
     static native void init();
 
 }
--- a/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,7 @@
         boolean deleteOnClose;
         boolean sync;
         boolean dsync;
+        boolean direct;
 
         static Flags toFlags(Set<? extends OpenOption> options) {
             Flags flags = new Flags();
@@ -88,6 +89,12 @@
                     flags.noFollowLinks = true;
                     continue;
                 }
+
+                if (ExtendedOptions.DIRECT.matches(option)) {
+                    flags.direct = true;
+                    continue;
+                }
+
                 if (option == null)
                     throw new NullPointerException();
                throw new UnsupportedOperationException(option + " not supported");
@@ -134,7 +141,8 @@
             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
 
         FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
-        return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, null);
+        return FileChannelImpl.open(fdObj, path.toString(), flags.read,
+                flags.write, flags.direct, null);
     }
 
     /**
@@ -235,6 +243,8 @@
             oflags |= O_DSYNC;
         if (flags.sync)
             oflags |= O_SYNC;
+        if (flags.direct)
+            oflags |= O_DIRECT;
 
         // permission check before we open the file
         SecurityManager sm = System.getSecurityManager();
--- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -70,6 +70,12 @@
     static final int PREFIX_O_NOFOLLOW = 00;
 #endif
 
+#ifdef O_DIRECT
+    static final int PREFIX_O_DIRECT = O_DIRECT;
+#else
+    // not supported (dummy values will not be used at runtime).
+    static final int PREFIX_O_DIRECT = 00;
+#endif
 
     static final int PREFIX_S_IAMB =
         (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -126,6 +126,12 @@
     }
 
     @Override
+    public long getBlockSize() throws IOException {
+       UnixFileStoreAttributes attrs = readAttributes();
+       return attrs.blockSize();
+    }
+
+    @Override
     public long getUnallocatedSpace() throws IOException {
         UnixFileStoreAttributes attrs = readAttributes();
         return attrs.blockSize() * attrs.freeBlocks();
--- a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c	Tue Oct 17 16:51:11 2017 -0700
@@ -50,7 +50,7 @@
 #define mmap64 mmap
 #endif
 
-static jfieldID chan_fd;        /* jobject 'fd' in sun.io.FileChannelImpl */
+static jfieldID chan_fd;        /* jobject 'fd' in sun.nio.ch.FileChannelImpl */
 
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz)
--- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c	Tue Oct 17 16:51:11 2017 -0700
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <sys/statvfs.h>
 #if defined(__linux__)
 #include <linux/fs.h>
 #include <sys/ioctl.h>
@@ -323,3 +324,58 @@
 {
     closeFileDescriptor(env, fd);
 }
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz,
+                                           jobject fdo)
+{
+    jint fd = fdval(env, fdo);
+    jint result;
+#ifdef MACOSX
+    struct statvfs file_stat;
+#else
+    struct statvfs64 file_stat;
+#endif
+
+#if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON)
+#ifdef O_DIRECT
+    jint orig_flag;
+    orig_flag = fcntl(fd, F_GETFL);
+    if (orig_flag == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        return -1;
+    }
+    result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT);
+    if (result == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        return result;
+    }
+#elif F_NOCACHE
+    result = fcntl(fd, F_NOCACHE, 1);
+    if (result == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        return result;
+    }
+#elif DIRECTIO_ON
+    result = directio(fd, DIRECTIO_ON);
+    if (result == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        return result;
+    }
+#endif
+#ifdef MACOSX
+    result = fstatvfs(fd, &file_stat);
+#else
+    result = fstatvfs64(fd, &file_stat);
+#endif
+    if(result == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        return result;
+    } else {
+        result = (int)file_stat.f_frsize;
+    }
+#else
+    result == -1;
+#endif
+    return result;
+}
--- a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java	Tue Oct 17 16:51:11 2017 -0700
@@ -30,6 +30,8 @@
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.JavaIOFileDescriptorAccess;
 import sun.security.action.GetPropertyAction;
+import java.io.File;
+import java.nio.CharBuffer;
 
 class FileDispatcherImpl extends FileDispatcher {
 
@@ -123,6 +125,21 @@
         return true;
     }
 
+    int setDirectIO(FileDescriptor fd, String path)
+    {
+        int result = -1;
+        String filePath = path.substring(0, path.lastIndexOf(File.separator));
+        CharBuffer buffer = CharBuffer.allocate(filePath.length());
+        buffer.put(filePath);
+        try {
+            result = setDirect0(fd, buffer);
+        } catch (IOException e) {
+            throw new UnsupportedOperationException
+                ("Error setting up DirectIO", e);
+        }
+        return result;
+    }
+
     static boolean isFastFileTransferRequested() {
         String fileTransferProp = GetPropertyAction
                 .privilegedGetProperty("jdk.nio.enableFastFileTransfer");
@@ -177,4 +194,6 @@
     static native void close0(FileDescriptor fd) throws IOException;
 
     static native long duplicateHandle(long fd) throws IOException;
+
+    static native int setDirect0(FileDescriptor fd, CharBuffer buffer) throws IOException;
 }
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,7 @@
         boolean overlapped;
         boolean sync;
         boolean dsync;
+        boolean direct;
 
         // non-standard
         boolean shareRead = true;
@@ -121,6 +122,10 @@
                     flags.shareDelete = false;
                     continue;
                 }
+                if (ExtendedOptions.DIRECT.matches(option)) {
+                    flags.direct = true;
+                    continue;
+                }
                 if (option == null)
                     throw new NullPointerException();
                 throw new UnsupportedOperationException();
@@ -161,7 +166,8 @@
             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
 
         FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
-        return FileChannelImpl.open(fdObj, pathForWindows, flags.read, flags.write, null);
+        return FileChannelImpl.open(fdObj, pathForWindows, flags.read,
+                flags.write, flags.direct, null);
     }
 
     /**
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,9 +125,18 @@
     }
 
     // read the free space info
+    private DiskFreeSpace readDiskFreeSpaceEx() throws IOException {
+        try {
+            return GetDiskFreeSpaceEx(root);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(root);
+            return null;
+        }
+    }
+
     private DiskFreeSpace readDiskFreeSpace() throws IOException {
         try {
-            return GetDiskFreeSpaceEx(root);
+            return GetDiskFreeSpace(root);
         } catch (WindowsException x) {
             x.rethrowAsIOException(root);
             return null;
@@ -136,17 +145,21 @@
 
     @Override
     public long getTotalSpace() throws IOException {
-        return readDiskFreeSpace().totalNumberOfBytes();
+        return readDiskFreeSpaceEx().totalNumberOfBytes();
     }
 
     @Override
     public long getUsableSpace() throws IOException {
-        return readDiskFreeSpace().freeBytesAvailable();
+        return readDiskFreeSpaceEx().freeBytesAvailable();
+    }
+
+    public long getBlockSize() throws IOException {
+        return readDiskFreeSpace().bytesPerSector();
     }
 
     @Override
     public long getUnallocatedSpace() throws IOException {
-        return readDiskFreeSpace().freeBytesAvailable();
+        return readDiskFreeSpaceEx().freeBytesAvailable();
     }
 
     @Override
@@ -165,6 +178,8 @@
             return getUsableSpace();
         if (attribute.equals("unallocatedSpace"))
             return getUnallocatedSpace();
+        if (attribute.equals("bytesPerSector"))
+            return getBlockSize();
         // windows specific for testing purposes
         if (attribute.equals("volume:vsn"))
             return volInfo.volumeSerialNumber();
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -485,21 +485,50 @@
             buffer.release();
         }
     }
+
+    /**
+     * GetDiskFreeSpace(
+     *   LPCTSTR lpRootPathName,
+     *   LPDWORD lpSectorsPerCluster,
+     *   LPDWORD lpBytesPerSector,
+     *   LPDWORD lpNumberOfFreeClusters,
+     *   LPDWORD lpTotalNumberOfClusters
+     * )
+     */
+    static DiskFreeSpace GetDiskFreeSpace(String path)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            DiskFreeSpace space = new DiskFreeSpace();
+            GetDiskFreeSpace0(buffer.address(), space);
+            return space;
+        } finally {
+            buffer.release();
+        }
+    }
+
     static class DiskFreeSpace {
         private long freeBytesAvailable;
         private long totalNumberOfBytes;
         private long totalNumberOfFreeBytes;
+        private long bytesPerSector;
         private DiskFreeSpace() { }
 
         public long freeBytesAvailable()      { return freeBytesAvailable; }
         public long totalNumberOfBytes()      { return totalNumberOfBytes; }
         public long totalNumberOfFreeBytes()  { return totalNumberOfFreeBytes; }
+        public long bytesPerSector()          { return bytesPerSector; }
     }
     private static native void GetDiskFreeSpaceEx0(long lpDirectoryName,
                                                    DiskFreeSpace obj)
         throws WindowsException;
 
 
+    private static native void GetDiskFreeSpace0(long lpRootPathName,
+                                                 DiskFreeSpace obj)
+        throws WindowsException;
+
     /**
      * GetVolumePathName(
      *   LPCTSTR lpszFileName,
--- a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c	Tue Oct 17 16:51:11 2017 -0700
@@ -456,3 +456,33 @@
        JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
     return ptr_to_jlong(hResult);
 }
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this,
+                                              jobject fdObj, jobject buffer)
+{
+    jint result = -1;
+
+    HANDLE orig = (HANDLE)(handleval(env, fdObj));
+
+    HANDLE modify = ReOpenFile(orig, 0, 0,
+            FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH);
+
+    if (modify != INVALID_HANDLE_VALUE) {
+        DWORD sectorsPerCluster;
+        DWORD bytesPerSector;
+        DWORD numberOfFreeClusters;
+        DWORD totalNumberOfClusters;
+        LPCWSTR lpRootPathName = (*env)->GetDirectBufferAddress(env, buffer);
+        BOOL res = GetDiskFreeSpaceW(lpRootPathName,
+                                     &sectorsPerCluster,
+                                     &bytesPerSector,
+                                     &numberOfFreeClusters,
+                                     &totalNumberOfClusters);
+        if (res == 0) {
+            JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+        }
+        result = bytesPerSector;
+    }
+    return result;
+}
--- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,6 +59,8 @@
 static jfieldID diskSpace_totalBytes;
 static jfieldID diskSpace_totalFree;
 
+static jfieldID diskSpace_bytesPerSector;
+
 static jfieldID account_domain;
 static jfieldID account_name;
 static jfieldID account_use;
@@ -121,6 +123,8 @@
     CHECK_NULL(diskSpace_totalBytes);
     diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J");
     CHECK_NULL(diskSpace_totalFree);
+    diskSpace_bytesPerSector = (*env)->GetFieldID(env, clazz, "bytesPerSector", "J");
+    CHECK_NULL(diskSpace_bytesPerSector);
 
     clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account");
     CHECK_NULL(clazz);
@@ -582,6 +586,30 @@
         long_to_jlong(totalNumberOfFreeBytes.QuadPart));
 }
 
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetDiskFreeSpace0(JNIEnv* env, jclass this,
+    jlong address, jobject obj)
+{
+    DWORD sectorsPerCluster;
+    DWORD bytesPerSector;
+    DWORD numberOfFreeClusters;
+    DWORD totalNumberOfClusters;
+    LPCWSTR lpRootPathName = jlong_to_ptr(address);
+
+
+    BOOL res = GetDiskFreeSpaceW(lpRootPathName,
+                                 &sectorsPerCluster,
+                                 &bytesPerSector,
+                                 &numberOfFreeClusters,
+                                 &totalNumberOfClusters);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+        return;
+    }
+
+    (*env)->SetLongField(env, obj, diskSpace_bytesPerSector,
+        long_to_jlong(bytesPerSector));
+}
 
 JNIEXPORT jstring JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumePathName0(JNIEnv* env, jclass this,
--- a/src/jdk.unsupported/share/classes/com/sun/nio/file/ExtendedOpenOption.java	Fri Oct 20 11:08:18 2017 -0700
+++ b/src/jdk.unsupported/share/classes/com/sun/nio/file/ExtendedOpenOption.java	Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,29 @@
     /**
      * Prevent operations on the file that request delete access.
      */
-    NOSHARE_DELETE(ExtendedOptions.NOSHARE_DELETE);
+    NOSHARE_DELETE(ExtendedOptions.NOSHARE_DELETE),
+
+    /**
+     * Requires that direct I/O be used for read or write access.
+     * Attempting to open a file with this option set will result in
+     * an {@code UnsupportedOperationException} if the operating system or
+     * file system does not support Direct I/O or a sufficient equivalent.
+     *
+     * @apiNote
+     * The DIRECT option enables performing file I/O directly between user
+     * buffers and the file thereby circumventing the operating system page
+     * cache and possibly avoiding the thrashing which could otherwise occur
+     * in I/O-intensive applications. This option may be of benefit to
+     * applications which do their own caching or do random I/O operations
+     * on large data sets. It is likely to provide the most benefit when
+     * the file is stored on a device which has high I/O throughput capacity.
+     * The option should be used with caution however as in general it is
+     * likely to degrade performance. The performance effects of using it
+     * should be evaluated in each particular circumstance.
+     *
+     * @since 10
+     */
+    DIRECT(ExtendedOptions.DIRECT);
 
     ExtendedOpenOption(ExtendedOptions.InternalOption<Void> option) {
         option.register(this);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8164900
+ * @summary Test for ExtendedOpenOption.DIRECT flag
+ * @requires (os.family == "linux" | os.family == "solaris"
+ *         | os.family == "aix")
+ * @library /test/lib
+ * @build jdk.test.lib.Platform
+ * @run main/native DirectIOTest
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import jdk.test.lib.Platform;
+import java.nio.file.FileStore;
+import java.nio.file.StandardOpenOption;
+import com.sun.nio.file.ExtendedOpenOption;
+
+public class DirectIOTest {
+
+    private static final int SIZE = 4096;
+
+    private static void testWrite(Path p) throws Exception {
+        try (FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE,
+             ExtendedOpenOption.DIRECT)) {
+            FileStore fs = Files.getFileStore(p);
+            int alignment = (int)fs.getBlockSize();
+            ByteBuffer src = ByteBuffer.allocateDirect(SIZE + alignment - 1)
+                                       .alignedSlice(alignment);
+            for (int j = 0; j < SIZE; j++) {
+                src.put((byte)0);
+            }
+            src.flip();
+            fc.write(src);
+        }
+    }
+
+    private static void testRead(Path p) throws Exception {
+        try (FileChannel fc = FileChannel.open(p, ExtendedOpenOption.DIRECT)) {
+            FileStore fs = Files.getFileStore(p);
+            int alignment = (int)fs.getBlockSize();
+            ByteBuffer dest = ByteBuffer.allocateDirect(SIZE + alignment - 1)
+                                        .alignedSlice(alignment);
+            fc.read(dest);
+        }
+    }
+
+    public static Path createTempFile() throws IOException {
+        return Files.createTempFile(
+            Paths.get(System.getProperty("test.dir", ".")), "test", null);
+    }
+
+    public static boolean isDirectIOSupportedByFS(Path p) throws Exception {
+        boolean supported = true;
+        if (Platform.isSolaris()) {
+            String fsType = Files.getFileStore(p).type();
+            if (!fsType.equals("nfs") && !fsType.equals("ufs")) {
+                // print a message and return without failing
+                System.out.format("Skipping test: file system type %s of "
+                    + "FileStore of %s is neither nfs nor ufs.%n", fsType, p);
+                supported = false;
+            }
+        }
+        return supported;
+    }
+
+    private static boolean isFileInCache(Path p) {
+        String path = p.toString();
+        return isFileInCache0(SIZE, path);
+    }
+
+    private static native boolean isFileInCache0(int size, String path);
+
+    public static void main(String[] args) throws Exception {
+        Path p = createTempFile();
+
+        if (!isDirectIOSupportedByFS(p)) {
+            Files.delete(p);
+            return;
+        }
+
+        System.loadLibrary("DirectIO");
+
+        try {
+            testWrite(p);
+            if (isFileInCache(p)) {
+                throw new RuntimeException("DirectIO is not working properly with "
+                    + "write. File still exists in cache!");
+            }
+            testRead(p);
+            if (isFileInCache(p)) {
+                throw new RuntimeException("DirectIO is not working properly with "
+                    + "read. File still exists in cache!");
+            }
+        } finally {
+            Files.delete(p);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/PreadDirect.java	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test positional read method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ *        DirectIOTest
+ * @run main/othervm PreadDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+/**
+ * Testing FileChannel's positional read method.
+ */
+
+public class PreadDirect {
+
+    private static PrintStream err = System.err;
+
+    private static Random generator = RandomFactory.getRandom();
+
+    private static int charsPerGroup = -1;
+
+    private static int alignment = -1;
+
+    public static void main(String[] args) throws Exception {
+        if (initTests()) {
+            genericTest();
+            testNotAlignedChannelPosition();
+            testNegativeChannelPosition();
+        }
+    }
+
+    private static boolean initTests() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+            Files.delete(p);
+            return false;
+        }
+        try {
+            FileStore fs = Files.getFileStore(p);
+            alignment = (int)fs.getBlockSize();
+            charsPerGroup = alignment;
+        } finally {
+            Files.delete(p);
+        }
+        return true;
+    }
+
+    private static void testNegativeChannelPosition() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            fos.write(new byte[charsPerGroup]);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            try {
+                fc.read(ByteBuffer.allocate(charsPerGroup), -1L);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch(IllegalArgumentException e) {
+                // Correct result
+            }
+        }
+    }
+
+    private static void testNotAlignedChannelPosition() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            fos.write(new byte[charsPerGroup]);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            long pos = charsPerGroup - 1;
+            try {
+                fc.read(ByteBuffer.allocate(charsPerGroup), pos);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch(IOException e) {
+                if (!e.getMessage().contains("Channel position (" + pos
+                    + ") is not a multiple of the block size (" + alignment + ")"))
+                    throw new RuntimeException("Read test failed");
+            }
+        }
+    }
+
+    private static void genericTest() throws Exception {
+        StringBuffer sb = new StringBuffer();
+        sb.setLength(2);
+
+        Path p = DirectIOTest.createTempFile();
+
+        initTestFile(p);
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block =
+                ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+                          .alignedSlice(alignment);
+            for (int x = 0; x < 100; x++) {
+                block.clear();
+                long offset = generator.nextInt(100) * charsPerGroup;
+                long expectedResult = offset / charsPerGroup;
+                offset = expectedResult * charsPerGroup;
+
+                long originalPosition = fc.position();
+
+                int read = fc.read(block, offset);
+                if (read != charsPerGroup)
+                    throw new Exception("Read failed");
+
+                long newPosition = fc.position();
+
+                for (int i = 0; i < 2; i++) {
+                    byte aByte = block.get(i);
+                    sb.setCharAt(i, (char)aByte);
+                }
+                int result = Integer.parseInt(sb.toString());
+                if (result != expectedResult) {
+                    err.println("I expected "+ expectedResult);
+                    err.println("I got "+ result);
+                    throw new Exception("Read test failed");
+                }
+
+                // Ensure that file pointer position has not changed
+                if (originalPosition != newPosition)
+                    throw new Exception("File position modified");
+            }
+        }
+    }
+
+    private static void initTestFile(Path p) throws Exception {
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            try (BufferedWriter awriter
+                 = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+
+                for (int i = 0; i < 100; i++) {
+                    String number = new Integer(i).toString();
+                    for (int h = 0; h < 2 - number.length(); h++)
+                        awriter.write("0");
+                    awriter.write(""+i);
+                    for (int j = 0; j < (charsPerGroup - 2); j++)
+                        awriter.write("0");
+                }
+                awriter.flush();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/PwriteDirect.java	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test positional write method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ *        DirectIOTest
+ * @run main/othervm PwriteDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+/**
+ * Testing FileChannel's positional write method.
+ */
+public class PwriteDirect {
+
+    private static Random generator = RandomFactory.getRandom();
+
+    private static int charsPerGroup = -1;
+
+    private static int alignment = -1;
+
+    private static boolean initTests() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+            Files.delete(p);
+            return false;
+        }
+        try {
+            FileStore fs = Files.getFileStore(p);
+            alignment = (int)fs.getBlockSize();
+            charsPerGroup = alignment;
+        } finally {
+            Files.delete(p);
+        }
+        return true;
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (initTests()) {
+            genericTest();
+            TestWithNotAlignedChannelPosition();
+            testUnwritableChannel();
+        }
+    }
+
+    private static void testUnwritableChannel() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            try {
+                fc.write(ByteBuffer.allocate(charsPerGroup), 0);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch(NonWritableChannelException e) {
+                // Correct result
+            }
+        }
+    }
+
+    private static void TestWithNotAlignedChannelPosition() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            int bufferSize = charsPerGroup;
+            long position = charsPerGroup - 1;
+            try {
+                fc.write(ByteBuffer.allocate(bufferSize), position);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch(IOException e) {
+                if (!e.getMessage().contains("Channel position (" + position + ")"
+                    + " is not a multiple of the block size (" + alignment + ")"))
+                    throw new RuntimeException("Write test failed");
+            }
+        }
+    }
+
+    private static void genericTest() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+
+        initTestFile(p);
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.WRITE,
+            StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block =
+                ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+                          .alignedSlice(alignment);
+            for (int x = 0; x < 100; x++) {
+                block.clear();
+                long offset = generator.nextInt(100) * charsPerGroup;
+
+                // Write known sequence out
+                for (int i = 0; i < charsPerGroup; i++) {
+                    block.put(i, (byte)'a');
+                }
+                long originalPosition = fc.position();
+
+                int written = fc.write(block, offset);
+                if (written < 0)
+                    throw new Exception("Write failed");
+
+                long newPosition = fc.position();
+
+                // Ensure that file pointer position has not changed
+                if (originalPosition != newPosition)
+                    throw new Exception("File position modified");
+
+                // Attempt to read sequence back in
+                originalPosition = fc.position();
+
+                block.rewind();
+                int read = fc.read(block, offset);
+                if (read != charsPerGroup)
+                    throw new Exception("Read failed");
+
+                newPosition = fc.position();
+
+                // Ensure that file pointer position has not changed
+                if (originalPosition != newPosition)
+                    throw new Exception("File position modified");
+
+                for (int j = 0; j < charsPerGroup; j++) {
+                    if (block.get(j) != (byte)'a')
+                        throw new Exception("Write test failed");
+                }
+            }
+        }
+    }
+
+    private static void initTestFile(Path p) throws Exception {
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            try (BufferedWriter awriter
+                = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+                for (int i = 0; i < 100; i++) {
+                    String number = new Integer(i).toString();
+                    for (int h = 0; h < 4 - number.length(); h++)
+                        awriter.write("0");
+                    awriter.write("" + i);
+                    for (int j = 0; j < 4092; j++)
+                        awriter.write("0");
+                }
+                awriter.flush();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/ReadDirect.java	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test read method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ *        DirectIOTest
+ * @run main/othervm ReadDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+public class ReadDirect {
+
+    private static PrintStream err = System.err;
+
+    private static Random generator = RandomFactory.getRandom();
+
+    private static int charsPerGroup = -1;
+
+    private static int alignment = -1;
+
+    private static boolean initTests() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+            Files.delete(p);
+            return false;
+        }
+        try {
+            FileStore fs = Files.getFileStore(p);
+            alignment = (int)fs.getBlockSize();
+            charsPerGroup = alignment;
+        } finally {
+            Files.delete(p);
+        }
+        return true;
+    }
+
+    private static void testWithSingleBuffer() throws Exception {
+        StringBuffer sb = new StringBuffer();
+        sb.setLength(2);
+
+        Path p = DirectIOTest.createTempFile();
+
+        initTestFile(p);
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block = ByteBuffer.allocateDirect(charsPerGroup
+                + alignment - 1).alignedSlice(alignment);
+            for (int x = 0; x < 100; x++) {
+                block.clear();
+                long offset = x * charsPerGroup;
+                long expectedResult = offset / charsPerGroup;
+                fc.read(block);
+
+                for (int i = 0; i < 2; i++) {
+                    byte aByte = block.get(i);
+                    sb.setCharAt(i, (char)aByte);
+                }
+                int result = Integer.parseInt(sb.toString());
+                if (result != expectedResult) {
+                    err.println("I expected " + expectedResult);
+                    err.println("I got " + result);
+                    throw new Exception("Read test failed");
+                }
+            }
+        }
+    }
+
+    private static void testWithNotAlignedBufferSize() throws Exception {
+        int bufferSize = charsPerGroup - 1;
+        Path p = DirectIOTest.createTempFile();
+
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            fos.write(new byte[bufferSize]);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block = ByteBuffer.allocate(bufferSize);
+            try {
+                fc.read(block);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch (IOException e) {
+                if (!e.getMessage().contains("Number of remaining bytes ("
+                    + bufferSize + ") is not a multiple of the block size ("
+                    + alignment + ")"))
+                    throw new Exception("Read test failed");
+            }
+        }
+    }
+
+    private static void testWithNotAlignedBufferOffset() throws Exception {
+        int bufferSize = charsPerGroup * 2;
+        int pos = alignment - 1;
+
+        Path p = DirectIOTest.createTempFile();
+
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            fos.write(new byte[bufferSize]);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block = ByteBuffer.allocateDirect(bufferSize);
+            block.position(pos);
+            block.limit(bufferSize - 1);
+            try {
+                fc.read(block);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch (IOException e) {
+                if (!e.getMessage().contains("Current location of the bytebuffer "
+                    +  "(" + pos + ") is not a multiple of the block size ("
+                    + alignment + ")"))
+                    throw new Exception("Read test failed");
+            }
+        }
+    }
+
+    private static void testWithArrayOfBuffer() throws Exception {
+        StringBuffer sb = new StringBuffer();
+        sb.setLength(2);
+        ByteBuffer[] dests = new ByteBuffer[4];
+        Path p = DirectIOTest.createTempFile();
+
+        initTestFile(p);
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            int randomNumber = -1;
+
+            for (int i = 0; i < 4; i++) {
+                dests[i] = ByteBuffer.allocateDirect
+                    (charsPerGroup + alignment - 1).alignedSlice(alignment);
+                for (int j = 0; j < charsPerGroup; j++) {
+                    dests[i].put(j, (byte)'a');
+                }
+            }
+
+            randomNumber = generator.nextInt(100);
+            long offset =  randomNumber * charsPerGroup;
+            fc.position(offset);
+            fc.read(dests, 1, 2);
+
+            for (int i = 0; i < 4; i++) {
+                if (i == 1 || i == 2) {
+                    for (int j = 0; j < 2; j++) {
+                        byte aByte = dests[i].get(j);
+                        sb.setCharAt(j, (char)aByte);
+                    }
+                    int result = Integer.parseInt(sb.toString());
+                    int expectedResult = randomNumber + i - 1;
+                    if (result != expectedResult) {
+                        err.println("I expected " + expectedResult);
+                        err.println("I got " + result);
+                        throw new Exception("Read test failed");
+                    }
+                } else {
+                    for (int k = 0; k < charsPerGroup; k++) {
+                        if (dests[i].get(k) != (byte)'a')
+                            throw new RuntimeException("Read test failed");
+                    }
+                }
+            }
+        }
+    }
+
+    public static void testOnEOF() throws Exception {
+        int bufferSize = charsPerGroup / 2;
+        Path p = DirectIOTest.createTempFile();
+
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            byte[] writeBlock = new byte[bufferSize];
+            for (int i = 0; i < bufferSize; i++) {
+                writeBlock[i] = ((byte)'a');
+            }
+            fos.write(writeBlock);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block = ByteBuffer.allocateDirect(
+                    (bufferSize / alignment + 1) * alignment + alignment - 1)
+                    .alignedSlice(alignment);
+            int result = fc.read(block);
+            if (result != bufferSize) {
+                err.println("Number of bytes to read " + bufferSize);
+                err.println("I read " + result);
+                throw new Exception("Read test failed");
+            }
+            for (int j = 0; j < bufferSize; j++) {
+                if (block.get(j) != (byte)'a')
+                    throw new RuntimeException("Read test failed");
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (initTests()) {
+            testWithSingleBuffer();
+            testWithNotAlignedBufferSize();
+            testWithNotAlignedBufferOffset();
+            testWithArrayOfBuffer();
+            testOnEOF();
+        }
+    }
+
+    private static void initTestFile(Path p)
+            throws Exception {
+        try (OutputStream fos = Files.newOutputStream(p)) {
+            try (BufferedWriter awriter
+                 = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+                for (int i = 0; i < 100; i++) {
+                    String number = new Integer(i).toString();
+                    for (int h = 0; h < 2 - number.length(); h++)
+                        awriter.write("0");
+                    awriter.write("" + i);
+                    for (int j = 0; j < (charsPerGroup - 2); j++)
+                        awriter.write("0");
+                }
+                awriter.flush();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/WriteDirect.java	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8164900
+ * @summary Test FileChannel write with DirectIO
+ * @library .. /test/lib
+ * @build DirectIOTest
+ * @run main/othervm WriteDirect
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import com.sun.nio.file.ExtendedOpenOption;
+
+public class WriteDirect {
+
+    private static int charsPerGroup = -1;
+
+    private static int alignment = -1;
+
+    private static boolean initTests() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+            Files.delete(p);
+            return false;
+        }
+        try {
+            FileStore fs = Files.getFileStore(p);
+            alignment = (int)fs.getBlockSize();
+            charsPerGroup = alignment;
+        } finally {
+            Files.delete(p);
+        }
+        return true;
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (initTests()) {
+            testWithNotAlignedBuffer();
+            testWithNotAlignedBufferOffset();
+            testWithArrayOfBuffer();
+        }
+    }
+
+    static void testWithNotAlignedBuffer() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            int bufferSize = charsPerGroup - 1;
+            ByteBuffer src = ByteBuffer.allocate(bufferSize);
+            try {
+                fc.write(src);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch (IOException e) {
+                if (!e.getMessage().contains("Number of remaining bytes ("
+                    + bufferSize + ") is not a multiple of the block size ("
+                    + alignment + ")"))
+                    throw new Exception("Write failure");
+            }
+        }
+    }
+
+    private static void testWithNotAlignedBufferOffset() throws Exception {
+        int bufferSize = charsPerGroup * 2;
+        int pos = alignment - 1;
+
+        Path p = DirectIOTest.createTempFile();
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE,
+            ExtendedOpenOption.DIRECT)) {
+            ByteBuffer block = ByteBuffer.allocateDirect(bufferSize);
+            block.position(pos);
+            block.limit(bufferSize - 1);
+            try {
+                fc.write(block);
+                throw new RuntimeException("Expected exception not thrown");
+            } catch (IOException e) {
+                if (!e.getMessage().contains("Current location of the bytebuffer "
+                    +  "(" + pos + ") is not a multiple of the block size ("
+                    + alignment + ")"))
+                    throw new Exception("Write test failed");
+            }
+        }
+    }
+
+    static void testWithArrayOfBuffer() throws Exception {
+        Path p = DirectIOTest.createTempFile();
+        ByteBuffer[] srcs = new ByteBuffer[4];
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.WRITE, ExtendedOpenOption.DIRECT)) {
+            for (int i = 0; i < 4; i++) {
+                srcs[i] = ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+                                    .alignedSlice(alignment);
+                for (int j = 0; j < charsPerGroup; j++) {
+                    srcs[i].put((byte)i);
+                }
+                srcs[i].flip();
+            }
+
+            fc.write(srcs, 1, 2);
+        }
+
+        try (FileChannel fc = FileChannel.open(p,
+            StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE)) {
+            ByteBuffer bb = ByteBuffer.allocateDirect(charsPerGroup * 2);
+            fc.read(bb);
+            bb.flip();
+            for (int k = 0; k < charsPerGroup; k++) {
+                if (bb.get() != 1)
+                    throw new RuntimeException("Write failure");
+            }
+            for (int m = 0; m < charsPerGroup; m++) {
+                if (bb.get() != 2)
+                    throw new RuntimeException("Write failure");
+            }
+            try {
+                bb.get();
+                throw new RuntimeException("Write failure");
+            } catch (BufferUnderflowException bufe) {
+                // correct result
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c	Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Test if a file exists in the file system cache
+ */
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "jni.h"
+
+/*
+ * Throws an exception with the given class name and detail message
+ */
+static void ThrowException(JNIEnv *env, const char *name, const char *msg) {
+    jclass cls = (*env)->FindClass(env, name);
+    if (cls != NULL) {
+        (*env)->ThrowNew(env, cls, msg);
+    }
+}
+
+/*
+ * Class:     DirectIO
+ * Method:    isFileInCache0
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env,
+                                                jclass cls,
+                                                jint file_size,
+                                                jstring file_path) {
+    void *f_mmap;
+#ifdef __linux__
+    unsigned char *f_seg;
+#else
+    char *f_seg;
+#endif
+
+#ifdef __APPLE__
+    size_t mask = MINCORE_INCORE;
+#else
+    size_t mask = 0x1;
+#endif
+
+    size_t page_size = getpagesize();
+    size_t index = (file_size + page_size - 1) /page_size;
+    jboolean result = JNI_FALSE;
+
+    const char* path = (*env)->GetStringUTFChars(env, file_path, JNI_FALSE);
+
+    int fd = open(path, O_RDWR);
+
+    (*env)->ReleaseStringUTFChars(env, file_path, path);
+
+    f_mmap = mmap(0, file_size, PROT_NONE, MAP_SHARED, fd, 0);
+    if (f_mmap == MAP_FAILED) {
+        close(fd);
+        ThrowException(env, "java/io/IOException",
+            "test of whether file exists in cache failed");
+    }
+    f_seg = malloc(index);
+    if (f_seg != NULL) {
+        if(mincore(f_mmap, file_size, f_seg) == 0) {
+            size_t i;
+            for (i = 0; i < index; i++) {
+                if (f_seg[i] & mask) {
+                    result = JNI_TRUE;
+                    break;
+                }
+            }
+        }
+        free(f_seg);
+    } else {
+        ThrowException(env, "java/io/IOException",
+            "test of whether file exists in cache failed");
+    }
+    close(fd);
+    munmap(f_mmap, file_size);
+    return result;
+}