Пример #1
0
int
do_zero_device (const char *device)
{
  int64_t ssize = do_blockdev_getsize64 (device);
  if (ssize == -1)
    return -1;
  uint64_t size = (uint64_t) ssize;

  int fd = open (device, O_RDWR|O_CLOEXEC);
  if (fd == -1) {
    reply_with_perror ("%s", device);
    return -1;
  }

  char buf[sizeof zero_buf];

  uint64_t pos = 0;

  while (pos < size) {
    uint64_t n64 = size - pos;
    size_t n;
    if (n64 > sizeof buf)
      n = sizeof buf;
    else
      n = (size_t) n64; /* safe because of if condition */

    /* Check if the block is already zero before overwriting it. */
    ssize_t r;
    r = pread (fd, buf, n, pos);
    if (r == -1) {
      reply_with_perror ("pread: %s at offset %" PRIu64, device, pos);
      close (fd);
      return -1;
    }

    if (!is_zero (buf, sizeof buf)) {
      r = pwrite (fd, zero_buf, n, pos);
      if (r == -1) {
        reply_with_perror ("pwrite: %s (with %" PRId64 " bytes left to write)",
                           device, size);
        close (fd);
        return -1;
      }
      pos += r;
    }
    else
      pos += n;

    notify_progress (pos, size);
  }

  if (close (fd) == -1) {
    reply_with_perror ("close: %s", device);
    return -1;
  }

  return 0;
}
Пример #2
0
/* Used to test read and write speed. */
static char *
debug_device_speed (const char *subcmd, size_t argc, char *const *const argv)
{
  const char *device;
  int writing, err;
  unsigned secs;
  int64_t size, position, copied;
  CLEANUP_FREE void *buf = NULL;
  struct timeval now, end;
  ssize_t r;
  int fd;
  char *ret;

  if (argc != 3) {
  bad_args:
    reply_with_error ("device_speed <device> <r|w> <secs>");
    return NULL;
  }

  device = argv[0];
  if (STREQ (argv[1], "r") || STREQ (argv[1], "read"))
    writing = 0;
  else if (STREQ (argv[1], "w") || STREQ (argv[1], "write"))
    writing = 1;
  else
    goto bad_args;
  if (sscanf (argv[2], "%u", &secs) != 1)
    goto bad_args;

  /* Find the size of the device. */
  size = do_blockdev_getsize64 (device);
  if (size == -1)
    return NULL;

  if (size < BUFSIZ) {
    reply_with_error ("%s: device is too small", device);
    return NULL;
  }

  /* Because we're using O_DIRECT, the buffer must be aligned. */
  err = posix_memalign (&buf, 4096, BUFSIZ);
  if (err != 0) {
    reply_with_error_errno (err, "posix_memalign");
    return NULL;
  }

  /* Any non-zero data will do. */
  memset (buf, 100, BUFSIZ);

  fd = open (device, (writing ? O_WRONLY : O_RDONLY) | O_CLOEXEC | O_DIRECT);
  if (fd == -1) {
    reply_with_perror ("open: %s", device);
    return NULL;
  }

  /* Now we read or write to the device, wrapping around to the
   * beginning when we reach the end, and only stop when <secs>
   * seconds has elapsed.
   */
  gettimeofday (&end, NULL);
  end.tv_sec += secs;

  position = copied = 0;

  for (;;) {
    gettimeofday (&now, NULL);
    if (now.tv_sec > end.tv_sec ||
        (now.tv_sec == end.tv_sec && now.tv_usec > end.tv_usec))
      break;

    /* Because of O_DIRECT, only write whole, aligned buffers. */
  again:
    if (size - position < BUFSIZ) {
      position = 0;
      goto again;
    }

    /*
    if (verbose) {
      fprintf (stderr, "p%s (fd, buf, %d, %" PRIi64 ")\n",
               writing ? "write" : "read", BUFSIZ, position);
    }
    */

    if (writing) {
      r = pwrite (fd, buf, BUFSIZ, position);
      if (r == -1) {
        reply_with_perror ("write: %s", device);
        goto error;
      }
    }
    else {
      r = pread (fd, buf, BUFSIZ, position);
      if (r == -1) {
        reply_with_perror ("read: %s", device);
        goto error;
      }
      if (r == 0) {
        reply_with_error ("unexpected end of file while reading");
        goto error;
      }
    }
    position += BUFSIZ;
    copied += r;
  }

  if (close (fd) == -1) {
    reply_with_perror ("close: %s", device);
    return NULL;
  }

  if (asprintf (&ret, "%" PRIi64, copied) == -1) {
    reply_with_perror ("asprintf");
    return NULL;
  }

  return ret;

 error:
  close (fd);
  return NULL;
}