Program to create bootcache area
Changes to bootcache program to match changes that have been
made to the bootcache device mapper.
BUG=chromium-os:25441
TEST=created bootcache and booted system.
Change-Id: Idc62d4cea72d69f4c202460400219184916231ee
Reviewed-on: https://gerrit.chromium.org/gerrit/31761
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
Commit-Ready: Paul Taysom <taysom@chromium.org>
Tested-by: Paul Taysom <taysom@chromium.org>
diff --git a/bootcache.c b/bootcache.c
index 515bde2..5fa9a8f 100644
--- a/bootcache.c
+++ b/bootcache.c
@@ -12,7 +12,10 @@
* conjunction with dm-bootcache device mapper to coalesce
* the blocks used during boot.
*
- * bootcache [-t] <device-name>
+ * Sizes and offsets are measured in 512 byte sectors.
+ * Space is allocated in CHUNK_SIZE chunks.
+ *
+ * bootcache [-t] <device-name> <raw-partition>
*
* -t - for testing - looks in a different place for
* information files.
@@ -21,14 +24,14 @@
* prefix.
*
* Files:
- * 1. Device - /dev/dm-0 - Where the blocks to be cached
- * are stored. Both the original and cached
- * copy.
+ * 1. Device - <raw-partition> - Where the blocks to be
+ * cached are stored. Both the original and
+ * cached copy.
* 2. Header - /sys/kernel/debug/dm-bootcache/dm-0/header
* Header for the boot cache. It contains the
* information the bootcache utility will need
* to create the bootcache.
- * 3. Trace - /sys/kernel/debug/dm-bootcache/dm-0/trace
+ * 3. Trace - /sys/kernel/debug/dm-bootcache/dm-0/blocktrace
* Trace of files read during boot
* 4. Valid - /sys/kernel/debug/dm-bootcache/dm-0/valid
* Returns "1" if cache is valid
@@ -41,14 +44,16 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/user.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "dm-bootcache.h"
@@ -56,30 +61,41 @@
typedef uint64_t u64;
typedef uint32_t u32;
-#define MAX_BLOCKS 128
+#define CHUNK_SIZE 4096 /* todo(taysom) should get from bootcache_hdr */
+#define SECTOR_SHIFT 9
+#define MAX_CHUNKS 128
#define MAX_FILE_NAME 256
+#define SECTORS_PER_CHUNK (CHUNK_SIZE >> SECTOR_SHIFT)
+#define MAX_MSG 1024
-static struct Bootcache_hdr Header;
+static struct bootcache_hdr Header;
static struct {
- struct Trace *tr;
+ struct bootcache_trace *tr;
int num;
} Trace;
static const char Progname[] = "bootcache";
-static char Device_file[MAX_FILE_NAME];
static char Valid_file[MAX_FILE_NAME];
static char Free_file[MAX_FILE_NAME];
static char Header_file[MAX_FILE_NAME];
-static char Trace_file[MAX_FILE_NAME];
+static char Blocktrace_file[MAX_FILE_NAME];
-static u64 Header_block;
static u64 Trace_start;
static u64 Cache_start;
#define fatal(fmt, ...) pr_fatal(__FILE__, __FUNCTION__, __LINE__, \
fmt, ## __VA_ARGS__)
+#define PRs(_x) printf("|%s<%d> %s %s\n", __FUNCTION__, __LINE__, \
+ # _x, _x);
+
+#define PRd(_x) printf("|%s<%d> %s %lld\n", __FUNCTION__, __LINE__, \
+ # _x, (unsigned long long)(_x));
+
+#define PRx(_x) printf("|%s<%d> %s %llx\n", __FUNCTION__, __LINE__, \
+ # _x, (unsigned long long)(_x));
+
/* pr_fatal: print error message and exit */
static void pr_fatal(
const char *file,
@@ -87,20 +103,28 @@
int line,
const char *fmt, ...)
{
+ char msg[MAX_MSG];
va_list args;
+ int n = MAX_MSG;
+ int i = 0;
+ int r;
fflush(stdout);
- fprintf(stderr, "Fatal %s %s:%s<%d> ", Progname, file, func, line);
- if (fmt) {
+ r = snprintf(msg, n, "Fatal %s %s:%s<%d> ", Progname, file, func, line);
+ n -= r;
+ i += r;
+ if (n && fmt) {
va_start(args, fmt);
- vfprintf(stderr, fmt, args);
+ r = vsnprintf(&msg[i], n, fmt, args);
+ n -= r;
+ i += r;
va_end(args);
- if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') {
- fprintf(stderr, " %s<%d>", strerror(errno), errno);
+ if (n && fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') {
+ snprintf(&msg[i], n, " %s<%d>", strerror(errno), errno);
}
}
- fprintf(stderr, "\n");
+ syslog(LOG_ERR, "%s\n", msg);
exit(2); /* conventional value for failed execution */
}
@@ -153,14 +177,14 @@
void *buf;
int rc;
- rc = posix_memalign(&buf, BLK_SIZE, npages * BLK_SIZE);
+ rc = posix_memalign(&buf, CHUNK_SIZE, npages * CHUNK_SIZE);
if (rc) {
fatal("posix_memalign rc=%d", rc);
}
return buf;
}
-static u64 num_blocks_in_cache(void)
+static u64 num_sectors_in_cache(void)
{
int i;
u64 sum = 0;
@@ -171,33 +195,41 @@
return sum;
}
-static void compute_sections(void)
+static u64 num_meta_sectors(void)
{
- Header.num_blks_meta = BLK_ALIGN(Trace.num * sizeof(*Trace.tr));
- Header.num_blks_data = num_blocks_in_cache();
- Header_block = Header.blkno;
- Trace_start = Header_block + 1;
- Cache_start = Trace_start + Header.num_blks_meta;
+ u64 num_bytes = Trace.num * sizeof(*Trace.tr);
+
+ /* Align to page boundary then convert to sectors */
+ return ((num_bytes + CHUNK_SIZE - 1) / CHUNK_SIZE) * SECTORS_PER_CHUNK;
}
-static void copy_trace(int dst, int src, struct Trace tr, void *buf)
+static void compute_sections(void)
+{
+ Header.num_trace_recs = Trace.num;
+ Header.sectors_meta = num_meta_sectors();
+ Header.sectors_data = num_sectors_in_cache();
+ Trace_start = Header.sector + SECTORS_PER_CHUNK;
+ Cache_start = Trace_start + Header.sectors_meta;
+}
+
+static void copy_trace(int dst, int src, struct bootcache_trace tr, void *buf)
{
u64 n;
u64 remainder;
u64 offset;
int rc;
- offset = tr.blkno << BLK_SHIFT;
- remainder = tr.count << BLK_SHIFT;
- n = BLK_SIZE * MAX_BLOCKS;
+ offset = tr.sector << SECTOR_SHIFT;
+ remainder = tr.count << SECTOR_SHIFT;
+ n = MAX_CHUNKS * CHUNK_SIZE;
while (remainder) {
if (n > remainder) {
n = remainder;
}
rc = pread(src, buf, n, offset);
if (rc < 0) {
- fatal("pread trace offset=%llu num blocks=%llu",
- offset >> BLK_SHIFT, n >> BLK_SHIFT);
+ fatal("pread trace offset=%llu num sectors=%llu:",
+ offset >> SECTOR_SHIFT, n >> SECTOR_SHIFT);
}
if (rc != n) {
fatal("pread read only %u bytes expected %llu",
@@ -205,8 +237,8 @@
}
rc = write(dst, buf, n);
if (rc < 0) {
- fatal("write trace offset=%llu num blocks=%llu",
- offset >> BLK_SHIFT, n >> BLK_SHIFT);
+ fatal("write trace offset=%llu num sectors=%llu:",
+ offset >> SECTOR_SHIFT, n >> SECTOR_SHIFT);
}
if (rc != n) {
fatal("write wrote only %u bytes expected %llu",
@@ -224,8 +256,9 @@
int src = open(device, O_RDONLY);
int dst = open(device, O_WRONLY);
- void *buf = malloc_buf(MAX_BLOCKS);
- rc = lseek(dst, Cache_start << BLK_SHIFT, SEEK_SET);
+ void *buf = malloc_buf(MAX_CHUNKS);
+
+ rc = lseek(dst, Cache_start << SECTOR_SHIFT, SEEK_SET);
if (rc == -1) {
fatal("lseek for cache start:");
}
@@ -238,28 +271,31 @@
eclose(src);
}
-static void dump_trace(struct Trace *tr, int num_recs)
+static void dump_trace()
{
+ struct bootcache_trace *tr = Trace.tr;
int i;
- for (i = 0; i < num_recs; i++, tr++) {
- printf("%llu %llu %llu\n", tr->blkno, tr->count, tr->ino);
+ if (0) {
+ for (i = 0; i < Trace.num; i++, tr++) {
+ printf("%llu %llu %llu\n", tr->sector, tr->count, tr->ino);
+ }
}
}
/*
- * Because we are reading a pseudo file, we scan it to
- * see how big it is.
+ * Because we are reading a pseudo file in sysfs,
+ * we scan it to see how big it is.
*/
-static u64 num_traces(const char *file)
+static u64 num_bytes(const char *file)
{
- struct Trace trace[1024];
+ char buf[CHUNK_SIZE];
ssize_t rc;
u64 sum = 0;
int fd = eopen(file, O_RDONLY);
for (;;) {
- rc = read(fd, trace, sizeof(trace));
+ rc = read(fd, buf, sizeof(buf));
if (rc == -1)
fatal("read %s:", file);
if (rc == 0)
@@ -267,23 +303,39 @@
sum += rc;
}
eclose(fd);
- return sum / sizeof(struct Trace);
+ return sum;
}
static void read_trace(const char *file)
{
- u64 n = num_traces(file);
+ /*
+ * Because this is a sysfs file, we have to read it to get
+ * its size. Even if more data is appended to the file, we
+ * don't care, we just want the data up to this point in
+ * time.
+ */
+ u64 n = num_bytes(file);
ssize_t rc;
int fd;
+ char *b;
- Trace.tr = emalloc(n * sizeof(struct Trace));
- Trace.num = n;
+ Trace.tr = emalloc(n);
+ Trace.num = n / sizeof(struct bootcache_trace);
fd = eopen(file, O_RDONLY);
- rc = read(fd, Trace.tr, n * sizeof(struct Trace));
- if (rc == -1) {
- fatal("read %s:", file);
+ /*
+ * Because sysfs only returns a page at a time,
+ * will need to do the read in a loop.
+ */
+ for (b = (char *)Trace.tr; n; n -= rc, b += rc) {
+ rc = read(fd, b, n);
+ if (rc == -1) {
+ fatal("read %s:", file);
+ }
+ if (rc == 0) {
+ fatal("trying to read %lld bytes", n);
+ }
}
- dump_trace(Trace.tr, n);
+ dump_trace();
eclose(fd);
}
@@ -319,7 +371,7 @@
int rc;
fd = eopen(file, O_WRONLY);
- rc = pwrite(fd, &Header, sizeof(Header), Header_block << BLK_SHIFT);
+ rc = pwrite(fd, &Header, sizeof(Header), Header.sector << SECTOR_SHIFT);
if (rc != sizeof(Header)) {
fatal("pwrite %s rc=%d:", file, rc);
}
@@ -334,7 +386,7 @@
ssize_t size = Trace.num * sizeof(*Trace.tr);
fd = eopen(file, O_WRONLY);
- rc = pwrite(fd, Trace.tr, size, Trace_start);
+ rc = pwrite(fd, Trace.tr, size, Trace_start << SECTOR_SHIFT);
if (rc != size) {
fatal("pwrite %s rc=%ld size=%ld:", file, rc, size);
}
@@ -380,96 +432,77 @@
return buf[0] == '1';
}
-static void gen_file_name(char *file_name, int size,
- const char *fmt, const char *name)
+static void gen_file_name(char *file_name, int size, const char *fmt,
+ const char *prefix, const char *name)
{
int rc;
- rc = snprintf(file_name, size, fmt, name);
+ rc = snprintf(file_name, size, fmt, prefix, name);
if (rc >= size) {
fatal("Name too long %s", name);
}
}
-static void gen_file_names(const char *name)
+static void gen_file_names(const char *fmt, const char *device_mapper)
{
- gen_file_name(Device_file, sizeof(Device_file), "/dev/%s", name);
gen_file_name(Valid_file, sizeof(Valid_file),
- "/sys/kernel/debug/dm-bootcache/%s/valid", name);
+ fmt, device_mapper, "valid");
gen_file_name(Free_file, sizeof(Free_file),
- "/sys/kernel/debug/dm-bootcache/%s/free", name);
+ fmt, device_mapper, "free");
gen_file_name(Header_file, sizeof(Header_file),
- "/sys/kernel/debug/dm-bootcache/%s/header", name);
- gen_file_name(Trace_file, sizeof(Trace_file),
- "/sys/kernel/debug/dm-bootcache/%s/trace", name);
-}
-
-static void test_file_names(const char *name)
-{
- gen_file_name(Device_file, sizeof(Device_file),
- "/tmp/%s/dev", name);
- gen_file_name(Valid_file, sizeof(Valid_file),
- "/tmp/%s/valid", name);
- gen_file_name(Free_file, sizeof(Free_file),
- "/tmp/%s/free", name);
- gen_file_name(Header_file, sizeof(Header_file),
- "/tmp/%s/header", name);
- gen_file_name(Trace_file, sizeof(Trace_file),
- "/tmp/%s/trace", name);
+ fmt, device_mapper, "header");
+ gen_file_name(Blocktrace_file, sizeof(Blocktrace_file),
+ fmt, device_mapper, "blocktrace");
}
static void usage(void)
{
- fprintf(stderr, "Usage: %s [-t] <name>\n"
- " e.g %s dm-0\n",
+ fprintf(stderr, "Usage: %s [-t]"
+ " <device mapper> <raw partition>\n"
+ " e.g %s dm-0 /dev/sda3\n",
Progname, Progname);
exit(2);
}
int main(int argc, char *argv[])
{
- bool test = false;
- char *name = NULL;
+ char *device_mapper = NULL;
+ char *raw_partition = NULL;
+ openlog(Progname, LOG_PERROR | LOG_CONS | LOG_PID, 0);
+ syslog(LOG_ERR, "started\n");
for (;;) {
int c;
- c = getopt(argc, argv, "t?");
+ c = getopt(argc, argv, "?");
if (c == -1)
break;
switch (c) {
- case 't':
- test = true;
- break;
case '?':
default:
usage();
break;
}
}
- if (optind >= argc) {
+ if (optind+2 != argc) {
usage();
}
- name = argv[optind];
- if (test) {
- test_file_names(name);
- } else {
- gen_file_names(name);
- }
- if (is_valid(Valid_file)) {
- /* Because the boot cache is valid, the block
- * traces are not kept so the boot cache can't
- * be rebuilt. To force a rebuild of the cache,
- * zero the header.
+ device_mapper = argv[optind];
+ raw_partition = argv[optind + 1];
+ gen_file_names("/sys/devices/virtual/block/%s/dm/%s",
+ device_mapper);
+ if (!is_valid(Valid_file)) {
+ /*
+ * Rebuild the bootcache
*/
- return 0;
+ read_header(Header_file);
+ read_trace(Blocktrace_file);
+ compute_sections();
+ copy_blocks(raw_partition);
+ write_trace(raw_partition);
+ write_header(raw_partition);
}
- read_header(Header_file);
- read_trace(Trace_file);
- compute_sections();
- copy_blocks(Device_file);
- write_trace(Device_file);
- write_header(Device_file);
free_bootcache(Free_file);
+ syslog(LOG_ERR, "done\n");
return 0;
}
diff --git a/bootcache.conf b/bootcache.conf
new file mode 100644
index 0000000..27d00db
--- /dev/null
+++ b/bootcache.conf
@@ -0,0 +1,19 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description "Start the bootcache process"
+author "chromium-os-dev@chromium.org"
+
+# Starts the bootcache deamon that either creates the bootcache
+# or cleans it up after it is used.
+start on started system-services
+
+pre-start script
+ sleep 5 # Give a little extra time for chrome
+end script
+
+script
+ device=$(rootdev -s)
+ exec ionice -c3 bootcache dm-0 $device
+end script
diff --git a/dm-bootcache.h b/dm-bootcache.h
index af12df8..536911f 100644
--- a/dm-bootcache.h
+++ b/dm-bootcache.h
@@ -1,42 +1,44 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
+/*
+ * Copyright 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#ifndef _BOOTCACHE_H
-#define _BOOTCACHE_H
+#ifndef DM_BOOTCACHE_H
+#define DM_BOOTCACHE_H
#include <linux/types.h>
-enum { BLK_SHIFT = 12,
- BLK_SIZE = 1<<BLK_SHIFT,
- BLK_MASK = BLK_SIZE - 1,
- SECTOR_BLOCK_SHIFT = 3,
- BOOTCACHE_MAGIC = 1651470196,
+enum { BOOTCACHE_MAGIC = 1651470196,
BOOTCACHE_VERSION = 2,
MAX_SIGNATURE = 256
};
-
-#define BLK_ALIGN(_x) (((_x) + BLK_MASK) >> BLK_SHIFT)
-
-struct Trace {
- __u64 blkno; /* Block number for data */
- __u64 count; /* Number of blocks in request */
- __u64 ino; /* Used for anaysis of traces */
+struct bootcache_trace {
+ __u64 sector; /* Sector offset */
+ __u64 count; /* Number of blocks traced */
+ __u64 ino; /* Inode number of file */
};
-struct Bootcache_hdr {
- __u64 blkno; /* Block number for where header is stored */
+struct bootcache_hdr {
+ __u64 sector; /* Sector offset where header is stored */
__u32 magic; /* Magic number */
__u32 version; /* Verion of boot cache */
__u32 state; /* Curent state */
- __u32 num_blks_meta; /* Size of trace data on disk */
- __u32 num_blks_data; /* Size of the data area */
- char date[12]; /* Date and time bootcache was compiled */
- char time[12];
+ __u32 num_trace_recs; /* Number of trace reords */
+ __u32 sectors_meta; /* Size of trace data on disk in sectors*/
+ __u32 sectors_data; /* Size of the data area in sectors*/
__u32 max_sectors; /* Max sectors that can to read */
__u32 max_hw_sectors; /* Max hardware sectore that can be read */
+ char date[12]; /* Date and time dm-bootcache was compiled */
+ char time[12];
char signature[MAX_SIGNATURE];
};