diff --git a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch
index a71991a92f..74e9995a13 100644
--- a/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch
+++ b/Spigot-Server-Patches/Asynchronous-chunk-IO-and-loading.patch
@@ -121,7 +121,7 @@ tasks required to be executed by the chunk load task (i.e lighting
 and some poi tasks).
 
 diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
-index 3a79cde595..8de6c4816c 100644
+index 3a79cde59..8de6c4816 100644
 --- a/src/main/java/co/aikar/timings/WorldTimingsHandler.java
 +++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
 @@ -0,0 +0,0 @@ public class WorldTimingsHandler {
@@ -161,7 +161,7 @@ index 3a79cde595..8de6c4816c 100644
  
      public static Timing getTickList(WorldServer worldserver, String timingsType) {
 diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
-index 546a1cfe0a..1d7d1ffbf7 100644
+index 546a1cfe0..1d7d1ffbf 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
 @@ -0,0 +0,0 @@
@@ -237,7 +237,7 @@ index 546a1cfe0a..1d7d1ffbf7 100644
 +    }
  }
 diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
-index 23626bef3a..1edcecd2ee 100644
+index 23626bef3..1edcecd2e 100644
 --- a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
 +++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
 @@ -0,0 +0,0 @@ import java.util.concurrent.Executors;
@@ -318,7 +318,7 @@ index 23626bef3a..1edcecd2ee 100644
  
 diff --git a/src/main/java/com/destroystokyo/paper/io/IOUtil.java b/src/main/java/com/destroystokyo/paper/io/IOUtil.java
 new file mode 100644
-index 0000000000..5af0ac3d9e
+index 000000000..5af0ac3d9
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/IOUtil.java
 @@ -0,0 +0,0 @@
@@ -386,7 +386,7 @@ index 0000000000..5af0ac3d9e
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
 new file mode 100644
-index 0000000000..4f10a8311e
+index 000000000..4f10a8311
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
 @@ -0,0 +0,0 @@
@@ -1053,7 +1053,7 @@ index 0000000000..4f10a8311e
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/PrioritizedTaskQueue.java b/src/main/java/com/destroystokyo/paper/io/PrioritizedTaskQueue.java
 new file mode 100644
-index 0000000000..78bd238f4c
+index 000000000..78bd238f4
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/PrioritizedTaskQueue.java
 @@ -0,0 +0,0 @@
@@ -1335,7 +1335,7 @@ index 0000000000..78bd238f4c
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
 new file mode 100644
-index 0000000000..ee906b594b
+index 000000000..ee906b594
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
 @@ -0,0 +0,0 @@
@@ -1582,7 +1582,7 @@ index 0000000000..ee906b594b
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java
 new file mode 100644
-index 0000000000..305da47868
+index 000000000..305da4786
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkLoadTask.java
 @@ -0,0 +0,0 @@
@@ -1737,7 +1737,7 @@ index 0000000000..305da47868
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkSaveTask.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkSaveTask.java
 new file mode 100644
-index 0000000000..60312b85f9
+index 000000000..60312b85f
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkSaveTask.java
 @@ -0,0 +0,0 @@
@@ -1855,7 +1855,7 @@ index 0000000000..60312b85f9
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTask.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTask.java
 new file mode 100644
-index 0000000000..1dfa8abfd8
+index 000000000..1dfa8abfd
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTask.java
 @@ -0,0 +0,0 @@
@@ -1901,7 +1901,7 @@ index 0000000000..1dfa8abfd8
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
 new file mode 100644
-index 0000000000..59d73bfad7
+index 000000000..59d73bfad
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
 @@ -0,0 +0,0 @@
@@ -2359,7 +2359,7 @@ index 0000000000..59d73bfad7
 +
 +}
 diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
-index e9cd44fae1..1f6b1c4f16 100644
+index e9cd44fae..1f6b1c4f1 100644
 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
 +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
 @@ -0,0 +0,0 @@ public class ChunkProviderServer extends IChunkProvider {
@@ -2529,7 +2529,7 @@ index e9cd44fae1..1f6b1c4f16 100644
          } finally {
              playerChunkMap.callbackExecutor.run();
 diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
-index a950ad801d..26f1a4b095 100644
+index a950ad801..26f1a4b09 100644
 --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
 +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
 @@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
@@ -2798,7 +2798,7 @@ index a950ad801d..26f1a4b095 100644
  
          nbttagcompound1.set("PostProcessing", a(ichunkaccess.l()));
 diff --git a/src/main/java/net/minecraft/server/ChunkStatus.java b/src/main/java/net/minecraft/server/ChunkStatus.java
-index 134a4f0b7d..88f1674616 100644
+index 134a4f0b7..88f167461 100644
 --- a/src/main/java/net/minecraft/server/ChunkStatus.java
 +++ b/src/main/java/net/minecraft/server/ChunkStatus.java
 @@ -0,0 +0,0 @@ public class ChunkStatus {
@@ -2810,7 +2810,7 @@ index 134a4f0b7d..88f1674616 100644
          return ChunkStatus.r.getInt(chunkstatus.c());
      }
 diff --git a/src/main/java/net/minecraft/server/IAsyncTaskHandler.java b/src/main/java/net/minecraft/server/IAsyncTaskHandler.java
-index 7210217913..f7156acb89 100644
+index 721021791..f7156acb8 100644
 --- a/src/main/java/net/minecraft/server/IAsyncTaskHandler.java
 +++ b/src/main/java/net/minecraft/server/IAsyncTaskHandler.java
 @@ -0,0 +0,0 @@ public abstract class IAsyncTaskHandler<R extends Runnable> implements Mailbox<R
@@ -2823,7 +2823,7 @@ index 7210217913..f7156acb89 100644
              ;
          }
 diff --git a/src/main/java/net/minecraft/server/IChunkLoader.java b/src/main/java/net/minecraft/server/IChunkLoader.java
-index 2f95174fcc..134c76065b 100644
+index 2f95174fc..134c76065 100644
 --- a/src/main/java/net/minecraft/server/IChunkLoader.java
 +++ b/src/main/java/net/minecraft/server/IChunkLoader.java
 @@ -0,0 +0,0 @@ package net.minecraft.server;
@@ -2948,7 +2948,7 @@ index 2f95174fcc..134c76065b 100644
 +//    Paper end
  }
 diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
-index 25a87c2d37..c02c53b50b 100644
+index 25a87c2d3..c02c53b50 100644
 --- a/src/main/java/net/minecraft/server/MCUtil.java
 +++ b/src/main/java/net/minecraft/server/MCUtil.java
 @@ -0,0 +0,0 @@ public final class MCUtil {
@@ -2962,7 +2962,7 @@ index 25a87c2d37..c02c53b50b 100644
 +    }
  }
 diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 4eba20b6ab..fe24d924e8 100644
+index 4eba20b6a..fe24d924e 100644
 --- a/src/main/java/net/minecraft/server/MinecraftServer.java
 +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
@@ -2974,7 +2974,7 @@ index 4eba20b6ab..fe24d924e8 100644
  
      public String getServerIp() {
 diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java
-index e9c405fb53..33cfeabdee 100644
+index e9c405fb5..33cfeabde 100644
 --- a/src/main/java/net/minecraft/server/NextTickListEntry.java
 +++ b/src/main/java/net/minecraft/server/NextTickListEntry.java
 @@ -0,0 +0,0 @@ import java.util.Comparator;
@@ -2996,7 +2996,7 @@ index e9c405fb53..33cfeabdee 100644
          this.e = t0;
          this.b = i;
 diff --git a/src/main/java/net/minecraft/server/NibbleArray.java b/src/main/java/net/minecraft/server/NibbleArray.java
-index ed8c4a87b5..996c832638 100644
+index ed8c4a87b..996c83263 100644
 --- a/src/main/java/net/minecraft/server/NibbleArray.java
 +++ b/src/main/java/net/minecraft/server/NibbleArray.java
 @@ -0,0 +0,0 @@ public class NibbleArray {
@@ -3008,7 +3008,7 @@ index ed8c4a87b5..996c832638 100644
          return this.a == null ? new NibbleArray() : new NibbleArray((byte[]) this.a.clone());
      }
 diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
-index 7a1578afaa..0fb9c1e441 100644
+index 7a1578afa..0fb9c1e44 100644
 --- a/src/main/java/net/minecraft/server/PlayerChunk.java
 +++ b/src/main/java/net/minecraft/server/PlayerChunk.java
 @@ -0,0 +0,0 @@ public class PlayerChunk {
@@ -3034,7 +3034,7 @@ index 7a1578afaa..0fb9c1e441 100644
                  completablefuture = (CompletableFuture) this.statusFutures.get(i);
                  if (completablefuture != null) {
 diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
-index 3825520fa1..d9faef8a67 100644
+index 3825520fa..0ad11ba68 100644
 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
 +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
 @@ -0,0 +0,0 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -3433,9 +3433,11 @@ index 3825520fa1..d9faef8a67 100644
      // Paper start - chunk status cache "api"
      public ChunkStatus getChunkStatusOnDiskIfCached(ChunkCoordIntPair chunkPos) {
 -        RegionFile regionFile = this.getIOWorker().getRegionFileCache().getRegionFileIfLoaded(chunkPos);
++        synchronized (this) { // Paper
 +        RegionFile regionFile = this.getRegionFileIfLoaded(chunkPos);
  
          return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z);
++        } // Paper
      }
  
      public ChunkStatus getChunkStatusOnDisk(ChunkCoordIntPair chunkPos) throws IOException {
@@ -3542,9 +3544,18 @@ index 3825520fa1..d9faef8a67 100644
          return this.m;
      }
 diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
-index d37abf2cf3..0de24c792e 100644
+index d37abf2cf..df728e2c0 100644
 --- a/src/main/java/net/minecraft/server/RegionFile.java
 +++ b/src/main/java/net/minecraft/server/RegionFile.java
+@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
+     private final RegionFileBitSet freeSectors;
+     public final File file;
+ 
++    public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper
++
+     // Paper start - Cache chunk status
+     private final ChunkStatus[] statuses = new ChunkStatus[32 * 32];
+ 
 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
          return (i + 4096 - 1) / 4096;
      }
@@ -3555,16 +3566,30 @@ index d37abf2cf3..0de24c792e 100644
  
          if (i == 0) {
 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
-         return chunkcoordintpair.j() + chunkcoordintpair.k() * 32;
      }
  
--    public void close() throws IOException {
-+    public synchronized void close() throws IOException { // Paper - Synchronized
+     public void close() throws IOException {
++        // Paper start - Prevent regionfiles from being closed during use
++        this.fileLock.lock();
++        synchronized (this) {
++        try {
++        // Paper end
          this.closed = true; // Paper
          try {
              this.c();
+@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
+                 }
+             }
+         }
++        } finally { // Paper start - Prevent regionfiles from being closed during use
++            this.fileLock.unlock();
++        }
++        } // Paper end
+ 
+     }
+ 
 diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
-index e07ae98540..d927f93211 100644
+index e07ae9854..0f201000f 100644
 --- a/src/main/java/net/minecraft/server/RegionFileCache.java
 +++ b/src/main/java/net/minecraft/server/RegionFileCache.java
 @@ -0,0 +0,0 @@ import java.io.File;
@@ -3588,11 +3613,70 @@ index e07ae98540..d927f93211 100644
      // Paper end
 -    public RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - private >  public
 +    public synchronized RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - private >  public, synchronize
++        // Paper start - add lock parameter
++        return this.getFile(chunkcoordintpair, existingOnly, false);
++    }
++    public synchronized RegionFile getFile(ChunkCoordIntPair chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException {
++        // Paper end
          long i = ChunkCoordIntPair.pair(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
          RegionFile regionfile = (RegionFile) this.cache.getAndMoveToFirst(i);
  
+         if (regionfile != null) {
++            // Paper start
++            if (lock) {
++                // must be in this synchronized block
++                regionfile.fileLock.lock();
++            }
++            // Paper end
+             return regionfile;
+         } else {
+             if (this.cache.size() >= com.destroystokyo.paper.PaperConfig.regionFileCacheSize) { // Paper - configurable
 @@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable {
+             RegionFile regionfile1 = new RegionFile(file, this.b);
+ 
+             this.cache.putAndMoveToFirst(i, regionfile1);
++            // Paper start
++            if (lock) {
++                // must be in this synchronized block
++                regionfile1.fileLock.lock();
++            }
++            // Paper end
+             return regionfile1;
+         }
+     }
+@@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable {
+ 
+     @Nullable
+     public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException {
+-        RegionFile regionfile = this.getFile(chunkcoordintpair, false); // CraftBukkit
++        RegionFile regionfile = this.getFile(chunkcoordintpair, false, true); // CraftBukkit // Paper
++        try { // Paper
+         DataInputStream datainputstream = regionfile.a(chunkcoordintpair);
+         // Paper start
+         if (regionfile.isOversized(chunkcoordintpair.x, chunkcoordintpair.z)) {
+@@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable {
+         }
+ 
+         return nbttagcompound;
++        } finally { // Paper start
++            regionfile.fileLock.unlock();
++        } // Paper end
+     }
+ 
+     protected void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException {
+-        RegionFile regionfile = this.getFile(chunkcoordintpair, false); // CraftBukkit
++        RegionFile regionfile = this.getFile(chunkcoordintpair, false, true); // CraftBukkit // Paper
++        try { // Paper
+         int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
+         DataOutputStream dataoutputstream = regionfile.c(chunkcoordintpair);
+         Throwable throwable = null;
+@@ -0,0 +0,0 @@ public final class RegionFileCache implements AutoCloseable {
+             MinecraftServer.LOGGER.error("Failed to save chunk", laste);
+         }
          // Paper end
++        } finally { // Paper start
++            regionfile.fileLock.unlock();
++        } // Paper end
      }
  
 -    public void close() throws IOException {
@@ -3610,7 +3694,7 @@ index e07ae98540..d927f93211 100644
  
          return regionfile != null ? regionfile.chunkExists(pos) : false;
 diff --git a/src/main/java/net/minecraft/server/RegionFileSection.java b/src/main/java/net/minecraft/server/RegionFileSection.java
-index db9f0196bd..a6d8ef5eb4 100644
+index db9f0196b..a6d8ef5eb 100644
 --- a/src/main/java/net/minecraft/server/RegionFileSection.java
 +++ b/src/main/java/net/minecraft/server/RegionFileSection.java
 @@ -0,0 +0,0 @@ import javax.annotation.Nullable;
@@ -3746,7 +3830,7 @@ index db9f0196bd..a6d8ef5eb4 100644
 +    // Paper end
  }
 diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java
-index 335b644351..481d954808 100644
+index 335b64435..481d95480 100644
 --- a/src/main/java/net/minecraft/server/TicketType.java
 +++ b/src/main/java/net/minecraft/server/TicketType.java
 @@ -0,0 +0,0 @@ public class TicketType<T> {
@@ -3758,7 +3842,7 @@ index 335b644351..481d954808 100644
      public static <T> TicketType<T> a(String s, Comparator<T> comparator) {
          return new TicketType<>(s, comparator, 0L);
 diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java
-index c999f8c9bf..b59ef1a633 100644
+index c999f8c9b..b59ef1a63 100644
 --- a/src/main/java/net/minecraft/server/VillagePlace.java
 +++ b/src/main/java/net/minecraft/server/VillagePlace.java
 @@ -0,0 +0,0 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
@@ -3847,7 +3931,7 @@ index c999f8c9bf..b59ef1a633 100644
  
          HAS_SPACE(VillagePlaceRecord::d), IS_OCCUPIED(VillagePlaceRecord::e), ANY((villageplacerecord) -> {
 diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
-index 90272d0c00..136c18d10b 100644
+index 90272d0c0..136c18d10 100644
 --- a/src/main/java/net/minecraft/server/WorldServer.java
 +++ b/src/main/java/net/minecraft/server/WorldServer.java
 @@ -0,0 +0,0 @@ public class WorldServer extends World {
@@ -3940,7 +4024,7 @@ index 90272d0c00..136c18d10b 100644
  
      // CraftBukkit start
 diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-index 2a33b90efd..0d036e5d96 100644
+index 2a33b90ef..0d036e5d9 100644
 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 @@ -0,0 +0,0 @@ public class CraftWorld implements World {
@@ -4002,7 +4086,7 @@ index 2a33b90efd..0d036e5d96 100644
      @Override
      public int getViewDistance() {
 diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
-index 07936eeba2..fe68df45ba 100644
+index 07936eeba..fe68df45b 100644
 --- a/src/main/java/org/spigotmc/WatchdogThread.java
 +++ b/src/main/java/org/spigotmc/WatchdogThread.java
 @@ -0,0 +0,0 @@ import java.lang.management.ThreadInfo;