[pnfs] [PATCH 2/6] 2.6-latest-pnfs-client-draft-13-device-decode

andros at umich.edu andros at umich.edu
Fri Oct 19 14:13:18 EDT 2007


From: Andy Adamson <andros at umich.edu>

Update the decoding of device_addr4 to draft-13. Used by GETDEVICELIST and
GETDEVICEINFO.

Add a list of data servers to nfs4_pnfs_dev_hlist and use for all
stripes (deviceID's).

Note: nfs4_pnfs_device_get() will be updated in a following patch

Signed-off by: Andy Adamson<andros at umich.edu>
---
 fs/nfs/nfs4_fs.h           |    2 +-
 fs/nfs/nfs4filelayout.c    |   32 +++--
 fs/nfs/nfs4filelayout.h    |   41 ++++--
 fs/nfs/nfs4filelayoutdev.c |  348 ++++++++++++++++++++++++++++++++++----------
 fs/nfs/nfs4proc.c          |   11 +-
 fs/nfs/super.c             |    3 +-
 include/linux/nfs_fs_sb.h  |    9 +-
 7 files changed, 332 insertions(+), 114 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1a0f0a3..8a010c4 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -199,7 +199,7 @@ extern struct nfs4_state_recovery_ops *nfs4_network_partition_recovery_ops[];
 #ifdef CONFIG_NFS_V4_1
 extern void nfs4_put_session(struct nfs4_session **session);
 extern struct nfs4_session *nfs4_alloc_session(void);
-extern int nfs4_proc_destroy_session(struct nfs_server *sp);
+extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_clnt *);
 #endif /* CONFIG_NFS_V4_1 */
 
 extern const u32 nfs4_fattr_bitmap[2];
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index ef3f107..563ede4 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -153,7 +153,7 @@ error_ret: ;
 int
 filelayout_uninitialize_mountpoint(struct pnfs_mount_type* mountid)
 {
-struct filelayout_mount_type* fl_mt = NULL;
+	struct filelayout_mount_type* fl_mt = NULL;
 
 	if (mountid)
 		fl_mt = (struct filelayout_mount_type*)mountid->mountid;
@@ -291,8 +291,11 @@ ssize_t filelayout_read_pagelist(
 			status = 0;
 		}
 		else {
-			data->pnfs_client = dserver.dev_item->server->client;
-			data->session = dserver.dev_item->server->session;
+			struct nfs4_pnfs_ds *ds = dserver.dev->ds_list[0];
+
+			/* just try the first data server for the index..*/
+			data->pnfs_client = ds->ds_clp->cl_rpcclient;
+			data->session = ds->ds_clp->cl_ds_session;
 			data->args.fh = dserver.fh;
 
 			/* Now get the file offset on the dserver
@@ -361,15 +364,17 @@ ssize_t filelayout_write_pagelist(
 					&dserver);
 	/* ANDROS: XXX should fail if no data server */
 	if(!status) {
-		data->pnfs_client = dserver.dev_item->server->client;
-		data->session = dserver.dev_item->server->session;
+		struct nfs4_pnfs_ds *ds = dserver.dev->ds_list[0];
+
+		/* just try the first data server for the index.. */
+		data->pnfs_client = ds->ds_clp->cl_rpcclient;
+		data->session = ds->ds_clp->cl_ds_session;
 		data->args.fh = dserver.fh;
 	}
-	dprintk("%s set wb_devid %d\n", __FUNCTION__,
-					dserver.dev_item[0].dev_id);
+	dprintk("%s set wb_devid %d\n", __FUNCTION__, dserver.dev_id);
 	list_for_each(h, &data->pages) {
 		req = list_entry(h, struct nfs_page, wb_list);
-		req->wb_devid = dserver.dev_item[0].dev_id;
+		req->wb_devid = dserver.dev_id;
 	}
 
         /* Now get the file offset on the dserver
@@ -512,6 +517,7 @@ filelayout_commit(struct pnfs_layout_type * layoutid, struct inode* ino, struct
 	struct pnfs_layout_type* laytype;
 	struct nfs4_filelayout* nfslay;
 	struct nfs4_pnfs_dserver dserver;
+	struct nfs4_pnfs_ds *ds;
 	struct nfs_page* first;
 	struct nfs_page* req;
 	struct list_head *pos, *tmp;
@@ -544,8 +550,8 @@ filelayout_commit(struct pnfs_layout_type * layoutid, struct inode* ino, struct
 		}
 		if (!dsdata)
 			goto out_bad;
-		dserver.dev_item = nfs4_pnfs_device_get(ino, dev_id);
-		if (dserver.dev_item == NULL) {
+		dserver.dev = nfs4_pnfs_device_get(ino, dev_id);
+		if (dserver.dev == NULL) {
 			return 1;
 		}
 		list_for_each_safe(pos, tmp, &data->pages) {
@@ -569,8 +575,10 @@ filelayout_commit(struct pnfs_layout_type * layoutid, struct inode* ino, struct
 		dprintk("%s call nfs_commit_rpcsetup i %d devid %d\n",
 						__FUNCTION__, i, dev_id);
 
-		dsdata->pnfs_client = dserver.dev_item->server->client;
-		dsdata->session =  dserver.dev_item->server->session;
+		/* just try the first data server for the index.. */
+		ds = dserver.dev->ds_list[0];
+		dsdata->pnfs_client = ds->ds_clp->cl_rpcclient;
+		dsdata->session =  ds->ds_clp->cl_ds_session;
 
 		nfs_commit_rpcsetup(dsdata, sync);
 
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 7045876..ab7f716 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -18,31 +18,43 @@
 #define NFS4_PNFS_DEV_HASH_BITS 5
 #define NFS4_PNFS_DEV_HASH (1 << NFS4_PNFS_DEV_HASH_BITS)
 
-#define NFS4_PNFS_MAX_DEVS 16
+#define NFS4_PNFS_MAX_STRIPE_CNT 16
+#define NFS4_PNFS_MAX_MULTI_DS   2
 
 struct nfs4_session *nfs41_alloc_session(void);
 int _nfs4_proc_create_session(struct nfs_client *clp, struct nfs4_session *session,
                                 struct rpc_clnt *clnt);
-int _nfs4_proc_destroy_session(struct nfs4_session **session, struct rpc_clnt *clnt);
-
 enum stripetype4 {
         STRIPE_SPARSE = 1,
         STRIPE_DENSE = 2
 };
 
+struct nfs4_pnfs_ds {
+	struct hlist_node 	ds_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
+	u32 			ds_ip_addr;
+	u32 			ds_port;
+	struct nfs_client 	*ds_clp;
+	atomic_t		ds_count;
+};
+
+struct nfs4_pnfs_dev {
+	u32 			stripe_index;
+	int 			num_ds;
+	struct nfs4_pnfs_ds 	*ds_list[NFS4_PNFS_MAX_MULTI_DS];
+};
+
+/* stripe_count is length of dev_list, bounded by NFS4_PNFS_MAX_STRIPE_CNT */
 struct nfs4_pnfs_dev_item {
-	struct hlist_node hash_node;
-	u32 dev_id;
-	u32 ip_addr;
-	u32 port;
-	atomic_t count;
-/*	struct nfs_client *clp; */
-	struct nfs_server *server;
+	struct hlist_node 	hash_node;   /* nfs4_pnfs_dev_hlist dev_list */
+	u32 			dev_id;
+	u32 			stripe_count;
+	struct nfs4_pnfs_dev 	*stripe_devs;
 };
 
 struct nfs4_pnfs_dev_hlist {
-	rwlock_t          dev_lock;
-	struct hlist_head dev_list[NFS4_PNFS_DEV_HASH];
+	rwlock_t		dev_lock;
+	struct hlist_head	dev_list[NFS4_PNFS_DEV_HASH];
+	struct hlist_head	dev_dslist[NFS4_PNFS_DEV_HASH];
 };
 
 struct nfs4_pnfs_devaddr {
@@ -58,7 +70,8 @@ struct nfs4_pnfs_devlist {
 
 struct nfs4_pnfs_dserver {
 	struct nfs_fh        *fh;
-	struct nfs4_pnfs_dev_item *dev_item;
+	struct nfs4_pnfs_dev *dev;
+	u32 dev_id;
 };
 
 struct nfs4_filelayout_devs {
@@ -79,7 +92,7 @@ struct nfs4_filelayout {
 	u64 stripe_unit;
 	unsigned int index_len;
 	unsigned int num_devs;
-	struct nfs4_filelayout_devs devs[NFS4_PNFS_MAX_DEVS];
+	struct nfs4_filelayout_devs devs[NFS4_PNFS_MAX_STRIPE_CNT];
 };
 
 struct filelayout_mount_type {
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index 117ec33..da462e4 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -63,6 +63,38 @@ create_nfs_rpcclient(struct rpc_xprt *xprt,
 				rpc_authflavor_t authflavor,
 				int *err);
 
+void
+print_ds_list(struct nfs4_pnfs_dev *fdev)
+{
+	struct nfs4_pnfs_ds *ds;
+	int i;
+
+	ds = fdev->ds_list[0];
+	for (i = 0; i < fdev->num_ds; i++) {
+		dprintk("        ip_addr %x\n", ntohl(ds->ds_ip_addr));
+		dprintk("        port %hu\n", ntohs(ds->ds_port));
+		dprintk("        client %p\n", ds->ds_clp);
+		dprintk("        cl_exchange_flags %x\n",
+				    ds->ds_clp->cl_exchange_flags);
+		ds++;
+	}
+}
+
+void
+print_stripe_devs(struct nfs4_pnfs_dev_item *dev)
+{
+	struct nfs4_pnfs_dev *fdev;
+	int i;
+
+	fdev = &dev->stripe_devs[0];
+	for (i = 0; i < dev->stripe_count; i++) {
+		dprintk("        stripe_index %u\n", fdev->stripe_index);
+		dprintk("        num_ds %d\n", fdev->num_ds);
+		print_ds_list(fdev);
+		fdev++;
+	}
+}
+
 /* Assumes lock is held */
 static inline struct nfs4_pnfs_dev_item *
 _device_lookup(struct nfs4_pnfs_dev_hlist *hlist, u32 dev_id)
@@ -85,33 +117,74 @@ _device_lookup(struct nfs4_pnfs_dev_hlist *hlist, u32 dev_id)
 }
 
 /* Assumes lock is held */
+static inline struct nfs4_pnfs_ds *
+_data_server_lookup(struct nfs4_pnfs_dev_hlist *hlist, u32 ip_addr, u32 port)
+{
+        unsigned long      hash;
+        struct hlist_node *np;
+
+        dprintk("_data_server_lookup: ip_addr=%x port=%hu\n",
+			ntohl(ip_addr), ntohs(port));
+
+        hash = hash_long(ip_addr, NFS4_PNFS_DEV_HASH_BITS);
+
+        hlist_for_each(np, &hlist->dev_dslist[hash]) {
+                struct nfs4_pnfs_ds *ds;
+                ds = hlist_entry(np, struct nfs4_pnfs_ds, ds_node);
+                if (ds->ds_ip_addr == ip_addr &&
+		    ds->ds_port == port) {
+                        return ds;
+                }
+        }
+        return NULL;
+}
+
+
+/* Assumes lock is held */
 static inline void
 _device_add(struct nfs4_pnfs_dev_hlist *hlist, struct nfs4_pnfs_dev_item *dev)
 {
 	unsigned long      hash;
 
-	dprintk("_device_add: dev_id=%u, ip=%x, port=%hu\n", dev->dev_id,
-		ntohl(dev->ip_addr), ntohs(dev->port));
+	dprintk("_device_add: dev_id=%u stripe_devs:\n", dev->dev_id);
+	print_stripe_devs(dev);
 
 	hash = hash_long(dev->dev_id, NFS4_PNFS_DEV_HASH_BITS);
 	hlist_add_head(&dev->hash_node, &hlist->dev_list[hash]);
 }
 
-/* Create an rpc to the data server defined in 'dev' */
+/* Assumes lock is held */
+static inline void
+_data_server_add(struct nfs4_pnfs_dev_hlist *hlist, struct nfs4_pnfs_ds *ds)
+{
+	unsigned long      hash;
+
+        dprintk("_data_server_add: ip_addr=%x port=%hu\n",
+			ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+
+	hash = hash_long(ds->ds_ip_addr, NFS4_PNFS_DEV_HASH_BITS);
+	hlist_add_head(&ds->ds_node, &hlist->dev_dslist[hash]);
+}
+
+/* Create an rpc to the data server defined in 'dev_list' */
 static int
-device_create(struct rpc_clnt *mds_rpc, struct nfs4_pnfs_dev_item *dev)
+device_create(struct rpc_clnt *mds_rpc, struct nfs4_pnfs_dev *dev)
 {
 	//struct rpc_clnt		*clnt;
 	//struct rpc_xprt		*xprt;
+	struct nfs4_pnfs_ds *ds;
 	struct sockaddr_in	sin;
 	int err = 0;
 
+	/* just use the first ds in ds list...*/
+	ds = dev->ds_list[0];
+
 	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = dev->ip_addr;
-	sin.sin_port = dev->port;
+	sin.sin_addr.s_addr = ds->ds_ip_addr;
+	sin.sin_port = ds->ds_port;
 
-	dprintk("device_create: dev_id=%u, ip=%x, port=%hu, rpcclient %p\n",
-		dev->dev_id, ntohl(dev->ip_addr), ntohs(dev->port), mds_rpc);
+	dprintk("device_create: ip=%x, port=%hu, rpcclient %p\n",
+			ntohl(ds->ds_ip_addr), ntohs(ds->ds_port), mds_rpc);
 
 	/*
  	 * XXX Need to implement.
@@ -137,28 +210,63 @@ out:
 	return err;
 }
 
+/* Assumes lock is held */
+static int
+unhash_ds(struct nfs4_pnfs_ds *ds)
+{
+
+	if (!atomic_dec_and_test(&ds->ds_count))
+		return 0;
+
+	hlist_del_init(&ds->ds_node);
+	return 1;
+}
+
 static void
-device_destroy(struct nfs4_pnfs_dev_item *dev)
+destroy_ds(struct nfs4_pnfs_ds *ds)
 {
+	nfs4_proc_destroy_session(ds->ds_clp->cl_ds_session,
+					  ds->ds_clp->cl_rpcclient);
+	rpc_shutdown_client(ds->ds_clp->cl_rpcclient);
+	ds->ds_clp->cl_rpcclient = NULL;
+	kfree(ds);
+}
+
+/* Assumes lock is NOT held */
+static void
+device_destroy(struct nfs4_pnfs_dev_item *dev, struct nfs4_pnfs_dev_hlist *hlist )
+{
+	struct nfs4_pnfs_dev *fdev;
+	struct nfs4_pnfs_ds *ds;
+	HLIST_HEAD(release);
+	struct hlist_node *np;
+	int i, j;
+
 	if (!dev)
 		return;
 
-	dprintk("device_destroy: did=%u, ip=%x, port=%hu, rpcclient %p flags %x\n",
-		dev->dev_id, ntohl(dev->ip_addr), ntohs(dev->port),
-		dev->server->client,
-		dev->server->nfs_client->cl_exchange_flags);
-
-	/* if not created for DS just return */
-	if (dev->server->nfs_client->cl_exchange_flags &
-			EXCHGID4_FLAG_USE_PNFS_DS &&
-	         !(dev->server->nfs_client->cl_exchange_flags &
-			EXCHGID4_FLAG_USE_PNFS_MDS)) {
-		nfs4_proc_destroy_session(dev->server);
-		// BUG_ON(!atomic_sub_and_test(0, &dev->count));
-		rpc_shutdown_client(dev->server->client);
-		dev->server->client = NULL;
-	}
+	dprintk("device_destroy: did=%u dev_list: \n", dev->dev_id);
+	print_stripe_devs(dev);
 
+	write_lock(&hlist->dev_lock);
+	hlist_del_rcu(&dev->hash_node);
+
+	fdev = &dev->stripe_devs[0];
+	for (i =0; i < dev->stripe_count; i++) {
+		for (j = 0; j < fdev->num_ds; j++) {
+			ds = fdev->ds_list[j];
+			if (unhash_ds(ds)) {
+				hlist_add_head(&ds->ds_node, &release);
+			}
+		}
+		fdev++;
+	}
+	write_unlock(&hlist->dev_lock);
+	hlist_for_each(np, &release) {
+		ds = hlist_entry(np, struct nfs4_pnfs_ds, ds_node);
+		destroy_ds(ds);
+	}
+	kfree(dev->stripe_devs);
 	kfree(dev);
 }
 
@@ -171,6 +279,7 @@ nfs4_pnfs_devlist_init(struct nfs4_pnfs_dev_hlist *hlist)
 
 	for (i = 0; i < NFS4_PNFS_DEV_HASH; i++) {
 		INIT_HLIST_HEAD(&hlist->dev_list[i]);
+		INIT_HLIST_HEAD(&hlist->dev_dslist[i]);
 	}
 
 	return 0;
@@ -194,8 +303,8 @@ nfs4_pnfs_devlist_destroy(struct nfs4_pnfs_dev_hlist *hlist)
 		hlist_for_each_safe(np, next, &hlist->dev_list[i]) {
 			struct nfs4_pnfs_dev_item *dev;
 			dev = hlist_entry(np, struct nfs4_pnfs_dev_item, hash_node);
-			hlist_del_rcu(&dev->hash_node);
-			device_destroy(dev);
+			/* device_destroy grabs hlist->dev_lock */
+			device_destroy(dev, hlist);
 		}
 	}
 }
@@ -209,7 +318,6 @@ nfs4_pnfs_device_add(struct filelayout_mount_type *mt,
 		     struct nfs4_pnfs_dev_item *dev)
 {
 	struct nfs4_pnfs_dev_item *tmp_dev;
-	int err;
 	struct nfs4_pnfs_dev_hlist *hlist = mt->hlist;
 
 	dprintk("nfs4_pnfs_device_add\n");
@@ -225,60 +333,61 @@ nfs4_pnfs_device_add(struct filelayout_mount_type *mt,
 	/* Cleanup, if device was recently added */
 	if (tmp_dev != NULL) {
 		dprintk(" device found, not adding (after creation)\n");
-		device_destroy(dev);
+		device_destroy(dev, hlist);
 	}
 
 	return 0;
 }
 
-/* Decode opaque device data and return the result
- */
-static struct nfs4_pnfs_dev_item*
-decode_device(struct pnfs_device* dev)
+static void
+nfs4_pnfs_ds_add(struct filelayout_mount_type *mt, struct nfs4_pnfs_ds **dsp, u32 ip_addr, u32 port)
 {
-	int index, i, j, len;
-	int tmp[6];
-	uint32_t *p = (uint32_t*)dev->dev_addr_buf;
-	struct nfs4_pnfs_dev_item* file_dev;
-	char r_addr[29]; /* max size of ip/port string */
-
-	if ((file_dev = kmalloc(sizeof(struct nfs4_pnfs_dev_item), GFP_KERNEL)) == NULL)
-	{
-		return NULL;
-	}
-	/* Initialize dev */
-	INIT_HLIST_NODE(&file_dev->hash_node);
-	atomic_set(&file_dev->count, 0);
+	struct nfs4_pnfs_ds *tmp_ds, *ds;
+	struct nfs4_pnfs_dev_hlist *hlist = mt->hlist;
 
-	/* Device id */
-	file_dev->dev_id = dev->dev_id;
+	*dsp = NULL;
 
-	READ32(index);
-	for (i = 0; i < index; i++) {  /* skip indices list */
-		READ32(j);
-	}
-
-	READ32(len);
-	BUG_ON(len != 1);    /* 1 DS per device id */
+	ds = kzalloc(sizeof(*tmp_ds), GFP_KERNEL);
+	if (!ds)
+		return;
 
-	/* Get the device count */
-	READ32(dev->dev_count);
+	/* Initialize ds */
+	ds->ds_ip_addr = ip_addr;
+	ds->ds_port = port;
+	atomic_set(&ds->ds_count, 1);
+	INIT_HLIST_NODE(&ds->ds_node);
 
-	if (dev->dev_count > 1)
-		printk(KERN_NOTICE "%s: Add loop for multipath dev_count %d dev_id %d\n",
-			__FUNCTION__, dev->dev_count, dev->dev_id);
+	write_lock(&hlist->dev_lock);
+	tmp_ds = _data_server_lookup(hlist, ip_addr, port);
+	if (tmp_ds == NULL) {
+		_data_server_add(hlist, ds);
+		*dsp = ds;
+	}
+	write_unlock(&hlist->dev_lock);
+	if (tmp_ds != NULL) {
+		dprintk(" data server found, not adding (after creation)\n");
+		destroy_ds(ds);
+		*dsp = tmp_ds;
+	}
 
-	/* Decode contents of device*/
+}
 
-        /* device addr --  r_netid, r_addr */
+static struct nfs4_pnfs_ds *
+decode_and_add_ds(uint32_t **pp, struct filelayout_mount_type *mt)
+{
+	struct nfs4_pnfs_ds *ds = NULL;
+	char r_addr[29]; /* max size of ip/port string */
+	int len;
+	u32 ip_addr, port;
+	int tmp[6];
+	uint32_t *p = *pp;
 
+	dprintk("%s enter\n", __FUNCTION__);
 	/* check and skip r_netid */
 	READ32(len);
 	if (len != 3) { /* "tcp" */
-		printk("%s: ERROR: Device index %d dev_count %d len %d\n",
-			__FUNCTION__, index, dev->dev_count, len);
-		kfree(file_dev);
-		return NULL;
+		printk("%s: ERROR: non TCP r_netid len %d\n", __FUNCTION__, len);
+		goto out_err;
 	}
 	/* Read the bytes into a temporary buffer */
 	/* TODO: should probably sanity check them */
@@ -286,20 +395,105 @@ decode_device(struct pnfs_device* dev)
 
 	READ32(len);
 	if (len > 29) {
-		printk("%s: ERROR: Device ip/port string too long (%d)\n",__FUNCTION__, len);
-		kfree(file_dev);
-		return NULL;
+		printk("%s: ERROR: Device ip/port too long (%d)\n",
+							__FUNCTION__, len);
+		goto out_err;
 	}
-	memcpy(r_addr, p, len);
+	COPYMEM(r_addr, len);
+	*pp = p;
 	r_addr[len] = '\0';
 	sscanf(r_addr, "%d.%d.%d.%d.%d.%d", &tmp[0], &tmp[1],
-	       &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
-	file_dev->ip_addr = htonl((tmp[0]<<24) | (tmp[1]<<16) |
-				  (tmp[2]<<8) | (tmp[3]));
-	file_dev->port = htons((tmp[4] << 8) | (tmp[5]));
+				&tmp[2], &tmp[3], &tmp[4], &tmp[5]);
+	ip_addr = htonl((tmp[0]<<24) | (tmp[1]<<16) |
+				(tmp[2]<<8) | (tmp[3]));
+	port = htons((tmp[4] << 8) | (tmp[5]));
+
+	nfs4_pnfs_ds_add(mt, &ds, ip_addr, port);
+
+	/* adding ds to stripe */
+	atomic_inc(&ds->ds_count);
 	dprintk("%s: addr:port string = %s\n",__FUNCTION__, r_addr);
+	return ds;
+out_err:
+	dprintk("%s returned NULL\n", __FUNCTION__);
+	return NULL;
+}
 
+/* Decode opaque device data and return the result
+ */
+static struct nfs4_pnfs_dev_item*
+decode_device(struct filelayout_mount_type *mt, struct pnfs_device* dev)
+{
+	int i, len;
+	uint32_t *p = (uint32_t*)dev->dev_addr_buf;
+	struct nfs4_pnfs_dev_item* file_dev;
+	struct nfs4_pnfs_dev* fdev;
+
+	/* Get the stripe count (number of stripe index) */
+	READ32(len);
+	if (len > NFS4_PNFS_MAX_STRIPE_CNT) {
+		printk(KERN_WARNING "%s: stripe count %d greater than supported maximum %d\n", __func__, len, NFS4_PNFS_MAX_STRIPE_CNT);
+
+		goto out_err;
+	}
+
+	file_dev = kzalloc(sizeof(*file_dev), GFP_KERNEL);
+	if (!file_dev)
+		goto out_err;
+
+	file_dev->stripe_devs = kzalloc(sizeof(struct nfs4_pnfs_dev) * len, GFP_KERNEL);
+	if (!file_dev->stripe_devs)
+		goto out_err_free;
+	file_dev->stripe_count = len;
+
+	/* Initialize dev */
+	INIT_HLIST_NODE(&file_dev->hash_node);
+
+	/* Device id */
+	file_dev->dev_id = dev->dev_id;
+
+	fdev = &file_dev->stripe_devs[0];
+	for (i = 0; i < len; i++) {
+		READ32(fdev->stripe_index);
+		fdev++;
+	}
+
+	/* Get the device count, which has to equal the stripe count */
+	READ32(len);
+	if(len != file_dev->stripe_count) {
+		printk("%s: ERROR: device count %d !=  index count %d\n",
+			__func__, len, file_dev->stripe_count);
+		goto out_err_free;
+	}
+
+	fdev = &file_dev->stripe_devs[0];
+	for (i = 0; i < file_dev->stripe_count; i++) {
+		int j, num;
+
+		/* Get the multipath count for this stripe index */
+		READ32(num);
+		if (num > NFS4_PNFS_MAX_MULTI_DS) {
+			printk(KERN_WARNING "%s: Multipath count %d not supported, setting to %d\n", __func__, num, NFS4_PNFS_MAX_MULTI_DS);
+
+			num = NFS4_PNFS_MAX_MULTI_DS;
+		}
+
+		fdev->num_ds = num;
+
+		for (j = 0; j < fdev->num_ds; j++) {
+			fdev->ds_list[j] = decode_and_add_ds(&p, mt);
+			if (fdev->ds_list[j] == NULL)
+				goto out_err_free;
+		}
+		fdev++;
+	}
 	return file_dev;
+
+out_err_free:
+	device_destroy(file_dev, mt->hlist);
+out_err:
+	dprintk("%s ERROR: returning NULL\n", __func__);
+	return NULL;
 }
 
 /* Decode the opaque device specified in 'dev'
@@ -312,7 +506,7 @@ decode_and_add_device(struct filelayout_mount_type *mt, struct pnfs_device* dev)
 {
 	struct nfs4_pnfs_dev_item* file_dev;
 
-	file_dev = decode_device(dev);
+	file_dev = decode_device(mt, dev);
 	if (!file_dev) {
 		printk(KERN_WARNING "%s Could not decode device\n",
 					__FUNCTION__);
@@ -437,8 +631,10 @@ nfs4_pnfs_dserver_get(struct inode *inode,
 
 	dev_id = layout->devs[stripe_idx].dev_id;
 
-	dserver->dev_item = nfs4_pnfs_device_get(inode, dev_id);
-	if (dserver->dev_item == NULL)
+	/* NOTE: resolved in following patch.
+	 *dserver->dev = nfs4_pnfs_device_get(inode, dev_id); */
+
+	if (dserver->dev == NULL)
 		return 1;
 	dserver->fh = &layout->devs[stripe_idx].fh;
 
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d2dcd0f..2a856b6 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4102,20 +4102,19 @@ out:
  * Issue the over-the-wire RPC DESTROY_SESSION.
  * The caller must serialize access to this routine.
  */
-int nfs4_proc_destroy_session(struct nfs_server *sp)
+int nfs4_proc_destroy_session(struct nfs4_session *session, struct rpc_clnt *clnt)
 {
 	int status = 0;
 	struct rpc_message msg;
 
 	dprintk("--> nfs4_proc_destroy_session\n");
-	BUG_ON(sp == NULL);
-	BUG_ON(sp->session == NULL);
+	BUG_ON(session == NULL);
 
 	msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION];
-	msg.rpc_argp = sp->session;
+	msg.rpc_argp = session;
 	msg.rpc_resp = NULL;
 	msg.rpc_cred = NULL;
-	status = rpc_call_sync(sp->nfs_client->cl_rpcclient, &msg, 0);
+	status = rpc_call_sync(clnt, &msg, 0);
 
 	if (status) {
 		printk(KERN_WARNING "Got error %d from the server on DESTROY_SESSION. Session has been destroyed regardless...\n", status);
@@ -4124,7 +4123,7 @@ int nfs4_proc_destroy_session(struct nfs_server *sp)
  	 * Since the caller has serialized access to this routine I don't
  	 * grab a lock to modify the expired value.
  	 */
-	nfs41_set_session_expired(sp->session);	/* Mark session as expired */
+	nfs41_set_session_expired(session);	/* Mark session as expired */
 
 	dprintk("<-- nfs4_proc_destroy_session\n");
 	return status;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index a46b1b1..c686b58 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1836,6 +1836,7 @@ error_splat_super:
 static void nfs4_kill_super(struct super_block *sb)
 {
 	struct nfs_server *server = NFS_SB(sb);
+	struct rpc_clnt *clnt = server->nfs_client->cl_rpcclient;
 
 	dprintk("--> %s\n", __FUNCTION__);
 	nfs_return_all_delegations(sb);
@@ -1847,7 +1848,7 @@ static void nfs4_kill_super(struct super_block *sb)
 		if (server->session) {
 			dprintk("%s Destroy session %p for nfs_server %p\n",
 				__FUNCTION__, server->session, server);
-			nfs4_proc_destroy_session(server);
+			nfs4_proc_destroy_session(server->session, clnt);
 		}
 		break;
 	default:
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 68118aa..c36b6dd 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -6,10 +6,12 @@
 
 #if defined (CONFIG_NFS_V4_1)
 #include <linux/nfs4_session.h>
+struct nfs4_session;	/* NFSv4.1 session */
 #endif
 
 struct nfs_iostats;
 
+
 /*
  * The nfs_client identifies our client state to the server.
  */
@@ -77,12 +79,11 @@ struct nfs_client {
 	/* The flags used for obtaining the clientid during EXCHANGE_ID */
 	u32			cl_exchange_flags;
 #endif
+#ifdef CONFIG_PNFS
+	struct nfs4_session *	 cl_ds_session; /* pNFS data server session */
+#endif /* CONFIG_PNFS */
 };
 
-#ifdef CONFIG_NFS_V4_1
-	struct nfs4_session;	/* NFSv4.1 session */
-#endif
-
 /*
  * NFS client parameters stored in the superblock.
  */
-- 
1.5.0.2



More information about the pNFS mailing list