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; }
/* 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; }