+/* when brw_kiovec() is asked to read from block -1UL it just zeros
+ * the page. this gives us a chance to verify the write mappings
+ * as well */
+static int filter_cleanup_mappings(int rw, struct kiobuf *iobuf,
+ struct inode *inode)
+{
+ int i, blocks_per_page_bits = PAGE_SHIFT - inode->i_blkbits;
+ ENTRY;
+
+ for (i = 0 ; i < iobuf->nr_pages << blocks_per_page_bits; i++) {
+ if (iobuf->blocks[i] > 0)
+ continue;
+
+ if (rw == OBD_BRW_WRITE)
+ RETURN(-EINVAL);
+
+ iobuf->blocks[i] = -1UL;
+ }
+ RETURN(0);
+}
+
+#if 0
+static void dump_page(int rw, unsigned long block, struct page *page)
+{
+ char *blah = kmap(page);
+ CDEBUG(D_PAGE, "rw %d block %lu: %02x %02x %02x %02x\n", rw, block,
+ blah[0], blah[1], blah[2], blah[3]);
+ kunmap(page);
+}
+#endif
+
+/* These are our hacks to keep our directio/bh IO coherent with ext3's
+ * page cache use. Most notably ext3 reads file data into the page
+ * cache when it is zeroing the tail of partial-block truncates and
+ * leaves it there, sometimes generating io from it at later truncates.
+ * This removes the partial page and its buffers from the page cache,
+ * so it should only ever cause a wait in rare cases, as otherwise we
+ * always do full-page IO to the OST.
+ *
+ * The call to truncate_complete_page() will call journal_flushpage() to
+ * free the buffers and drop the page from cache. The buffers should not
+ * be dirty, because we already called fdatasync/fdatawait on them.
+ */
+static int filter_clear_page_cache(struct inode *inode, struct kiobuf *iobuf)
+{
+ struct page *page;
+ int i, rc, rc2;
+
+ check_pending_bhs(KIOBUF_GET_BLOCKS(iobuf), iobuf->nr_pages,
+ inode->i_dev, 1 << inode->i_blkbits);
+
+ /* This is nearly generic_osync_inode, without the waiting on the inode
+ rc = generic_osync_inode(inode, inode->i_mapping,
+ OSYNC_DATA|OSYNC_METADATA);
+ */
+ rc = filemap_fdatasync(inode->i_mapping);
+ rc2 = fsync_inode_data_buffers(inode);
+ if (rc == 0)
+ rc = rc2;
+ rc2 = filemap_fdatawait(inode->i_mapping);
+ if (rc == 0)
+ rc = rc2;
+ if (rc != 0)
+ RETURN(rc);
+
+ /* be careful to call this after fsync_inode_data_buffers has waited
+ * for IO to complete before we evict it from the cache */
+ for (i = 0; i < iobuf->nr_pages ; i++) {
+ page = find_lock_page(inode->i_mapping,
+ iobuf->maplist[i]->index);
+ if (page == NULL)
+ continue;
+ if (page->mapping != NULL)
+ ll_truncate_complete_page(page);
+
+ unlock_page(page);
+ page_cache_release(page);
+ }
+
+ return 0;
+}
+
+/* Must be called with i_sem taken for writes; this will drop it */
+int filter_direct_io(int rw, struct dentry *dchild, void *buf,
+ struct obd_export *exp, struct iattr *attr,
+ struct obd_trans_info *oti, void **wait_handle)