static vdev_t * vdev_lookup_by_path(vdev_t *vd, const char *name) { vdev_t *mvd; int c; char pathbuf[MAXPATHLEN]; char *lookup_name; int err = 0; if (!vd) return NULL; // Check both strings are valid if (name && *name && vd->vdev_path && vd->vdev_path[0]) { int off; struct vnode *vp; lookup_name = vd->vdev_path; // We need to resolve symlinks here to get the final source name dprintf("ZFS: Looking up '%s'\n", vd->vdev_path); if ((err = vnode_lookup(vd->vdev_path, 0, &vp, vfs_context_current())) == 0) { int len = MAXPATHLEN; if ((err = vn_getpath(vp, pathbuf, &len)) == 0) { dprintf("ZFS: '%s' resolved name is '%s'\n", vd->vdev_path, pathbuf); lookup_name = pathbuf; } vnode_put(vp); } if (err) dprintf("ZFS: Lookup failed %d\n", err); // Skip /dev/ or not? strncmp("/dev/", lookup_name, 5) == 0 ? off=5 : off=0; dprintf("ZFS: vdev '%s' == '%s' ?\n", name, &lookup_name[off]); if (!strcmp(name, &lookup_name[off])) return vd; } for (c = 0; c < vd->vdev_children; c++) if ((mvd = vdev_lookup_by_path(vd->vdev_child[c], name)) != NULL) return (mvd); return (NULL); }
static vdev_t * vdev_lookup_by_path(vdev_t *vd, const char *name) { vdev_t *mvd; int c; char *lookup_name; vdev_disk_t *dvd = NULL; if (!vd) return NULL; dvd = (vdev_disk_t *)vd->vdev_tsd; // Check both strings are valid if (name && *name && dvd && vd->vdev_path && vd->vdev_path[0]) { int off; // Try normal path "vdev_path" or the readlink resolved lookup_name = vd->vdev_path; // Skip /dev/ or not? strncmp("/dev/", lookup_name, 5) == 0 ? off=5 : off=0; dprintf("ZFS: vdev '%s' == '%s' ?\n", name, &lookup_name[off]); if (!strcmp(name, &lookup_name[off])) return vd; lookup_name = dvd->vd_readlinkname; // Skip /dev/ or not? strncmp("/dev/", lookup_name, 5) == 0 ? off=5 : off=0; dprintf("ZFS: vdev '%s' == '%s' ?\n", name, &lookup_name[off]); if (!strcmp(name, &lookup_name[off])) return vd; } for (c = 0; c < vd->vdev_children; c++) if ((mvd = vdev_lookup_by_path(vd->vdev_child[c], name)) != NULL) return (mvd); return (NULL); }
/* * Callback for device termination events, ie, disks removed. */ bool IOkit_disk_removed_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier) { OSObject *prop = 0; OSString* bsdnameosstr = 0; prop = newService->getProperty(kIOBSDNameKey, gIOServicePlane, kIORegistryIterateRecursively); if (prop) { spa_t *spa = NULL; bsdnameosstr = OSDynamicCast(OSString, prop); printf("ZFS: Device removal detected: '%s'\n", bsdnameosstr->getCStringNoCopy()); for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa)) { vdev_t *vd; dprintf("ZFS: Scanning pool '%s'\n", spa_name(spa)); vd = vdev_lookup_by_path(spa->spa_root_vdev, bsdnameosstr->getCStringNoCopy()); if (vd && vd->vdev_path) { printf("ZFS: Device '%s' removal requested\n", vd->vdev_path); (void) thread_create(NULL, 0, vdev_close_thread, vd, 0, &p0, TS_RUN, minclsyspri); vd->vdev_remove_wanted = B_TRUE; spa_async_request(spa, SPA_ASYNC_REMOVE); break; } } // for all spa } // if has BSDname return true; }