[PATCH 1/5] pnfs_post_submit: restore CB_NOTIFY_DEVICEID

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Andy Adamson <andros@xxxxxxxxxx>

Reverts "pnfs_submit: remove CB_NOTIFY_DEVICEID"
and replaces "pnfs_submit: remove filelayout CB_NOTIFY_DEVICE support"

With the generic device id cache, there is no need for a per layout driver
delete_deviceid function.

Note: This functionlaity is incomplete as all layout segments referring to
the 'to be removed device id' need to be reaped, and all in flight I/O drained.

Signed-off-by: Andy Adamson <andros@xxxxxxxxxx>
---
 fs/nfs/callback_proc.c    |   53 ++++++++++++++++++++++++
 fs/nfs/callback_xdr.c     |   97 ++++++++++++++++++++++++++++++++++++++++++++-
 fs/nfs/pnfs.c             |   16 ++++++-
 include/linux/nfs4_pnfs.h |    2 +
 4 files changed, 165 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 025f31d..ebf86df 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -325,6 +325,59 @@ out:
 	return res;
 }
 
+/* Remove the deviceid(s) from the nfs_client deviceid cache */
+static __be32 pnfs_devicenotify_client(struct nfs_client *clp,
+				       struct cb_pnfs_devicenotifyargs *args)
+{
+	uint32_t type;
+	int i;
+
+	dprintk("%s: --> clp %p\n", __func__, clp);
+
+	for (i = 0; i < args->ndevs; i++) {
+		struct cb_pnfs_devicenotifyitem *dev = &args->devs[i];
+		type = dev->cbd_notify_type;
+		if (type == NOTIFY_DEVICEID4_DELETE && clp->cl_devid_cache)
+			nfs4_delete_device(clp->cl_devid_cache,
+					   &dev->cbd_dev_id);
+		else if (type == NOTIFY_DEVICEID4_CHANGE)
+			printk(KERN_ERR "%s: NOTIFY_DEVICEID4_CHANGE "
+					"not supported\n", __func__);
+	}
+	return 0;
+}
+
+__be32 pnfs_cb_devicenotify(struct cb_pnfs_devicenotifyargs *args,
+			    void *dummy)
+{
+	struct nfs_client *clp;
+	__be32 res = 0;
+	unsigned int num_client = 0;
+
+	dprintk("%s: -->\n", __func__);
+
+	res = __constant_htonl(NFS4ERR_INVAL);
+	clp = nfs_find_client(args->addr, 4);
+	if (clp == NULL) {
+		dprintk("%s: no client for addr %u.%u.%u.%u\n",
+			__func__, NIPQUAD(args->addr));
+		goto out;
+	}
+
+	do {
+		struct nfs_client *prev = clp;
+		num_client++;
+		res = pnfs_devicenotify_client(clp, args);
+		clp = nfs_find_client_next(prev);
+		nfs_put_client(prev);
+	} while (clp != NULL);
+
+out:
+	dprintk("%s: exit with status = %d numclient %u\n",
+		__func__, ntohl(res), num_client);
+	return res;
+}
+
 int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
 {
 	if (delegation == NULL)
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 1856181..69a026d 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -23,6 +23,7 @@
 
 #if defined(CONFIG_NFS_V4_1)
 #define CB_OP_LAYOUTRECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_DEVICENOTIFY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
 #define CB_OP_SEQUENCE_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
 					4 + 1 + 3)
 #define CB_OP_RECALLANY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
@@ -267,6 +268,94 @@ out:
 	return status;
 }
 
+static
+__be32 decode_pnfs_devicenotify_args(struct svc_rqst *rqstp,
+				     struct xdr_stream *xdr,
+				     struct cb_pnfs_devicenotifyargs *args)
+{
+	__be32 *p;
+	__be32 status = 0;
+	u32 tmp;
+	int n, i;
+	args->ndevs = 0;
+
+	args->addr = svc_addr(rqstp);
+
+	/* Num of device notifications */
+	p = read_buf(xdr, sizeof(uint32_t));
+	if (unlikely(p == NULL)) {
+		status = htonl(NFS4ERR_RESOURCE);
+		goto out;
+	}
+	n = ntohl(*p++);
+	if (n <= 0)
+		goto out;
+
+	/* XXX: need to possibly return error in this case */
+	if (n > NFS4_DEV_NOTIFY_MAXENTRIES) {
+		dprintk("%s: Processing (%d) notifications out of (%d)\n",
+			__func__, NFS4_DEV_NOTIFY_MAXENTRIES, n);
+		n = NFS4_DEV_NOTIFY_MAXENTRIES;
+	}
+
+	/* Decode each dev notification */
+	for (i = 0; i < n; i++) {
+		struct cb_pnfs_devicenotifyitem *dev = &args->devs[i];
+
+		p = read_buf(xdr, (4 * sizeof(uint32_t))
+			     + NFS4_PNFS_DEVICEID4_SIZE);
+		if (unlikely(p == NULL)) {
+			status = htonl(NFS4ERR_RESOURCE);
+			goto out;
+		}
+
+		tmp = ntohl(*p++);	/* bitmap size */
+		if (tmp != 1) {
+			status = htonl(NFS4ERR_INVAL);
+			goto out;
+		}
+		dev->cbd_notify_type = ntohl(*p++);
+		if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
+		    dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
+			status = htonl(NFS4ERR_INVAL);
+			goto out;
+		}
+
+		tmp = ntohl(*p++);	/* opaque size */
+		if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
+		     (tmp != NFS4_PNFS_DEVICEID4_SIZE + 8)) ||
+		    ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
+		     (tmp != NFS4_PNFS_DEVICEID4_SIZE + 4))) {
+			status = htonl(NFS4ERR_INVAL);
+			goto out;
+		}
+		dev->cbd_layout_type = ntohl(*p++);
+		memcpy(dev->cbd_dev_id.data, p, NFS4_PNFS_DEVICEID4_SIZE);
+		p += XDR_QUADLEN(NFS4_PNFS_DEVICEID4_SIZE);
+
+		if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
+			p = read_buf(xdr, sizeof(uint32_t));
+			if (unlikely(p == NULL)) {
+				status = htonl(NFS4ERR_DELAY);
+				goto out;
+			}
+			dev->cbd_immediate = ntohl(*p++);
+		} else {
+			dev->cbd_immediate = 0;
+		}
+
+		args->ndevs++;
+
+		dprintk("%s: type %d layout 0x%x immediate %d\n",
+			__func__, dev->cbd_notify_type, dev->cbd_layout_type,
+			dev->cbd_immediate);
+	}
+out:
+	dprintk("%s: status %d ndevs %d\n",
+		__func__, ntohl(status), args->ndevs);
+	return status;
+}
+
 static __be32 decode_sessionid(struct xdr_stream *xdr,
 				 struct nfs4_sessionid *sid)
 {
@@ -622,11 +711,11 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
 	case OP_CB_RECALL_ANY:
 	case OP_CB_RECALL_SLOT:
 	case OP_CB_LAYOUTRECALL:
+	case OP_CB_NOTIFY_DEVICEID:
 		*op = &callback_ops[op_nr];
 		break;
 
 	case OP_CB_NOTIFY:
-	case OP_CB_NOTIFY_DEVICEID:
 	case OP_CB_PUSH_DELEG:
 	case OP_CB_RECALLABLE_OBJ_AVAIL:
 	case OP_CB_WANTS_CANCELLED:
@@ -792,6 +881,12 @@ static struct callback_op callback_ops[] = {
 			(callback_decode_arg_t)decode_pnfs_layoutrecall_args,
 		.res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
 	},
+	[OP_CB_NOTIFY_DEVICEID] = {
+		.process_op = (callback_process_op_t)pnfs_cb_devicenotify,
+		.decode_args =
+			(callback_decode_arg_t)decode_pnfs_devicenotify_args,
+		.res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
+	},
 	[OP_CB_SEQUENCE] = {
 		.process_op = (callback_process_op_t)nfs4_callback_sequence,
 		.decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 1560b4d..af6424a 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2359,7 +2359,8 @@ nfs4_add_deviceid(struct nfs4_deviceid_cache *c, struct nfs4_deviceid *new)
 EXPORT_SYMBOL(nfs4_add_deviceid);
 
 static int
-nfs4_remove_deviceid(struct nfs4_deviceid_cache *c, long hash)
+nfs4_remove_deviceid(struct nfs4_deviceid_cache *c, long hash,
+		     struct pnfs_deviceid *id)
 {
 	struct nfs4_deviceid *d;
 	struct hlist_node *n;
@@ -2367,6 +2368,8 @@ nfs4_remove_deviceid(struct nfs4_deviceid_cache *c, long hash)
 	dprintk("--> %s hash %ld\n", __func__, hash);
 	spin_lock(&c->dc_lock);
 	hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) {
+		if (id && memcmp(id, &d->de_id, NFS4_PNFS_DEVICEID4_SIZE))
+			continue;
 		hlist_del_rcu(&d->de_node);
 		spin_unlock(&c->dc_lock);
 		synchronize_rcu();
@@ -2379,6 +2382,15 @@ nfs4_remove_deviceid(struct nfs4_deviceid_cache *c, long hash)
 	return 0;
 }
 
+void
+nfs4_delete_device(struct nfs4_deviceid_cache *c, struct pnfs_deviceid *id)
+{
+	long hash = nfs4_deviceid_hash(id);
+
+	nfs4_remove_deviceid(c, hash, id);
+}
+EXPORT_SYMBOL(nfs4_delete_device);
+
 static void
 nfs4_free_deviceid_cache(struct kref *kref)
 {
@@ -2390,7 +2402,7 @@ nfs4_free_deviceid_cache(struct kref *kref)
 	for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++) {
 		more = 1;
 		while (more)
-			more = nfs4_remove_deviceid(cache, i);
+			more = nfs4_remove_deviceid(cache, i, NULL);
 	}
 	kfree(cache);
 }
diff --git a/include/linux/nfs4_pnfs.h b/include/linux/nfs4_pnfs.h
index 81701a3..1efea2a 100644
--- a/include/linux/nfs4_pnfs.h
+++ b/include/linux/nfs4_pnfs.h
@@ -304,6 +304,8 @@ extern void nfs4_set_layout_deviceid(struct pnfs_layout_segment *,
 extern void nfs4_unset_layout_deviceid(struct pnfs_layout_segment *,
 				struct nfs4_deviceid *,
 				void (*free_callback)(struct kref *));
+extern void nfs4_delete_device(struct nfs4_deviceid_cache *,
+				struct pnfs_deviceid *);
 
 /* pNFS client callback functions.
  * These operations allow the layout driver to access pNFS client
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux