@@ -65,6 +65,7 @@ verify_stateid(struct msg *m)
/* FIXME: use an actual limit on parallelism */
return m->status = NFS4ERR_OLD_STATEID;
} else if (m->stateid.type == LAYOUT_STATEID) {
+ /* FIXME: is this specified for LAYOUTRETURN. */
if (srv_layout.layout_recall_msg &&
m->stateid.seq < srv_layout.layout_recall_msg->stateid.seq)
return m->status = NFS4ERR_OLD_STATEID;
@@ -78,10 +79,26 @@ verify_stateid(struct msg *m)
return 0;
}
+static bool
+is_conflicting(struct layout_range *lr, struct layout_range *r)
+{
+ if (lr->iomode != IOMODE_ANY && lr->iomode != r->iomode)
+ return false;
+ if (r->offset >= lr->offset)
+ return (lr->length == NFS4_MAX_UINT64) ||
+ (lr->offset + lr->length > r->offset);
+ else
+ return (r->length == NFS4_MAX_UINT64) ||
+ (r->offset + r->length > lr->offset);
+}
+
static void
srv_recv_layoutget(struct msg *m)
{
- if (srv_layout.layout_recall_msg) {
+ struct msg *lrm = srv_layout.layout_recall_msg;
+
+ /* See section 12.5.5.2.1.3 */
+ if (lrm && is_conflicting(&lrm->range, &m->range)) {
m->status = NFS4ERR_RECALLCONFLICT;
goto out;
}