+/*
+ * the routine is used to request pages from pagecache
+ *
+ * use GFP_NOFS for requests from a local client not allowing to enter FS
+ * as we might end up waiting on a page he sent in the request we're serving.
+ * use __GFP_HIGHMEM so that the pages can use all of the available memory
+ * on 32-bit machines
+ * use more agressive GFP_HIGHUSER flags from non-local clients to be able to
+ * generate more memory pressure, but at the same time use __GFP_NOMEMALLOC
+ * in order not to exhaust emergency reserves.
+ *
+ * See Bug 19529 and Bug 19917 for details.
+ */
+static struct page *filter_get_page(struct obd_device *obd,
+ struct inode *inode,
+ obd_off offset,
+ int localreq)
+{
+ struct page *page;
+
+ page = find_or_create_page(inode->i_mapping, offset >> CFS_PAGE_SHIFT,
+ (localreq ? (GFP_NOFS | __GFP_HIGHMEM)
+ : GFP_HIGHUSER));
+ if (unlikely(page == NULL))
+ lprocfs_counter_add(obd->obd_stats, LPROC_FILTER_NO_PAGE, 1);
+
+ return page;
+}
+
+/*
+ * the routine initializes array of local_niobuf from remote_niobuf
+ */
+static int filter_map_remote_to_local(int objcount, struct obd_ioobj *obj,
+ struct niobuf_remote *nb,
+ int *nrpages, struct niobuf_local *res)
+{
+ struct niobuf_remote *rnb;
+ struct niobuf_local *lnb;
+ int i, max;
+ ENTRY;
+
+ /* we don't support multiobject RPC yet
+ * ost_brw_read() and ost_brw_write() check this */
+ LASSERT(objcount == 1);
+
+ max = *nrpages;
+ *nrpages = 0;
+ for (i = 0, rnb = nb, lnb = res; i < obj->ioo_bufcnt; i++, rnb++) {
+ obd_off offset = rnb->offset;
+ unsigned int len = rnb->len;
+
+ while (len > 0) {
+ int poff = offset & (CFS_PAGE_SIZE - 1);
+ int plen = CFS_PAGE_SIZE - poff;
+
+ if (*nrpages >= max) {
+ CERROR("small array of local bufs: %d\n", max);
+ RETURN(-EINVAL);
+ }
+
+ if (plen > len)
+ plen = len;
+ lnb->offset = offset;
+ lnb->len = plen;
+ lnb->flags = rnb->flags;
+ lnb->page = NULL;
+ lnb->rc = 0;
+ lnb->lnb_grant_used = 0;
+
+ LASSERTF(plen <= len, "plen %u, len %u\n", plen, len);
+ offset += plen;
+ len -= plen;
+ lnb++;
+ (*nrpages)++;
+ }
+ }
+ RETURN(0);
+}
+
+/*
+ * the invalidate above doesn't work during read because lnet pins pages.
+ * The truncate is used here instead to drop pages from cache
+ */
+void filter_release_cache(struct obd_device *obd, struct obd_ioobj *obj,
+ struct niobuf_remote *rnb, struct inode *inode)
+{
+ int i;
+
+ LASSERT(inode != NULL);
+ for (i = 0; i < obj->ioo_bufcnt; i++, rnb++) {
+#ifdef HAVE_TRUNCATE_RANGE
+ /* remove pages in which range is fit */
+ truncate_inode_pages_range(inode->i_mapping,
+ rnb->offset & CFS_PAGE_MASK,
+ (rnb->offset + rnb->len - 1) |
+ ~CFS_PAGE_MASK);
+#else
+ /* use invalidate for old kernels */
+ invalidate_mapping_pages(inode->i_mapping,
+ rnb->offset >> CFS_PAGE_SHIFT,
+ (rnb->offset + rnb->len) >>
+ CFS_PAGE_SHIFT);
+#endif
+ }
+}
+