diff --git a/applications/utilities/parallelProcessing/redistributePar/redistributePar.C b/applications/utilities/parallelProcessing/redistributePar/redistributePar.C
index 65e36d5c783c73e4c315e0892889fe5383b8bc17..e7c58ad462434f548f630c75dfd92ced6bac2886 100644
--- a/applications/utilities/parallelProcessing/redistributePar/redistributePar.C
+++ b/applications/utilities/parallelProcessing/redistributePar/redistributePar.C
@@ -2754,6 +2754,10 @@ int main(int argc, char *argv[])
             Info<< "Time = " << runTime.timeName() << endl << endl;
 
 
+            // Read undecomposed mesh on master and 'empty' mesh
+            // (zero faces, point, cells but valid patches and zones) on slaves.
+            // This is a bit of tricky code and hidden inside fvMeshTools for
+            // now.
             Info<< "Reading undecomposed mesh (on master)" << endl;
             autoPtr<fvMesh> baseMeshPtr = fvMeshTools::newMesh
             (
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMesh.C b/src/OpenFOAM/meshes/polyMesh/polyMesh.C
index 232cb3de794dddf0d266638435296db80091f8ca..0a5e93d70890ba282396c56837db711b7ec469b9 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMesh.C
@@ -402,7 +402,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            io.readOpt(),
             io.writeOpt()
         ),
         std::move(points)
@@ -415,7 +415,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            io.readOpt(),
             io.writeOpt()
         ),
         std::move(faces)
@@ -428,7 +428,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            io.readOpt(),
             io.writeOpt()
         ),
         std::move(owner)
@@ -441,7 +441,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            io.readOpt(),
             io.writeOpt()
         ),
         std::move(neighbour)
@@ -455,7 +455,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            IOobject::NO_READ,  // ignore since no alternative can be supplied
             io.writeOpt()
         ),
         *this,
@@ -475,7 +475,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            IOobject::NO_READ,  // ignore since no alternative can be supplied
             IOobject::NO_WRITE
         ),
         *this,
@@ -489,7 +489,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            IOobject::NO_READ,// ignore since no alternative can be supplied
             IOobject::NO_WRITE
         ),
         *this,
@@ -503,7 +503,7 @@ Foam::polyMesh::polyMesh
             instance(),
             meshSubDir,
             *this,
-            IOobject::NO_READ,  //io.readOpt(),
+            IOobject::NO_READ,  // ignore since no alternative can be supplied
             IOobject::NO_WRITE
         ),
         *this,
@@ -515,6 +515,11 @@ Foam::polyMesh::polyMesh
     curMotionTimeIndex_(time().timeIndex()),
     oldPointsPtr_(nullptr)
 {
+    // Note: changed that the constructors where values can be supplied
+    //       (points, faces, owner/neighbour) use the readOpt. All others
+    //       (boundary, *zones) ignore readOpt. To be reviewed as with
+    //       constructor below
+
     // Check if the faces and cells are valid
     forAll(faces_, facei)
     {
@@ -666,6 +671,9 @@ Foam::polyMesh::polyMesh
     curMotionTimeIndex_(time().timeIndex()),
     oldPointsPtr_(nullptr)
 {
+    // Note: probably needs io.readOpt() for points/faces/cells etc so
+    //       we can run with READ_IF_PRESENT. See constructor above.
+
     // Check if faces are valid
     forAll(faces_, facei)
     {
diff --git a/src/dynamicMesh/fvMeshTools/fvMeshTools.C b/src/dynamicMesh/fvMeshTools/fvMeshTools.C
index 1fbc71b471a3d53af5f76880ec2c2df5892475fd..0b4c828cf1fe37a33544739ba22059c26c69a056 100644
--- a/src/dynamicMesh/fvMeshTools/fvMeshTools.C
+++ b/src/dynamicMesh/fvMeshTools/fvMeshTools.C
@@ -450,6 +450,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
     PtrList<entry> patchEntries;
     if (Pstream::master())
     {
+        const bool oldParRun = Pstream::parRun(false);
         facesInstance = io.time().findInstance
         (
             meshSubDir,
@@ -470,6 +471,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
                 false
             )
         );
+        Pstream::parRun(oldParRun);
 
         // Send patches
         for (const int slave : Pstream::subProcs())
@@ -520,11 +522,14 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
 
     // Read mesh
     // ~~~~~~~~~
-    // Now all processors read a mesh and use supplied points,faces etc
+    // Now all processors read a mesh or use supplied points,faces etc
     // if there is none.
-    // Note: fvSolution, fvSchemes are also using the supplied Ioobject so
+    // Note: fvSolution, fvSchemes are also using the supplied IOobject so
     //       on slave will be NO_READ, on master READ_IF_PRESENT. This will
     //       conflict with e.g. timeStampMaster reading so switch off.
+    // Note: v2006 used the READ_IF_PRESENT flag in the meshIO.readOpt(). v2012
+    //       (correctly) does no longer so below code explicitly addFvPatches
+    //       using the separately read boundary file.
 
     const regIOobject::fileCheckTypes oldCheckType =
         regIOobject::fileModificationChecking;
@@ -551,8 +556,12 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
 
         DynamicList<polyPatch*> newPatches;
 
-        if (haveMesh)   //Pstream::master())
+        if (mesh.boundary().size() == patchEntries.size())
         {
+            // Assumably we have correctly read the boundary and can clone.
+            // Note: for
+            // v2012 onwards this is probably never the case and this whole
+            // section can be removed.
             forAll(mesh.boundary(), patchI)
             {
                 newPatches.append
@@ -563,6 +572,10 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
         }
         else
         {
+            // Use patchEntries (read on master & scattered to slaves). This
+            // is probably always happening since boundary file is not read with
+            // READ_IF_PRESENT on recent versions.
+
             forAll(patchEntries, patchI)
             {
                 const entry& e = patchEntries[patchI];
@@ -577,8 +590,12 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
                 else
                 {
                     dictionary patchDict(e.dict());
-                    patchDict.set("nFaces", 0);
-                    patchDict.set("startFace", 0);
+
+                    if (mesh.nInternalFaces() == 0)
+                    {
+                        patchDict.set("nFaces", 0);
+                        patchDict.set("startFace", 0);
+                    }
 
                     newPatches.append
                     (
@@ -655,7 +672,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
             );
         }
 
-        if (pz.size() && fz.size() && cz.size())
+        if (pz.size() || fz.size() || cz.size())
         {
             mesh.addZones(pz, fz, cz);
         }