]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/test/librbd/fsx.cc
import ceph 12.2.12
[ceph.git] / ceph / src / test / librbd / fsx.cc
index 444fdbefd590454860b476c53b343731a3690a1f..00c6847162c2358e5c06714d4182848c4fe5d54b 100644 (file)
@@ -89,6 +89,7 @@ int                   logcount = 0;   /* total ops */
  * FALLOCATE:  -       5
  * PUNCH HOLE: -       6
  * WRITESAME:  -       7
+ * COMPAREANDWRITE:    -       8
  *
  * When mapped read/writes are disabled, they are simply converted to normal
  * reads and writes. When fallocate/fpunch calls are disabled, they are
@@ -113,10 +114,11 @@ int                       logcount = 0;   /* total ops */
 #define OP_FALLOCATE   5
 #define OP_PUNCH_HOLE  6
 #define OP_WRITESAME   7
+#define OP_COMPARE_AND_WRITE   8
 /* rbd-specific operations */
-#define OP_CLONE        8
-#define OP_FLATTEN     9
-#define OP_MAX_FULL    10
+#define OP_CLONE        9
+#define OP_FLATTEN     10
+#define OP_MAX_FULL    11
 
 /* operation modifiers */
 #define OP_CLOSEOPEN   100
@@ -511,6 +513,8 @@ struct rbd_operations {
        int (*flatten)(struct rbd_ctx *ctx);
        ssize_t (*writesame)(struct rbd_ctx *ctx, uint64_t off, size_t len,
                             const char *buf, size_t data_len);
+        ssize_t (*compare_and_write)(struct rbd_ctx *ctx, uint64_t off, size_t len,
+                                     const char *cmp_buf, const char *buf);
 };
 
 char *pool;                    /* name of the pool our test image is in */
@@ -678,6 +682,31 @@ librbd_writesame(struct rbd_ctx *ctx, uint64_t off, size_t len,
        return n;
 }
 
+ssize_t
+librbd_compare_and_write(struct rbd_ctx *ctx, uint64_t off, size_t len,
+                         const char *cmp_buf, const char *buf)
+{
+        ssize_t n;
+        int ret;
+        uint64_t mismatch_off = 0;
+
+        n = rbd_compare_and_write(ctx->image, off, len, cmp_buf, buf, &mismatch_off, 0);
+        if (n == -EINVAL) {
+                return n;
+        } else if (n < 0) {
+                prt("rbd_compare_and_write mismatch(%llu, %zu, %llu) failed\n",
+                    off, len, mismatch_off);
+                return n;
+        }
+
+        ret = librbd_verify_object_map(ctx);
+        if (ret < 0) {
+                return ret;
+        }
+        return n;
+
+}
+
 int
 librbd_get_size(struct rbd_ctx *ctx, uint64_t *size)
 {
@@ -796,6 +825,7 @@ const struct rbd_operations librbd_operations = {
        librbd_clone,
        librbd_flatten,
        librbd_writesame,
+       librbd_compare_and_write,
 };
 
 int
@@ -933,7 +963,7 @@ krbd_discard(struct rbd_ctx *ctx, uint64_t off, uint64_t len)
        int ret;
 
        /*
-        * BLKDISCARD goes straight to disk and doesn't do anything
+        * BLKZEROOUT goes straight to disk and doesn't do anything
         * about dirty buffers.  This means we need to flush so that
         *
         *   write 0..3M
@@ -947,19 +977,22 @@ krbd_discard(struct rbd_ctx *ctx, uint64_t off, uint64_t len)
         *
         * returns "data 0000 data" rather than "data data data" in
         * case 1..2M was cached.
+        *
+         * Note: These cache coherency issues are supposed to be fixed
+         * in recent kernels.
         */
        ret = __krbd_flush(ctx, true);
        if (ret < 0)
                return ret;
 
        /*
-        * off and len must be 512-byte aligned, otherwise BLKDISCARD
+        * off and len must be 512-byte aligned, otherwise BLKZEROOUT
         * will fail with -EINVAL.  This means that -K (enable krbd
         * mode) requires -h 512 or similar.
         */
-       if (ioctl(ctx->krbd_fd, BLKDISCARD, &range) < 0) {
+       if (ioctl(ctx->krbd_fd, BLKZEROOUT, &range) < 0) {
                ret = -errno;
-               prt("BLKDISCARD(%llu, %llu) failed\n", off, len);
+               prt("BLKZEROOUT(%llu, %llu) failed\n", off, len);
                return ret;
        }
 
@@ -1306,6 +1339,18 @@ logdump(void)
                                badoff < lp->args[0] + lp->args[1])
                                prt("\t***WSWSWSWS");
                        break;
+               case OP_COMPARE_AND_WRITE:
+                        prt("COMPARE_AND_WRITE    0x%x thru 0x%x\t(0x%x bytes)",
+                            lp->args[0], lp->args[0] + lp->args[1] - 1,
+                            lp->args[1]);
+                        if (lp->args[0] > lp->args[2])
+                            prt(" HOLE");
+                        else if (lp->args[0] + lp->args[1] > lp->args[2])
+                            prt(" EXTEND");
+                        if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+                                badoff < lp->args[0] + lp->args[1])
+                                prt("\t***WWWW");
+                        break;
                case OP_CLONE:
                        prt("CLONE");
                        break;
@@ -1522,6 +1567,8 @@ create_image()
                simple_err("Error creating ioctx", r);
                goto failed_krbd;
        }
+        rados_application_enable(ioctx, "rbd", 1);
+
        if (clone_calls || journal_replay) {
                 uint64_t features = 0;
                 if (clone_calls) {
@@ -1913,6 +1960,72 @@ dowritesame(unsigned offset, unsigned size)
                doflush(offset, size);
 }
 
+void
+docompareandwrite(unsigned offset, unsigned size)
+{
+        int ret;
+
+        if (skip_partial_discard) {
+                if (!quiet && testcalls > simulatedopcount)
+                        prt("compare and write disabled\n");
+                log4(OP_SKIPPED, OP_COMPARE_AND_WRITE, offset, size);
+                return;
+        }
+
+        offset -= offset % writebdy;
+        if (o_direct)
+                size -= size % writebdy;
+
+        if (size == 0) {
+                if (!quiet && testcalls > simulatedopcount && !o_direct)
+                        prt("skipping zero size read\n");
+                log4(OP_SKIPPED, OP_READ, offset, size);
+                return;
+        }
+
+        if (size + offset > file_size) {
+                if (!quiet && testcalls > simulatedopcount)
+                        prt("skipping seek/compare past end of file\n");
+                log4(OP_SKIPPED, OP_COMPARE_AND_WRITE, offset, size);
+                return;
+        }
+
+        memcpy(temp_buf + offset, good_buf + offset, size);
+       gendata(original_buf, good_buf, offset, size);
+        log4(OP_COMPARE_AND_WRITE, offset, size, 0);
+
+        if (testcalls <= simulatedopcount)
+                return;
+
+        if (!quiet &&
+               ((progressinterval && testcalls % progressinterval == 0) ||
+                      (debug &&
+                      (monitorstart == -1 ||
+                       (static_cast<long>(offset + size) > monitorstart &&
+                        (monitorend == -1 ||
+                         static_cast<long>(offset) <= monitorend))))))
+               prt("%lu compareandwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+                   offset, offset + size - 1, size);
+
+        ret = ops->compare_and_write(&ctx, offset, size, temp_buf + offset,
+                                     good_buf + offset);
+        if (ret != (ssize_t)size) {
+                if (ret == -EINVAL) {
+                        memcpy(good_buf + offset, temp_buf + offset, size);
+                        return;
+                }
+                if (ret < 0)
+                        prterrcode("docompareandwrite: ops->compare_and_write", ret);
+                else
+                        prt("short write: 0x%x bytes instead of 0x%x\n", ret, size);
+                report_failure(151);
+                return;
+        }
+
+        if (flush_enabled)
+                doflush(offset, size);
+}
+
 void clone_filename(char *buf, size_t len, int clones)
 {
        snprintf(buf, len, "%s/fsx-%s-parent%d",
@@ -2290,6 +2403,14 @@ test(void)
                        log4(OP_SKIPPED, OP_WRITESAME, offset, size);
                        goto out;
                }
+               break;
+        case OP_COMPARE_AND_WRITE:
+                /* compare_and_write not implemented */
+                if (!ops->compare_and_write) {
+                        log4(OP_SKIPPED, OP_COMPARE_AND_WRITE, offset, size);
+                        goto out;
+                }
+               break;
        }
 
        switch (op) {
@@ -2328,6 +2449,10 @@ test(void)
                TRIM_OFF_LEN(offset, size, maxfilelen);
                dowritesame(offset, size);
                break;
+        case OP_COMPARE_AND_WRITE:
+                TRIM_OFF_LEN(offset, size, file_size);
+                docompareandwrite(offset, size);
+                break;
 
        case OP_CLONE:
                do_clone();