commit 625ca7f8fbe02b9bb9947bf821c7e6f51ab90852 Author: Kent Overstreet Date: Tue May 4 17:58:22 2010 -0800 Initial commit diff --git a/bcache-test.c b/bcache-test.c new file mode 100644 index 00000000..33218e53 --- /dev/null +++ b/bcache-test.c @@ -0,0 +1,127 @@ +#define _XOPEN_SOURCE 500 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define Pread(fd, buf, size, offset) do { \ + int _read = 0, _r; \ + while (_read < size) { \ + _r = pread(fd, buf, (size) - _read, (offset) + _read); \ + if (_r <= 0) \ + goto err; \ + _read += _r; \ + } \ +} while (0) + +/* Marsaglia polar method + */ +double normal() +{ + double x, y, s; + static double n = 0 / (double) 0; + + if (n == n) { + x = n; + n = 0 / (double) 0; + return x; + } + + do { + x = random() / (double) (RAND_MAX / 2) - 1; + y = random() / (double) (RAND_MAX / 2) - 1; + + s = x * x + y * y; + } while (s >= 1); + + s = sqrt(-2 * log(s) / s); + n = y * s; + return x * s; +} + +long getblocks(int fd) +{ + long ret; + struct stat statbuf; + if (fstat(fd, &statbuf)) { + perror("stat error\n"); + exit(EXIT_FAILURE); + } + ret = statbuf.st_blocks; + if (S_ISBLK(statbuf.st_mode)) + if (ioctl(fd, BLKGETSIZE, &ret)) { + perror("ioctl error"); + exit(EXIT_FAILURE); + } + return ret; +} + +int main(int argc, char **argv) +{ + bool walk = false, randsize = false, verbose = false; + int fd1, fd2, direct = 0; + long size, i; + + if (argc < 3) { + printf("Please enter a cache device and raw device\n"); + exit(EXIT_FAILURE); + } + + for (i = 3; i < argc; i++) { + if (strcmp(argv[i], "direct") == 0) + direct = O_DIRECT; + if (strcmp(argv[i], "walk") == 0) + walk = true; + if (strcmp(argv[i], "verbose") == 0) + verbose = true; + if (strcmp(argv[i], "size") == 0) + randsize = true; + } + + fd1 = open(argv[1], O_RDONLY|direct); + fd2 = open(argv[2], O_RDONLY|direct); + if (fd1 == -1 || fd2 == -1) { + perror("Error opening device"); + exit(EXIT_FAILURE); + } + + size = MIN(getblocks(fd1), getblocks(fd2)) / 8; + printf("size %li\n", size); + + for (i = 0;; i++) { + char buf1[4096 * 16], buf2[4096 * 16]; + long offset; + int pages = randsize ? MAX(MIN(abs(normal()) * 4, 16), 1) : 1; + + offset = walk ? offset * normal() * 2 : random(); + offset %= size; + + if (verbose) + printf("Loop %li offset %li\n", i, offset); + else if (!(i % 100)) + printf("Loop %li\n", i); + + Pread(fd1, buf1, 4096 * pages, offset << 12); + Pread(fd2, buf2, 4096 * pages, offset << 12); + + if (memcmp(buf1, buf2, 4096 * pages)) { + printf("Bad read! offset %li", offset << 12); + exit(EXIT_FAILURE); + } + } +err: + perror("Read error"); + exit(EXIT_FAILURE); +} diff --git a/make-bcache.c b/make-bcache.c new file mode 100644 index 00000000..54828bbc --- /dev/null +++ b/make-bcache.c @@ -0,0 +1,108 @@ +#define _XOPEN_SOURCE 500 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char bcache_magic[] = { + 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, + 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 }; + +struct cache_sb { + uint8_t magic[16]; + uint32_t version; + uint16_t block_size; /* sectors */ + uint16_t bucket_size; /* sectors */ + uint32_t journal_start; /* buckets */ + uint32_t first_bucket; /* start of data */ + uint64_t nbuckets; /* device size */ + uint64_t btree_root; + uint16_t btree_level; +}; + +struct bucket_disk { + uint16_t priority; + uint8_t generation; +} __attribute((packed)); + +char zero[4096]; + +int main(int argc, char **argv) +{ + long n; + int fd, i; + struct stat statbuf; + struct cache_sb sb; + + if (argc < 2) { + printf("Please supply a device\n"); + exit(EXIT_FAILURE); + } + + fd = open(argv[1], O_RDWR); + if (!fd) { + perror("Can't open dev\n"); + exit(EXIT_FAILURE); + } + + if (fstat(fd, &statbuf)) { + perror("stat error\n"); + exit(EXIT_FAILURE); + } + if (!S_ISBLK(statbuf.st_mode)) + n = statbuf.st_blocks; + else + if (ioctl(fd, BLKGETSIZE, &n)) { + perror("ioctl error"); + exit(EXIT_FAILURE); + } + + memcpy(sb.magic, bcache_magic, 16); + sb.version = 0; + sb.block_size = 8; + sb.bucket_size = 32; + sb.nbuckets = n / sb.bucket_size; + + do + sb.first_bucket = ((--sb.nbuckets * sizeof(struct bucket_disk)) + + 4096 * 3) / (sb.bucket_size * 512) + 1; + while ((sb.nbuckets + sb.first_bucket) * sb.bucket_size * 512 + > statbuf.st_size); + + sb.journal_start = sb.first_bucket; + + sb.btree_root = sb.first_bucket * sb.bucket_size; + sb.btree_level = 0; + + printf("block_size: %u\n" + "bucket_size: %u\n" + "journal_start: %u\n" + "first_bucket: %u\n" + "nbuckets: %ju\n", + sb.block_size, + sb.bucket_size, + sb.journal_start, + sb.first_bucket, + sb.nbuckets); + + /* Zero out priorities */ + lseek(fd, 4096, SEEK_SET); + for (i = 8; i < sb.first_bucket * sb.bucket_size; i++) + if (write(fd, zero, 512) != 512) + goto err; + + if (pwrite(fd, &sb, sizeof(sb), 4096) != sizeof(sb)) + goto err; + + exit(EXIT_SUCCESS); +err: + perror("write error\n"); + return 1; +}