summaryrefslogtreecommitdiffstats
path: root/sys/boot/zfs
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2012-08-05 14:48:28 +0000
committerae <ae@FreeBSD.org>2012-08-05 14:48:28 +0000
commitce1cae970c8f58726e122d9a5135fd8010fc6733 (patch)
tree5b7c1c92b8440f342ce74666a012bcf7d9f1b54d /sys/boot/zfs
parentd8ef1d62b66279995de94de2c68c501fc44561f6 (diff)
downloadFreeBSD-src-ce1cae970c8f58726e122d9a5135fd8010fc6733.zip
FreeBSD-src-ce1cae970c8f58726e122d9a5135fd8010fc6733.tar.gz
Teach the ZFS use new partitions API when probing.
Note: now ZFS does probe only for partitions with type "freebsd-zfs" and "freebsd".
Diffstat (limited to 'sys/boot/zfs')
-rw-r--r--sys/boot/zfs/zfs.c103
1 files changed, 93 insertions, 10 deletions
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index cffb19e..d7ea878 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -33,10 +33,11 @@ __FBSDID("$FreeBSD$");
* Stand-alone file reading package.
*/
+#include <sys/disk.h>
#include <sys/param.h>
-#include <sys/disklabel.h>
#include <sys/time.h>
#include <sys/queue.h>
+#include <part.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
@@ -376,21 +377,103 @@ zfs_dev_init(void)
return (0);
}
-int
-zfs_probe_dev(const char *devname, uint64_t *pool_guid)
+struct zfs_probe_args {
+ int fd;
+ const char *devname;
+ uint64_t *pool_guid;
+ uint16_t secsz;
+};
+
+static int
+zfs_diskread(void *arg, void *buf, size_t blocks, off_t offset)
+{
+ struct zfs_probe_args *ppa;
+
+ ppa = (struct zfs_probe_args *)arg;
+ return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd,
+ offset * ppa->secsz, buf, blocks * ppa->secsz));
+}
+
+static int
+zfs_probe(int fd, uint64_t *pool_guid)
{
spa_t *spa;
- int fd;
int ret;
- fd = open(devname, O_RDONLY);
- if (fd == -1)
- return (ENXIO);
ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa);
- if (ret != 0)
- close(fd);
- else if (pool_guid != NULL)
+ if (ret == 0 && pool_guid != NULL)
*pool_guid = spa->spa_guid;
+ return (ret);
+}
+
+static void
+zfs_probe_partition(void *arg, const char *partname,
+ const struct ptable_entry *part)
+{
+ struct zfs_probe_args *ppa, pa;
+ struct ptable *table;
+ char devname[32];
+ int ret;
+
+ /* Probe only freebsd-zfs and freebsd partitions */
+ if (part->type != PART_FREEBSD &&
+ part->type != PART_FREEBSD_ZFS)
+ return;
+
+ ppa = (struct zfs_probe_args *)arg;
+ strncpy(devname, ppa->devname, strlen(ppa->devname) - 1);
+ sprintf(devname, "%s%s:", devname, partname);
+ pa.fd = open(devname, O_RDONLY);
+ if (pa.fd == -1)
+ return;
+ ret = zfs_probe(pa.fd, ppa->pool_guid);
+ if (ret == 0)
+ return;
+ /* Do we have BSD label here? */
+ if (part->type == PART_FREEBSD) {
+ pa.devname = devname;
+ pa.pool_guid = ppa->pool_guid;
+ pa.secsz = ppa->secsz;
+ table = ptable_open(&pa, part->end - part->start + 1,
+ ppa->secsz, zfs_diskread);
+ if (table != NULL) {
+ ptable_iterate(table, &pa, zfs_probe_partition);
+ ptable_close(table);
+ }
+ }
+ close(pa.fd);
+}
+
+int
+zfs_probe_dev(const char *devname, uint64_t *pool_guid)
+{
+ struct ptable *table;
+ struct zfs_probe_args pa;
+ off_t mediasz;
+ int ret;
+
+ pa.fd = open(devname, O_RDONLY);
+ if (pa.fd == -1)
+ return (ENXIO);
+ /* Probe the whole disk */
+ ret = zfs_probe(pa.fd, pool_guid);
+ if (ret == 0)
+ return (0);
+ /* Probe each partition */
+ ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
+ if (ret == 0)
+ ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
+ if (ret == 0) {
+ pa.devname = devname;
+ pa.pool_guid = pool_guid;
+ table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
+ zfs_diskread);
+ if (table != NULL) {
+ ptable_iterate(table, &pa, zfs_probe_partition);
+ ptable_close(table);
+ }
+ }
+ close(pa.fd);
return (0);
}
OpenPOWER on IntegriCloud