#include "../nfs4trace.h"
 #include "../iostat.h"
 #include "../nfs.h"
+#include "../nfs42.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
        dprintk("%s: Return\n", __func__);
 }
 
+static bool
+ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args,
+                              struct pnfs_layout_segment *pls,
+                              int *dev_count, int dev_limit)
+{
+       struct nfs4_ff_layout_mirror *mirror;
+       struct nfs4_deviceid_node *dev;
+       struct nfs42_layoutstat_devinfo *devinfo;
+       int i;
+
+       for (i = 0; i <= FF_LAYOUT_MIRROR_COUNT(pls); i++) {
+               if (*dev_count >= dev_limit)
+                       break;
+               mirror = FF_LAYOUT_COMP(pls, i);
+               dev = FF_LAYOUT_DEVID_NODE(pls, i);
+               devinfo = &args->devinfo[*dev_count];
+               memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE);
+               devinfo->offset = pls->pls_range.offset;
+               devinfo->length = pls->pls_range.length;
+               /* well, we don't really know if IO is continuous or not! */
+               devinfo->read_count = mirror->read_stat.io_stat.bytes_completed;
+               devinfo->read_bytes = mirror->read_stat.io_stat.bytes_completed;
+               devinfo->write_count = mirror->write_stat.io_stat.bytes_completed;
+               devinfo->write_bytes = mirror->write_stat.io_stat.bytes_completed;
+               devinfo->layout_type = LAYOUT_FLEX_FILES;
+               devinfo->layoutstats_encode = NULL;
+               devinfo->layout_private = NULL;
+
+               ++(*dev_count);
+       }
+
+       return *dev_count < dev_limit;
+}
+
+static int
+ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args)
+{
+       struct pnfs_layout_segment *pls;
+       int dev_count = 0;
+
+       spin_lock(&args->inode->i_lock);
+       list_for_each_entry(pls, &NFS_I(args->inode)->layout->plh_segs, pls_list) {
+               dev_count += FF_LAYOUT_MIRROR_COUNT(pls);
+       }
+       spin_unlock(&args->inode->i_lock);
+       /* For now, send at most PNFS_LAYOUTSTATS_MAXDEV statistics */
+       if (dev_count > PNFS_LAYOUTSTATS_MAXDEV) {
+               dprintk("%s: truncating devinfo to limit (%d:%d)\n",
+                       __func__, dev_count, PNFS_LAYOUTSTATS_MAXDEV);
+               dev_count = PNFS_LAYOUTSTATS_MAXDEV;
+       }
+       args->devinfo = kmalloc(dev_count * sizeof(*args->devinfo), GFP_KERNEL);
+       if (!args->devinfo)
+               return -ENOMEM;
+
+       dev_count = 0;
+       spin_lock(&args->inode->i_lock);
+       list_for_each_entry(pls, &NFS_I(args->inode)->layout->plh_segs, pls_list) {
+               if (!ff_layout_mirror_prepare_stats(args, pls, &dev_count,
+                                                   PNFS_LAYOUTSTATS_MAXDEV)) {
+                       break;
+               }
+       }
+       spin_unlock(&args->inode->i_lock);
+       args->num_dev = dev_count;
+
+       return 0;
+}
+
 static struct pnfs_layoutdriver_type flexfilelayout_type = {
        .id                     = LAYOUT_FLEX_FILES,
        .name                   = "LAYOUT_FLEX_FILES",
        .alloc_deviceid_node    = ff_layout_alloc_deviceid_node,
        .encode_layoutreturn    = ff_layout_encode_layoutreturn,
        .sync                   = pnfs_nfs_generic_sync,
+       .prepare_layoutstats    = ff_layout_prepare_layoutstats,
 };
 
 static int __init nfs4flexfilelayout_init(void)