From d572289a17562f78a0ecb91e8733b79eaf76b01e Mon Sep 17 00:00:00 2001 From: Sanath Kumar Date: Tue, 4 Apr 2017 23:56:49 -0500 Subject: [PATCH] sparc64: DAX request to dequeue half of a long CCB should not succeed Orabug: 25827254 When a dequeue call is made to the driver such that the last CCB in the request is the first half of a long ccb, the driver does not report an error and releases the BIP buffer for the CCBs dequeued up until then. This was detected by a ioctl_test23 written by Stanislav specifically to validate the above scenario. This bug fix addresses both the above issues. Reviewed-by: Rob Gardner Signed-off-by: Sanath Kumar Signed-off-by: Allen Pais --- arch/sparc/dax/dax_main.c | 50 ++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/sparc/dax/dax_main.c b/arch/sparc/dax/dax_main.c index 3f637bda7d88..8a4ffcb4bb36 100644 --- a/arch/sparc/dax/dax_main.c +++ b/arch/sparc/dax/dax_main.c @@ -35,7 +35,7 @@ static int dax_validate_ccb(union ccb *); static int dax_preprocess_usr_ccbs(struct dax_ctx *, union ccb *, size_t); static void dax_ctx_fini(struct dax_ctx *); static void dax_ctx_flush_decommit_ccbs(struct dax_ctx *); -static int dax_ccb_flush_contig(struct dax_ctx *, int, int, bool); +static int dax_ccb_flush_contig(struct dax_ctx *, int, int, bool, bool); static void dax_ccb_wait(struct dax_ctx *, int); static void dax_state_destroy(struct file *f); @@ -435,8 +435,18 @@ static int dax_ioctl_ca_dequeue(void *arg, struct file *f) n_dq = min(n_remain, n_avail); end_idx = start_idx + n_dq; - if (dax_ccb_flush_contig(dax_ctx, start_idx, end_idx, false)) { - rv = -EBUSY; + rv = dax_ccb_flush_contig(dax_ctx, start_idx, end_idx, + false, true); + if (rv != 0) { + /* Attempted to dequeue single CA for long CCB. All + * the CCBs till then are dequeued, So release their + * backing BIP buffer + */ + if (rv == -EINVAL) { + n_dq--; + dax_ccb_buffer_decommit(dax_ctx, n_dq); + usr_args.dcd_len_dequeued += NCCB_TO_CA_BYTE(n_dq); + } goto ca_dequeue_end; } @@ -975,12 +985,12 @@ static void dax_ctx_flush_decommit_ccbs(struct dax_ctx *dax_ctx) /* Wait for all CCBs to complete. Do not remove from CCB buffer */ dax_ccb_flush_contig(dax_ctx, CCB_BYTE_TO_NCCB(dax_ctx->a_start), - CCB_BYTE_TO_NCCB(dax_ctx->a_end), true); + CCB_BYTE_TO_NCCB(dax_ctx->a_end), true, false); if (dax_ctx->b_end > 0) dax_ccb_flush_contig(dax_ctx, 0, CCB_BYTE_TO_NCCB(dax_ctx->b_end), - true); + true, false); /* decommit all */ while (dax_ccb_buffer_get_contig_ccbs(dax_ctx, &n_contig_ccbs) >= 0) { @@ -991,7 +1001,8 @@ static void dax_ctx_flush_decommit_ccbs(struct dax_ctx *dax_ctx) } static int dax_ccb_flush_contig(struct dax_ctx *dax_ctx, int start_idx, - int end_idx, bool wait) + int end_idx, bool wait, + bool check_long_ccb_error) { int i; @@ -1001,6 +1012,18 @@ static int dax_ccb_flush_contig(struct dax_ctx *dax_ctx, int start_idx, u8 status; union ccb *ccb = &dax_ctx->ccb_buf[i]; + if (check_long_ccb_error && IS_LONG_CCB(ccb) && + (i == (end_idx - 1))) { + /* + * Validate that the user must dequeue 2 CAs for a long + * CCB. In other words, the last entry in a contig + * block cannot be a long CCB. + */ + dax_err("invalid attempt to dequeue single CA for long CCB, index=%d", + i); + return -EINVAL; + } + if (wait) { dax_ccb_wait(dax_ctx, i); } else { @@ -1017,20 +1040,9 @@ static int dax_ccb_flush_contig(struct dax_ctx *dax_ctx, int start_idx, /* free any locked pages associated with this ccb */ dax_unlock_pages_ccb(dax_ctx, i, ccb, true); - if (IS_LONG_CCB(ccb)) { - /* - * Validate that the user must dequeue 2 CAs for a long - * CCB. In other words, the last entry in a contig - * block cannot be a long CCB. - */ - if (i == end_idx) { - dax_err("invalid attempt to dequeue single CA for long CCB, index=%d", - i); - return -EINVAL; - } - /* skip over 64B data of long CCB */ + /* skip over 64B data of long CCB */ + if (IS_LONG_CCB(ccb)) i++; - } } return 0; } -- 2.50.1