Skip to contentSkip to conversation

layout-sim: layout recall callback (forgetful client)

PATCH New Benny Halevy 1 participant 1 message Jan 27, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 layout-sim: layout recall callback (forgetful client)

[Fixing typo in list address]

-------- Original Message --------
Subject: [PATCH] layout-sim: layout recall callback (forgetful client)
Date: Thu, 27 Jan 2011 17:06:06 +0200
From: Benny Halevy <[email protected]>
To: [email protected], [email protected]
CC: Benny Halevy <[email protected]>

Simulate cb_layoutrecall with the forget client model.
The client responds with NFS4ERR_DELAY if there are any calls it needs to wait for before processing the callback, or if there I/Os in flight (simulated randomally). When the layout can be returned, the client deleted it locally and replies synchronously with NFS4ERR_NOMATCHING_LAYOUT instead of sending layout return.

The server sends only one CB_LAYOUT_RECALL at a time and does not process any LAYOUTGETs while waiting on it, replying with NFS4ERR_RECALLCONFLICT. LAYOUTRETURN stateid sequencing is enforced so that only those sent after the client processed the layout recall callback are accepted. The layout recall "process" is completed either on NFS4ERR_RECALLCONFLICT or on a matching LAYOUTRETURN.

---
 client.c |   37 ++++++++++++++++++++++--
 layout.c |   21 +++++++++----
 layout.h |   18 +++++++++++-
 server.c |   93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 150 insertions(+), 19 deletions(-)
client.c +34 -3
index 61163b5..182db7b 100644
@@ -171,6 +171,8 @@ _reprocess_queue(void)
 	struct msg *m;
 
 	list_for_each_entry (m, &cl_queued.list, list) {
+		if (m->type == CB_LAYOUT_RECALL)
+			continue;
 		if (is_next(&m->stateid, &cl_layout.stateid) ||
 		    (m->type == LAYOUTRETURN &&
 		     m->stateid.type == OPEN_STATEID &&
@@ -227,6 +229,36 @@ out_free:
 }
 
 static void
+cl_recv_cb_layout_recall(struct msg *m)
+{
+	if ((m->stateid.type == OPEN_STATEID &&
+	     cl_layout.stateid.type != OPEN_STATEID) ||
+	    (m->stateid.seq > cl_layout.stateid.seq + 1)) {
+		dprintk(1, "%s: m=%p seq=%llu cl_layout.seq=%llu: waiting\n",
+			__func__, m,
+			llu(m->stateid.seq), llu(cl_layout.stateid.seq));
+		m->status = NFS4ERR_DELAY;
+		goto out;
+	}
+
+	BUG_ON(m->stateid.seq <= cl_layout.stateid.seq);
+	if (mynrand(10) < 3) {
+		dprintk(1, "%s: m=%p: simulating delay\n", __func__, m);
+		m->status = NFS4ERR_DELAY;
+		goto out;
+	}
+
+	/* forgetful model */
+	layout_delete(&cl_layout, &m->range);
+	cl_layout.stateid = m->stateid;
+	m->status = NFS4ERR_NOMATCHING_LAYOUT;
+
+out:
+	dprintk(1, "%s: m=%p status=%d\n", __func__, m, m->status);
+	enqueue(&srv_msg_queue, m);
+}
+
+static void
 _cl_recv_msg(struct msg *m)
 {
 	switch (m->type) {
@@ -236,10 +268,9 @@ _cl_recv_msg(struct msg *m)
 	case LAYOUTRETURN:
 		cl_recv_layoutreturn(m);
 		break;
-#if 0
-	case CB_LAYOUTRECALL:
+	case CB_LAYOUT_RECALL:
+		cl_recv_cb_layout_recall(m);
 		break;
-#endif
 	default:
 		BUG_ON(true);
 	}
layout.c +14 -7
index 94870f0..c5ad99a 100644
@@ -65,7 +65,7 @@ last_byte_offset(u64 start, u64 len)
  *                  |----------------|
  */
 static inline int
-lo_seg_overlapping(struct layout_range *l1, struct layout_range *l2)
+lo_seg_overlapping(const struct layout_range *l1, const struct layout_range *l2)
 {
 	u64 start1 = l1->offset;
 	u64 last1 = last_byte_offset(start1, l1->length);
@@ -82,13 +82,15 @@ lo_seg_overlapping(struct layout_range *l1, struct layout_range *l2)
 }
 
 bool
-layout_delete(struct layout *lo, struct layout_range *range)
+_lookup_layout(const char *func, struct layout *lo,
+	       const struct layout_range *range,
+	       bool do_delete)
 {
 	bool found = false;
 	struct layout_item *pos, *next;
 
 	dprintk(1, "%s: %s: offset=%llu length=%llu iomode=%d roc=%d\n",
-		__func__, lo->desc,
+		func, lo->desc,
 		llu(range->offset), llu(range->length),
 		range->iomode, range->roc);
 
@@ -98,9 +100,12 @@ layout_delete(struct layout *lo, struct layout_range *range)
 		    (!range->roc || pos->range.roc) &&
 		    lo_seg_overlapping(&pos->range, range)) {
 			dprintk(1, "%s: found l=%p\n", __func__, pos);
-			list_del(&pos->list);
-			myfree(pos);
 			found = true;
+			if (do_delete) {
+				list_del(&pos->list);
+				myfree(pos);
+			} else
+				break;
 		}
 	}
 
@@ -113,8 +118,10 @@ layout_verify(struct layout *server, struct layout *client)
 	bool ok = true, found;
 	struct layout_item *cl, *sl;
 
-	if ((client->stateid.type != server->stateid.type) ||
-	    (client->stateid.seq != server->stateid.seq)) {
+	if (((client->stateid.type != server->stateid.type) ||
+	     (client->stateid.seq != server->stateid.seq)) &&
+	    (!server->layout_recall_msg ||
+	     client->stateid.seq >= server->stateid.seq)) {
 		dprintk(0, "%s: cl stateid=%d:%llu srv stateid=%d:%llu\n",
 			__func__,
 			client->stateid.type, llu(client->stateid.seq),
layout.h +17 -1
index bafad13..895b145 100644
@@ -43,15 +43,31 @@ struct stateid {
 		    type resets to OPEN_STATEID */
 };
 
+struct msg;
+
 struct layout {
 	struct stateid stateid;
 	struct list_head segs;
 	char *desc;
+	struct msg *layout_recall_msg;
 };
 
 void layout_init(struct layout *, char *desc);
 void layout_insert(struct layout *, struct layout_range *);
-bool layout_delete(struct layout *, struct layout_range *);
+bool _lookup_layout(const char *func, struct layout *,
+		    const struct layout_range *,
+		    bool do_delete);
+
+static inline bool has_layout(struct layout *lo, const struct layout_range *range)
+{
+	return _lookup_layout(__func__, lo, range, false);
+}
+
+static inline bool layout_delete(struct layout *lo, const struct layout_range *range)
+{
+	return _lookup_layout(__func__, lo, range, true);
+}
+
 bool layout_verify(struct layout *server, struct layout *client);
 
 enum msg_type {
server.c +85 -8

146 lines not on this page · raw message

Signature · 1 line
1.7.3.4