]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: DAX request to dequeue half of a long CCB should not succeed
authorSanath Kumar <sanath.s.kumar@oracle.com>
Wed, 5 Apr 2017 04:56:49 +0000 (23:56 -0500)
committerChuck Anderson <chuck.anderson@oracle.com>
Mon, 24 Apr 2017 04:43:27 +0000 (21:43 -0700)
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 <rob.gardner@oracle.com>
Signed-off-by: Sanath Kumar <sanath.s.kumar@oracle.com>
Signed-off-by: Allen Pais <allen.pais@oracle.com>
arch/sparc/dax/dax_main.c

index 3f637bda7d88bf903d73eb64ccdb71d5dfb3e1de..8a4ffcb4bb361eb35841681cac52caf5be452b10 100644 (file)
@@ -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;
 }