return true;
}
+/*
+ * After a caller releases write-space or a request slot,
+ * re-enqueue the transport only when there is pending
+ * work that a thread could act on. The smp_mb() pairs
+ * with the smp_rmb() in svc_xprt_ready() and orders the
+ * preceding counter update before the flags read so a
+ * concurrent set_bit(XPT_DATA) is visible here.
+ */
+static void svc_xprt_resource_released(struct svc_xprt *xprt)
+{
+ smp_mb();
+ if (READ_ONCE(xprt->xpt_flags) &
+ (BIT(XPT_DATA) | BIT(XPT_DEFERRED)))
+ svc_xprt_enqueue(xprt);
+}
+
static void svc_xprt_release_slot(struct svc_rqst *rqstp)
{
struct svc_xprt *xprt = rqstp->rq_xprt;
if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) {
atomic_dec(&xprt->xpt_nr_rqsts);
- smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
- svc_xprt_enqueue(xprt);
+ svc_xprt_resource_released(xprt);
}
}
space += rqstp->rq_res.head[0].iov_len;
if (xprt && space < rqstp->rq_reserved) {
- atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
+ atomic_sub((rqstp->rq_reserved - space),
+ &xprt->xpt_reserved);
rqstp->rq_reserved = space;
- smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
- svc_xprt_enqueue(xprt);
+ svc_xprt_resource_released(xprt);
}
}
EXPORT_SYMBOL_GPL(svc_reserve);