]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/nfs/nfs4filelayout.c
NFSv4.1: pnfs: filelayout: add driver's LAYOUTGET and GETDEVICEINFO infrastructure
[net-next-2.6.git] / fs / nfs / nfs4filelayout.c
index 696e283c26324f086f7d6e05c4b29852c9385915..9e82b51cb515ccda778088f921df87b520cd6200 100644 (file)
@@ -30,7 +30,9 @@
  */
 
 #include <linux/nfs_fs.h>
-#include "pnfs.h"
+
+#include "internal.h"
+#include "nfs4filelayout.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
@@ -41,23 +43,223 @@ MODULE_DESCRIPTION("The NFSv4 file layout driver");
 int
 filelayout_initialize_mountpoint(struct nfs_server *nfss)
 {
+       int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client,
+                                               nfs4_fl_free_deviceid_callback);
+       if (status) {
+               printk(KERN_WARNING "%s: deviceid cache could not be "
+                       "initialized\n", __func__);
+               return status;
+       }
+       dprintk("%s: deviceid cache has been initialized successfully\n",
+               __func__);
        return 0;
 }
 
+/* Uninitialize a mountpoint by destroying its device list */
 int
 filelayout_uninitialize_mountpoint(struct nfs_server *nfss)
 {
        dprintk("--> %s\n", __func__);
 
+       if (nfss->nfs_client->cl_devid_cache)
+               pnfs_put_deviceid_cache(nfss->nfs_client);
        return 0;
 }
 
+/*
+ * filelayout_check_layout()
+ *
+ * Make sure layout segment parameters are sane WRT the device.
+ * At this point no generic layer initialization of the lseg has occurred,
+ * and nothing has been added to the layout_hdr cache.
+ *
+ */
+static int
+filelayout_check_layout(struct pnfs_layout_hdr *lo,
+                       struct nfs4_filelayout_segment *fl,
+                       struct nfs4_layoutget_res *lgr,
+                       struct nfs4_deviceid *id)
+{
+       struct nfs4_file_layout_dsaddr *dsaddr;
+       int status = -EINVAL;
+       struct nfs_server *nfss = NFS_SERVER(lo->inode);
+
+       dprintk("--> %s\n", __func__);
+
+       if (fl->pattern_offset > lgr->range.offset) {
+               dprintk("%s pattern_offset %lld to large\n",
+                               __func__, fl->pattern_offset);
+               goto out;
+       }
+
+       if (fl->stripe_unit % PAGE_SIZE) {
+               dprintk("%s Stripe unit (%u) not page aligned\n",
+                       __func__, fl->stripe_unit);
+               goto out;
+       }
+
+       /* find and reference the deviceid */
+       dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id);
+       if (dsaddr == NULL) {
+               dsaddr = get_device_info(lo->inode, id);
+               if (dsaddr == NULL)
+                       goto out;
+       }
+       fl->dsaddr = dsaddr;
+
+       if (fl->first_stripe_index < 0 ||
+           fl->first_stripe_index >= dsaddr->stripe_count) {
+               dprintk("%s Bad first_stripe_index %d\n",
+                               __func__, fl->first_stripe_index);
+               goto out_put;
+       }
+
+       if ((fl->stripe_type == STRIPE_SPARSE &&
+           fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
+           (fl->stripe_type == STRIPE_DENSE &&
+           fl->num_fh != dsaddr->stripe_count)) {
+               dprintk("%s num_fh %u not valid for given packing\n",
+                       __func__, fl->num_fh);
+               goto out_put;
+       }
+
+       if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
+               dprintk("%s Stripe unit (%u) not aligned with rsize %u "
+                       "wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
+                       nfss->wsize);
+       }
+
+       status = 0;
+out:
+       dprintk("--> %s returns %d\n", __func__, status);
+       return status;
+out_put:
+       pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid);
+       goto out;
+}
+
+static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
+{
+       int i;
+
+       for (i = 0; i < fl->num_fh; i++) {
+               if (!fl->fh_array[i])
+                       break;
+               kfree(fl->fh_array[i]);
+       }
+       kfree(fl->fh_array);
+       fl->fh_array = NULL;
+}
+
+static void
+_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
+{
+       filelayout_free_fh_array(fl);
+       kfree(fl);
+}
+
+static int
+filelayout_decode_layout(struct pnfs_layout_hdr *flo,
+                        struct nfs4_filelayout_segment *fl,
+                        struct nfs4_layoutget_res *lgr,
+                        struct nfs4_deviceid *id)
+{
+       uint32_t *p = (uint32_t *)lgr->layout.buf;
+       uint32_t nfl_util;
+       int i;
+
+       dprintk("%s: set_layout_map Begin\n", __func__);
+
+       memcpy(id, p, sizeof(*id));
+       p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+       print_deviceid(id);
+
+       nfl_util = be32_to_cpup(p++);
+       if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
+               fl->commit_through_mds = 1;
+       if (nfl_util & NFL4_UFLG_DENSE)
+               fl->stripe_type = STRIPE_DENSE;
+       else
+               fl->stripe_type = STRIPE_SPARSE;
+       fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
+
+       fl->first_stripe_index = be32_to_cpup(p++);
+       p = xdr_decode_hyper(p, &fl->pattern_offset);
+       fl->num_fh = be32_to_cpup(p++);
+
+       dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
+               __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
+               fl->pattern_offset);
+
+       fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
+                              GFP_KERNEL);
+       if (!fl->fh_array)
+               return -ENOMEM;
+
+       for (i = 0; i < fl->num_fh; i++) {
+               /* Do we want to use a mempool here? */
+               fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+               if (!fl->fh_array[i]) {
+                       filelayout_free_fh_array(fl);
+                       return -ENOMEM;
+               }
+               fl->fh_array[i]->size = be32_to_cpup(p++);
+               if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
+                       printk(KERN_ERR "Too big fh %d received %d\n",
+                              i, fl->fh_array[i]->size);
+                       filelayout_free_fh_array(fl);
+                       return -EIO;
+               }
+               memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
+               p += XDR_QUADLEN(fl->fh_array[i]->size);
+               dprintk("DEBUG: %s: fh len %d\n", __func__,
+                       fl->fh_array[i]->size);
+       }
+
+       return 0;
+}
+
+static struct pnfs_layout_segment *
+filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
+                     struct nfs4_layoutget_res *lgr)
+{
+       struct nfs4_filelayout_segment *fl;
+       int rc;
+       struct nfs4_deviceid id;
+
+       dprintk("--> %s\n", __func__);
+       fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+       if (!fl)
+               return NULL;
+
+       rc = filelayout_decode_layout(layoutid, fl, lgr, &id);
+       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) {
+               _filelayout_free_lseg(fl);
+               return NULL;
+       }
+       return &fl->generic_hdr;
+}
+
+static void
+filelayout_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       struct nfs_server *nfss = NFS_SERVER(lseg->layout->inode);
+       struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
+
+       dprintk("--> %s\n", __func__);
+       pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache,
+                         &fl->dsaddr->deviceid);
+       _filelayout_free_lseg(fl);
+}
+
 static struct pnfs_layoutdriver_type filelayout_type = {
        .id = LAYOUT_NFSV4_1_FILES,
        .name = "LAYOUT_NFSV4_1_FILES",
        .owner = THIS_MODULE,
        .initialize_mountpoint   = filelayout_initialize_mountpoint,
        .uninitialize_mountpoint = filelayout_uninitialize_mountpoint,
+       .alloc_lseg              = filelayout_alloc_lseg,
+       .free_lseg               = filelayout_free_lseg,
 };
 
 static int __init nfs4filelayout_init(void)