} while (1);
 }
 
-void *
-kmem_alloc_large(size_t size, xfs_km_flags_t flags)
+
+/*
+ * __vmalloc() will allocate data pages and auxillary structures (e.g.
+ * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context here. Hence
+ * we need to tell memory reclaim that we are in such a context via
+ * PF_MEMALLOC_NOFS to prevent memory reclaim re-entering the filesystem here
+ * and potentially deadlocking.
+ */
+static void *
+__kmem_vmalloc(size_t size, xfs_km_flags_t flags)
 {
        unsigned nofs_flag = 0;
        void    *ptr;
-       gfp_t   lflags;
-
-       trace_kmem_alloc_large(size, flags, _RET_IP_);
-
-       ptr = kmem_alloc(size, flags | KM_MAYFAIL);
-       if (ptr)
-               return ptr;
+       gfp_t   lflags = kmem_flags_convert(flags);
 
-       /*
-        * __vmalloc() will allocate data pages and auxillary structures (e.g.
-        * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context
-        * here. Hence we need to tell memory reclaim that we are in such a
-        * context via PF_MEMALLOC_NOFS to prevent memory reclaim re-entering
-        * the filesystem here and potentially deadlocking.
-        */
        if (flags & KM_NOFS)
                nofs_flag = memalloc_nofs_save();
 
-       lflags = kmem_flags_convert(flags);
        ptr = __vmalloc(size, lflags, PAGE_KERNEL);
 
        if (flags & KM_NOFS)
        return ptr;
 }
 
+/*
+ * Same as kmem_alloc_large, except we guarantee the buffer returned is aligned
+ * to the @align_mask. We only guarantee alignment up to page size, we'll clamp
+ * alignment at page size if it is larger. vmalloc always returns a PAGE_SIZE
+ * aligned region.
+ */
+void *
+kmem_alloc_io(size_t size, int align_mask, xfs_km_flags_t flags)
+{
+       void    *ptr;
+
+       trace_kmem_alloc_io(size, flags, _RET_IP_);
+
+       if (WARN_ON_ONCE(align_mask >= PAGE_SIZE))
+               align_mask = PAGE_SIZE - 1;
+
+       ptr = kmem_alloc(size, flags | KM_MAYFAIL);
+       if (ptr) {
+               if (!((uintptr_t)ptr & align_mask))
+                       return ptr;
+               kfree(ptr);
+       }
+       return __kmem_vmalloc(size, flags);
+}
+
+void *
+kmem_alloc_large(size_t size, xfs_km_flags_t flags)
+{
+       void    *ptr;
+
+       trace_kmem_alloc_large(size, flags, _RET_IP_);
+
+       ptr = kmem_alloc(size, flags | KM_MAYFAIL);
+       if (ptr)
+               return ptr;
+       return __kmem_vmalloc(size, flags);
+}
+
 void *
 kmem_realloc(const void *old, size_t newsize, xfs_km_flags_t flags)
 {
 
         */
        size = BBTOB(bp->b_length);
        if (size < PAGE_SIZE) {
-               bp->b_addr = kmem_alloc(size, KM_NOFS);
+               int align_mask = xfs_buftarg_dma_alignment(bp->b_target);
+               bp->b_addr = kmem_alloc_io(size, align_mask, KM_NOFS);
                if (!bp->b_addr) {
                        /* low memory - use alloc_page loop instead */
                        goto use_alloc_page;
                }
                bp->b_offset = offset_in_page(bp->b_addr);
                bp->b_pages = bp->b_page_array;
-               bp->b_pages[0] = virt_to_page(bp->b_addr);
+               bp->b_pages[0] = kmem_to_page(bp->b_addr);
                bp->b_page_count = 1;
                bp->b_flags |= _XBF_KMEM;
                return 0;
 
         */
        ASSERT(log->l_iclog_size >= 4096);
        for (i = 0; i < log->l_iclog_bufs; i++) {
+               int align_mask = xfs_buftarg_dma_alignment(mp->m_logdev_targp);
                size_t bvec_size = howmany(log->l_iclog_size, PAGE_SIZE) *
                                sizeof(struct bio_vec);
 
                iclog->ic_prev = prev_iclog;
                prev_iclog = iclog;
 
-               iclog->ic_data = kmem_alloc_large(log->l_iclog_size,
-                               KM_MAYFAIL);
+               iclog->ic_data = kmem_alloc_io(log->l_iclog_size, align_mask,
+                                               KM_MAYFAIL);
                if (!iclog->ic_data)
                        goto out_free_iclog;
 #ifdef DEBUG
 
        struct xlog     *log,
        int             nbblks)
 {
+       int align_mask = xfs_buftarg_dma_alignment(log->l_targ);
+
        /*
         * Pass log block 0 since we don't have an addr yet, buffer will be
         * verified on read.
        if (nbblks > 1 && log->l_sectBBsize > 1)
                nbblks += log->l_sectBBsize;
        nbblks = round_up(nbblks, log->l_sectBBsize);
-       return kmem_alloc_large(BBTOB(nbblks), KM_MAYFAIL);
+       return kmem_alloc_io(BBTOB(nbblks), align_mask, KM_MAYFAIL);
 }
 
 /*
 
        TP_PROTO(ssize_t size, int flags, unsigned long caller_ip), \
        TP_ARGS(size, flags, caller_ip))
 DEFINE_KMEM_EVENT(kmem_alloc);
+DEFINE_KMEM_EVENT(kmem_alloc_io);
 DEFINE_KMEM_EVENT(kmem_alloc_large);
 DEFINE_KMEM_EVENT(kmem_realloc);
 DEFINE_KMEM_EVENT(kmem_zone_alloc);