summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Taysom <taysom@chromium.org>2012-08-30 08:33:32 -0700
committerGerrit <chrome-bot@google.com>2012-09-25 17:08:28 -0700
commitc9880282b115a0127c948d16f4ab3c6cadcbfcd2 (patch)
tree8ec533cfbe40ad80859408561a3623f8b24b909b
parentf8e5f9f2ed1a383d5726d4e55a40c7e6f9bc9744 (diff)
downloadrootdev-c9880282b115a0127c948d16f4ab3c6cadcbfcd2.tar.gz
Modified rootdev to handle stacked device mappers
Rootdev only went down one level when traversing the device tree. With the addition of the bootcache device mapper, we need to go multiple levels for the -s option for rootdev. BUG=chromium-os:25441 TEST=used it with bootcache to find boot device. Change-Id: Ica82dc150e403d0e49e4d8074c0b920b20e4cccc Reviewed-on: https://gerrit.chromium.org/gerrit/31851 Commit-Ready: Paul Taysom <taysom@chromium.org> Reviewed-by: Paul Taysom <taysom@chromium.org> Tested-by: Paul Taysom <taysom@chromium.org>
-rw-r--r--rootdev.c61
-rw-r--r--rootdev.h5
2 files changed, 45 insertions, 21 deletions
diff --git a/rootdev.c b/rootdev.c
index 3162be9..5ef0c3d 100644
--- a/rootdev.c
+++ b/rootdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* 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.
*
@@ -21,6 +21,13 @@
#include <sys/types.h>
#include <unistd.h>
+/*
+ * A depth of more than about 4 slave devices
+ * will run out of kernel stack space, so setting
+ * the serach depth to 8 covers all possible cases.
+ */
+#define MAX_SLAVE_DEPTH 8
+
static const char *kDefaultSearchPath = "/sys/block";
static const char *kDefaultDevPath = "/dev";
@@ -75,9 +82,10 @@ static dev_t devt_from_file(const char *file) {
return dev;
}
-/* Walks sysfs and will recurse into any directory/link that represents
- * a block device to find sub-devices (partitions).
- * If dev == 0, the first device in the directory will be returned. */
+/* Walks sysfs and recurses into any directory/link that represents
+ * a block device to find sub-devices (partitions) for dev.
+ * If dev == 0, the name fo the first device in the directory will be returned.
+ * Returns the device's name in "name" */
static int match_sysfs_device(char *name, size_t name_len,
const char *basedir, dev_t *dev, int depth) {
int found = -1;
@@ -253,25 +261,42 @@ int rootdev_get_device(char *dst, size_t size, dev_t dev,
return 0;
}
-int rootdev_get_device_slave(char *slave, size_t size, dev_t *dev,
- const char *device, const char *search) {
+/*
+ * rootdev_get_device_slave returns results in slave which
+ * may be the original device or the name of the slave.
+ *
+ * Because slave and device may point to the same data,
+ * must be careful how they are handled because slave
+ * is modified (can't use snprintf).
+ */
+void rootdev_get_device_slave(char *slave, size_t size, dev_t *dev,
+ const char *device, const char *search) {
char dst[PATH_MAX];
int len = 0;
+ int i;
if (search == NULL)
search = kDefaultSearchPath;
- /* So far, I've only seen top-level block devices with slaves. */
- len = snprintf(dst, sizeof(dst), "%s/%s/slaves", search, device);
- if (len < 0 || len != strlen(device) + strlen(search) + 8) {
- warnx("rootdev_get_device_slave: device name too long");
- return -1;
+ /*
+ * With stacked device mappers, we have to chain through all the levels
+ * and find the last device. For example, verity can be stacked on bootcache
+ * that is stacked on a disk partition.
+ */
+ strncpy(slave, device, size);
+ slave[size - 1] = '\0';
+ for (i = 0; i < MAX_SLAVE_DEPTH; i++) {
+ len = snprintf(dst, sizeof(dst), "%s/%s/slaves", search, slave);
+ if (len != strlen(device) + strlen(search) + 8) {
+ warnx("rootdev_get_device_slave: device name too long");
+ return;
+ }
+ *dev = 0;
+ if (match_sysfs_device(slave, size, dst, dev, 0) <= 0) {
+ return;
+ }
}
- *dev = 0;
- if (match_sysfs_device(slave, size, dst, dev, 0) <= 0)
- return -1;
-
- return 0;
+ warnx("slave depth greater than %d at %s", i, slave);
}
int rootdev_create_devices(const char *name, dev_t dev, bool symlink) {
@@ -358,8 +383,8 @@ int rootdev_wrapper(char *path, size_t size,
return res;
if (full)
- res = rootdev_get_device_slave(devname, sizeof(devname), dev, devname,
- search);
+ rootdev_get_device_slave(devname, sizeof(devname), dev, devname,
+ search);
/* TODO(wad) we should really just track the block dev, partition number, and
* dev path. When we rewrite this, we can track all the sysfs info
diff --git a/rootdev.h b/rootdev.h
index 03b8bd8..74a48da 100644
--- a/rootdev.h
+++ b/rootdev.h
@@ -61,11 +61,10 @@ int rootdev_get_device(char *dst, size_t size, dev_t dev,
* @device: name of the device to probe, like "sdb"
* @search: path to search under. NULL for default.
*
- * Returns 0 on success, non-zero on failure.
* It is safe for @device == @slave.
*/
-int rootdev_get_device_slave(char *slave, size_t size, dev_t *dev,
- const char *device, const char *search);
+void rootdev_get_device_slave(char *slave, size_t size, dev_t *dev,
+ const char *device, const char *search);
/**
* rootdev_get_path: converts a device name to a path in the device tree