@@ -422,16 +422,19 @@ static int nvme_streams_deallocate(struct nvme_ns *ns)
static void nvme_write_hint_work(struct work_struct *work)
{
- struct nvme_ns *ns = container_of(work, struct nvme_ns, write_hint_work);
int ret, nr_streams;
+ struct nvme_ns *ns;
+ ns = container_of(work, struct nvme_ns, write_hint_work);
if (ns->nr_streams)
return;
- nr_streams = streams_per_ns;
- if (nr_streams > ns->ctrl->nssa)
- nr_streams = ns->ctrl->nssa;
-
+ /*
+ * For now, always ask for 'streams_per_ns' number of streams. It's
+ * possible that we will then run out of streams if we have many
+ * name spaces. Different policies could be implemented.
+ */
+ nr_streams = min_t(unsigned int, streams_per_ns, ns->ctrl->nssa);
ret = nvme_streams_allocate(ns, nr_streams);
if (ret <= 0)
goto err;
@@ -457,30 +460,41 @@ static void nvme_configure_streams(struct nvme_ns *ns)
schedule_work(&ns->write_hint_work);
}
-static enum rw_hint nvme_get_write_stream(struct nvme_ns *ns,
- struct request *req)
+/*
+ * Check if 'req' has a write hint associated with it. If it does, assign
+ * a valid namespace stream to the write. If we haven't setup streams yet,
+ * kick off configuration and ignore the hints until that has completed.
+ */
+static void nvme_assign_write_stream(struct nvme_ns *ns, struct request *req,
+ u16 *control, u32 *dsmgmt)
{
- enum rw_hint streamid = req->cmd_flags & REQ_WRITE_LIFE_MASK;
+ enum rw_hint streamid;
+
+ streamid = (req->cmd_flags & REQ_WRITE_LIFE_MASK)
+ >> __REQ_WRITE_HINT_SHIFT;
+ if (streamid == WRITE_LIFE_NONE)
+ return;
+
+ if (!ns->nr_streams) {
+ nvme_configure_streams(ns);
+ return;
+ }
- if (req_op(req) != REQ_OP_WRITE ||
- !(ns->ctrl->oacs & NVME_CTRL_OACS_DIRECTIVES))
- return WRITE_LIFE_NONE;
+ /* for now just round-robin, do something more clever later */
+ if (streamid > ns->nr_streams)
+ streamid = (streamid % ns->nr_streams) + 1;
- streamid = req->cmd_flags & REQ_WRITE_LIFE_MASK;
if (streamid < ARRAY_SIZE(req->q->write_hints))
req->q->write_hints[streamid] += blk_rq_bytes(req) >> 9;
- if (streamid <= ns->nr_streams)
- return streamid;
-
- /* for now just round-robin, do something more clever later */
- return (streamid % ns->nr_streams) + 1;
+ *control |= NVME_RW_DTYPE_STREAMS;
+ *dsmgmt |= streamid << 16;
}
static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
struct nvme_command *cmnd)
{
- enum rw_hint stream;
+ struct nvme_ctrl *ctrl = ns->ctrl;
u16 control = 0;
u32 dsmgmt = 0;
@@ -498,19 +512,9 @@ static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
- /*
- * If we support streams and this request is a write with a valid
- * hint, then flag it as such. If we haven't allocated streams on
- * this ns before, do so lazily.
- */
- stream = nvme_get_write_stream(ns, req);
- if (stream != WRITE_LIFE_NONE) {
- if (ns->nr_streams) {
- control |= NVME_RW_DTYPE_STREAMS;
- dsmgmt |= (stream << 16);
- } else
- nvme_configure_streams(ns);
- }
+ if (req_op(req) == REQ_OP_WRITE &&
+ (ctrl->oacs & NVME_CTRL_OACS_DIRECTIVES))
+ nvme_assign_write_stream(ns, req, &control, &dsmgmt);
if (ns->ms) {
switch (ns->pi_type) {