Date: Thu, 9 Sep 2010 21:18:00 +0000 (UTC) From: Pawel Jakub Dawidek <pjd@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r212383 - head/sys/boot/zfs Message-ID: <201009092118.o89LI0an034338@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: pjd Date: Thu Sep 9 21:18:00 2010 New Revision: 212383 URL: http://svn.freebsd.org/changeset/base/212383 Log: Allow to boot from a pool within which replacing is in progress. Before the change it wasn't possible and the following error was printed: ZFS: can only boot from disk, mirror or raidz vdevs Now if the original vdev (the one we are replacing) is still present we will read from it, but if it is not present we won't read from the new vdev, as it might not have enough valid data yet. MFC after: 2 weeks Modified: head/sys/boot/zfs/zfsimpl.c Modified: head/sys/boot/zfs/zfsimpl.c ============================================================================== --- head/sys/boot/zfs/zfsimpl.c Thu Sep 9 21:15:16 2010 (r212382) +++ head/sys/boot/zfs/zfsimpl.c Thu Sep 9 21:18:00 2010 (r212383) @@ -376,6 +376,27 @@ vdev_mirror_read(vdev_t *vdev, const blk return (rc); } +static int +vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + + /* + * Here we should have two kids: + * First one which is the one we are replacing and we can trust + * only this one to have valid data, but it might not be present. + * Second one is that one we are replacing with. It is most likely + * healthy, but we can't trust it has needed data, so we won't use it. + */ + kid = STAILQ_FIRST(&vdev->v_children); + if (kid == NULL) + return (EIO); + if (kid->v_state != VDEV_STATE_HEALTHY) + return (EIO); + return (kid->v_read(kid, bp, buf, offset, bytes)); +} + static vdev_t * vdev_find(uint64_t guid) { @@ -416,7 +437,7 @@ vdev_init_from_nvlist(const unsigned cha vdev_t *vdev, *kid; const unsigned char *kids; int nkids, i, is_new; - uint64_t is_offline, is_faulted, is_degraded, is_removed; + uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, 0, &guid) @@ -428,14 +449,17 @@ vdev_init_from_nvlist(const unsigned cha return (ENOENT); } + + if (strcmp(type, VDEV_TYPE_MIRROR) && strcmp(type, VDEV_TYPE_DISK) - && strcmp(type, VDEV_TYPE_RAIDZ)) { + && strcmp(type, VDEV_TYPE_RAIDZ) + && strcmp(type, VDEV_TYPE_REPLACING)) { printf("ZFS: can only boot from disk, mirror or raidz vdevs\n"); return (EIO); } - is_offline = is_removed = is_faulted = is_degraded = 0; + is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, 0, &is_offline); @@ -445,6 +469,8 @@ vdev_init_from_nvlist(const unsigned cha &is_faulted); nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, 0, &is_degraded); + nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, 0, + &isnt_present); vdev = vdev_find(guid); if (!vdev) { @@ -454,6 +480,8 @@ vdev_init_from_nvlist(const unsigned cha vdev = vdev_create(guid, vdev_mirror_read); else if (!strcmp(type, VDEV_TYPE_RAIDZ)) vdev = vdev_create(guid, vdev_raidz_read); + else if (!strcmp(type, VDEV_TYPE_REPLACING)) + vdev = vdev_create(guid, vdev_replacing_read); else vdev = vdev_create(guid, vdev_disk_read); @@ -506,6 +534,8 @@ vdev_init_from_nvlist(const unsigned cha vdev->v_state = VDEV_STATE_FAULTED; else if (is_degraded) vdev->v_state = VDEV_STATE_DEGRADED; + else if (isnt_present) + vdev->v_state = VDEV_STATE_CANT_OPEN; else vdev->v_state = VDEV_STATE_HEALTHY; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009092118.o89LI0an034338>