pnfs-obj: Better IO pattern in case of unaligned offset
[linux-2.6-block.git] / fs / nfs / objlayout / objio_osd.c
index f50d3e8d6f2230a42cdc656b61004dcf62182dd2..ea6d111b03e9484c23d5ca3f7997f10d893a57ad 100644 (file)
@@ -570,17 +570,66 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
                return false;
 
        return pgio->pg_count + req->wb_bytes <=
-                       OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+                       (unsigned long)pgio->pg_layout_private;
+}
+
+void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       pnfs_generic_pg_init_read(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+}
+
+static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
+                                  unsigned long *stripe_end)
+{
+       u32 stripe_off;
+       unsigned stripe_size;
+
+       if (layout->raid_algorithm == PNFS_OSD_RAID_0)
+               return true;
+
+       stripe_size = layout->stripe_unit *
+                               (layout->group_width - layout->parity);
+
+       div_u64_rem(offset, stripe_size, &stripe_off);
+       if (!stripe_off)
+               return true;
+
+       *stripe_end = stripe_size - stripe_off;
+       return false;
+}
+
+void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       unsigned long stripe_end = 0;
+
+       pnfs_generic_pg_init_write(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       if (req->wb_offset ||
+           !aligned_on_raid_stripe(req->wb_index * PAGE_SIZE,
+                              &OBJIO_LSEG(pgio->pg_lseg)->layout,
+                              &stripe_end)) {
+               pgio->pg_layout_private = (void *)stripe_end;
+       } else {
+               pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+       }
 }
 
 static const struct nfs_pageio_ops objio_pg_read_ops = {
-       .pg_init = pnfs_generic_pg_init_read,
+       .pg_init = objio_init_read,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_readpages,
 };
 
 static const struct nfs_pageio_ops objio_pg_write_ops = {
-       .pg_init = pnfs_generic_pg_init_write,
+       .pg_init = objio_init_write,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_writepages,
 };