diff options
author | ae <ae@FreeBSD.org> | 2012-08-05 14:48:28 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2012-08-05 14:48:28 +0000 |
commit | ce1cae970c8f58726e122d9a5135fd8010fc6733 (patch) | |
tree | 5b7c1c92b8440f342ce74666a012bcf7d9f1b54d /sys/boot/zfs | |
parent | d8ef1d62b66279995de94de2c68c501fc44561f6 (diff) | |
download | FreeBSD-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.c | 103 |
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); } |