Whamcloud - gitweb
LU-13300 ldiskfs: port patches to improve extent status shrink
[fs/lustre-release.git] / lnet / lnet / lib-md.c
index c53a486..53a8557 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -80,31 +80,112 @@ lnet_md_unlink(struct lnet_libmd *md)
        lnet_md_free(md);
 }
 
+struct page *
+lnet_kvaddr_to_page(unsigned long vaddr)
+{
+       if (is_vmalloc_addr((void *)vaddr))
+               return vmalloc_to_page((void *)vaddr);
+
+#ifdef CONFIG_HIGHMEM
+
+#ifdef HAVE_KMAP_TO_PAGE
+       /*
+        * This ifdef is added to handle the kernel versions
+        * which have kmap_to_page() function exported. If so,
+        * we should use it. Otherwise, remain with the legacy check.
+        */
+       return kmap_to_page((void *)vaddr);
+#else
+
+       if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
+               /* No highmem pages only used for bulk (kiov) I/O */
+               CERROR("find page for address in highmem\n");
+               LBUG();
+       }
+       return virt_to_page(vaddr);
+#endif /* HAVE_KMAP_TO_PAGE */
+#else
+
+       return virt_to_page(vaddr);
+#endif /* CONFIG_HIGHMEM */
+}
+EXPORT_SYMBOL(lnet_kvaddr_to_page);
+
 int
-lnet_cpt_of_md(struct lnet_libmd *md)
+lnet_cpt_of_md(struct lnet_libmd *md, unsigned int offset)
 {
        int cpt = CFS_CPT_ANY;
+       unsigned int niov;
 
-       if (!md)
-               return CFS_CPT_ANY;
-
-       if ((md->md_options & LNET_MD_BULK_HANDLE) != 0 &&
-           !LNetMDHandleIsInvalid(md->md_bulk_handle)) {
+       /*
+        * if the md_options has a bulk handle then we want to look at the
+        * bulk md because that's the data which we will be DMAing
+        */
+       if (md && (md->md_options & LNET_MD_BULK_HANDLE) != 0 &&
+           !LNetMDHandleIsInvalid(md->md_bulk_handle))
                md = lnet_handle2md(&md->md_bulk_handle);
 
-               if (!md)
-                       return CFS_CPT_ANY;
-       }
+       if (!md || md->md_niov == 0)
+               return CFS_CPT_ANY;
 
+       niov = md->md_niov;
+
+       /*
+        * There are three cases to handle:
+        *  1. The MD is using lnet_kiov_t
+        *  2. The MD is using struct kvec
+        *  3. Contiguous buffer allocated via vmalloc
+        *
+        *  in case 2 we can use virt_to_page() macro to get the page
+        *  address of the memory kvec describes.
+        *
+        *  in case 3 use is_vmalloc_addr() and vmalloc_to_page()
+        *
+        * The offset provided can be within the first iov/kiov entry or
+        * it could go beyond it. In that case we need to make sure to
+        * look at the page which actually contains the data that will be
+        * DMAed.
+        */
        if ((md->md_options & LNET_MD_KIOV) != 0) {
-               if (md->md_iov.kiov[0].kiov_page != NULL)
-                       cpt = cfs_cpt_of_node(lnet_cpt_table(),
-                               page_to_nid(md->md_iov.kiov[0].kiov_page));
-       } else if (md->md_iov.iov[0].iov_base != NULL) {
+               lnet_kiov_t *kiov = md->md_iov.kiov;
+
+               while (offset >= kiov->kiov_len) {
+                       offset -= kiov->kiov_len;
+                       niov--;
+                       kiov++;
+                       if (niov == 0) {
+                               CERROR("offset %d goes beyond kiov\n", offset);
+                               goto out;
+                       }
+               }
+
                cpt = cfs_cpt_of_node(lnet_cpt_table(),
-                       page_to_nid(virt_to_page(md->md_iov.iov[0].iov_base)));
+                               page_to_nid(kiov->kiov_page));
+       } else {
+               struct kvec *iov = md->md_iov.iov;
+               unsigned long vaddr;
+               struct page *page;
+
+               while (offset >= iov->iov_len) {
+                       offset -= iov->iov_len;
+                       niov--;
+                       iov++;
+                       if (niov == 0) {
+                               CERROR("offset %d goes beyond iov\n", offset);
+                               goto out;
+                       }
+               }
+
+               vaddr = ((unsigned long)iov->iov_base) + offset;
+               page = lnet_kvaddr_to_page(vaddr);
+               if (!page) {
+                       CERROR("Couldn't resolve vaddr 0x%lx to page\n", vaddr);
+                       goto out;
+               }
+               cpt = cfs_cpt_of_node(lnet_cpt_table(), page_to_nid(page));
        }
 
+out:
        return cpt;
 }
 
@@ -188,7 +269,7 @@ lnet_md_build(struct lnet_libmd *lmd, struct lnet_md *umd, int unlink)
 
 /* must be called with resource lock held */
 static int
-lnet_md_link(struct lnet_libmd *md, struct lnet_handle_eq eq_handle, int cpt)
+lnet_md_link(struct lnet_libmd *md, struct lnet_eq *eq, int cpt)
 {
        struct lnet_res_container *container = the_lnet.ln_md_containers[cpt];
 
@@ -204,12 +285,8 @@ lnet_md_link(struct lnet_libmd *md, struct lnet_handle_eq eq_handle, int cpt)
         * maybe there we shouldn't even allow LNET_EQ_NONE!)
         * LASSERT (eq == NULL);
         */
-       if (!LNetEQHandleIsInvalid(eq_handle)) {
-               md->md_eq = lnet_handle2eq(&eq_handle);
-
-               if (md->md_eq == NULL)
-                       return -ENOENT;
-
+       if (eq) {
+               md->md_eq = eq;
                (*md->md_eq->eq_refs[cpt])++;
        }
 
@@ -237,7 +314,6 @@ lnet_md_deconstruct(struct lnet_libmd *lmd, struct lnet_md *umd)
        umd->max_size = lmd->md_max_size;
        umd->options = lmd->md_options;
        umd->user_ptr = lmd->md_user_ptr;
-       lnet_eq2handle(&umd->eq_handle, lmd->md_eq);
 }
 
 static int
@@ -262,7 +338,7 @@ lnet_md_validate(struct lnet_md *umd)
 /**
  * Create a memory descriptor and attach it to a ME
  *
- * \param meh A handle for a ME to associate the new MD with.
+ * \param me An ME to associate the new MD with.
  * \param umd Provides initial values for the user-visible parts of a MD.
  * Other than its use for initialization, there is no linkage between this
  * structure and the MD maintained by the LNet.
@@ -285,12 +361,11 @@ lnet_md_validate(struct lnet_md *umd)
  * a MD.
  */
 int
-LNetMDAttach(struct lnet_handle_me meh, struct lnet_md umd,
+LNetMDAttach(struct lnet_me *me, struct lnet_md umd,
             enum lnet_unlink unlink, struct lnet_handle_md *handle)
 {
-       struct list_head        matches = LIST_HEAD_INIT(matches);
-       struct list_head        drops = LIST_HEAD_INIT(drops);
-       struct lnet_me          *me;
+       LIST_HEAD(matches);
+       LIST_HEAD(drops);
        struct lnet_libmd       *md;
        int                     cpt;
        int                     rc;
@@ -313,14 +388,11 @@ LNetMDAttach(struct lnet_handle_me meh, struct lnet_md umd,
        if (rc != 0)
                goto out_free;
 
-       cpt = lnet_cpt_of_cookie(meh.cookie);
+       cpt = me->me_cpt;
 
        lnet_res_lock(cpt);
 
-       me = lnet_handle2me(&meh);
-       if (me == NULL)
-               rc = -ENOENT;
-       else if (me->me_md != NULL)
+       if (me->me_md)
                rc = -EBUSY;
        else
                rc = lnet_md_link(md, umd.eq_handle, cpt);
@@ -391,6 +463,13 @@ LNetMDBind(struct lnet_md umd, enum lnet_unlink unlink,
        if (rc != 0)
                goto out_free;
 
+       if (md->md_length > LNET_MTU) {
+               CERROR("Invalid length: too big transfer size %u, %d max\n",
+                      md->md_length, LNET_MTU);
+               rc = -EINVAL;
+               goto out_free;
+       }
+
        cpt = lnet_res_lock_current();
 
        rc = lnet_md_link(md, umd.eq_handle, cpt);
@@ -468,6 +547,9 @@ LNetMDUnlink(struct lnet_handle_md mdh)
                lnet_eq_enqueue_event(md->md_eq, &ev);
        }
 
+       if (md->md_rspt_ptr != NULL)
+               lnet_detach_rsp_tracker(md, cpt);
+
        lnet_md_unlink(md);
 
        lnet_res_unlock(cpt);