#include <linux/nd.h>
 #include "nd-core.h"
 #include "pmem.h"
+#include "pfn.h"
 #include "nd.h"
 
 static void namespace_io_release(struct device *dev)
                return ERR_PTR(-ENODEV);
        }
 
+       /*
+        * Note, alignment validation for fsdax and devdax mode
+        * namespaces happens in nd_pfn_validate() where infoblock
+        * padding parameters can be applied.
+        */
+       if (pmem_should_map_pages(dev)) {
+               struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+               struct resource *res = &nsio->res;
+
+               if (!IS_ALIGNED(res->start | (res->end + 1),
+                                       memremap_compat_align())) {
+                       dev_err(&ndns->dev, "%pr misaligned, unable to map\n", res);
+                       return ERR_PTR(-EOPNOTSUPP);
+               }
+       }
+
        if (is_namespace_pmem(&ndns->dev)) {
                struct nd_namespace_pmem *nspm;
 
 
        __le64 npfns;
        __le32 mode;
        /* minor-version-1 additions for section alignment */
+       /**
+        * @start_pad: Deprecated attribute to pad start-misaligned namespaces
+        *
+        * start_pad is deprecated because the original definition did
+        * not comprehend that dataoff is relative to the base address
+        * of the namespace not the start_pad adjusted base. The result
+        * is that the dax path is broken, but the block-I/O path is
+        * not. The kernel will no longer create namespaces using start
+        * padding, but it still supports block-I/O for legacy
+        * configurations mainly to allow a backup, reconfigure the
+        * namespace, and restore flow to repair dax operation.
+        */
        __le32 start_pad;
        __le32 end_trunc;
        /* minor-version-2 record the base alignment of the mapping */
 
 int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
 {
        u64 checksum, offset;
+       struct resource *res;
        enum nd_pfn_mode mode;
        struct nd_namespace_io *nsio;
        unsigned long align, start_pad;
         * established.
         */
        nsio = to_nd_namespace_io(&ndns->dev);
-       if (offset >= resource_size(&nsio->res)) {
+       res = &nsio->res;
+       if (offset >= resource_size(res)) {
                dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
                                dev_name(&ndns->dev));
                return -EOPNOTSUPP;
        }
 
-       if ((align && !IS_ALIGNED(nsio->res.start + offset + start_pad, align))
+       if ((align && !IS_ALIGNED(res->start + offset + start_pad, align))
                        || !IS_ALIGNED(offset, PAGE_SIZE)) {
                dev_err(&nd_pfn->dev,
                                "bad offset: %#llx dax disabled align: %#lx\n",
                return -EOPNOTSUPP;
        }
 
+       if (!IS_ALIGNED(res->start + le32_to_cpu(pfn_sb->start_pad),
+                               memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "resource start misaligned\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (!IS_ALIGNED(res->end + 1 - le32_to_cpu(pfn_sb->end_trunc),
+                               memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "resource end misaligned\n");
+               return -EOPNOTSUPP;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(nd_pfn_validate);
        start = nsio->res.start;
        size = resource_size(&nsio->res);
        npfns = PHYS_PFN(size - SZ_8K);
-       align = max(nd_pfn->align, SUBSECTION_SIZE);
+       align = max(nd_pfn->align, memremap_compat_align());
+
+       /*
+        * When @start is misaligned fail namespace creation. See
+        * the 'struct nd_pfn_sb' commentary on why ->start_pad is not
+        * an option.
+        */
+       if (!IS_ALIGNED(start, memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "%s: start %pa misaligned to %#lx\n",
+                               dev_name(&ndns->dev), &start,
+                               memremap_compat_align());
+               return -EINVAL;
+       }
        end_trunc = start + size - ALIGN_DOWN(start + size, align);
        if (nd_pfn->mode == PFN_MODE_PMEM) {
                /*