/* * Check if we have the drive in our list, based upon the device id. * We got the device id from the dev tree walk. This is encoded * using devid_str_encode(3DEVID). In order to check the device ids we need * to use the devid_compare(3DEVID) function, so we need to decode the * string representation of the device id. */ descriptor_t * drive_get_descriptor_by_name(char *name, int *errp) { ddi_devid_t devid; descriptor_t **drives; descriptor_t *drive = NULL; int i; if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) { *errp = EINVAL; return (NULL); } drives = cache_get_descriptors(DM_DRIVE, errp); if (*errp != 0) { devid_free(devid); return (NULL); } /* * We have to loop through all of them, freeing the ones we don't * want. Once drive is set, we don't need to compare any more. */ for (i = 0; drives[i]; i++) { if (drive == NULL && drives[i]->p.disk->devid != NULL && devid_compare(devid, drives[i]->p.disk->devid) == 0) { drive = drives[i]; } else { /* clean up the unused descriptor */ cache_free_descriptor(drives[i]); } } free(drives); devid_free(devid); if (drive == NULL) { *errp = ENODEV; } return (drive); }
/* * Check if we have the drive in our list, based upon the device id. * We got the device id from the dev tree walk. This is encoded * using devid_str_encode(3DEVID). In order to check the device ids we need * to use the devid_compare(3DEVID) function, so we need to decode the * string representation of the device id. */ static disk_t * get_disk_by_deviceid(disk_t *listp, char *devidstr) { ddi_devid_t devid; if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) { return (NULL); } while (listp != NULL) { if (listp->devid != NULL && devid_compare(listp->devid, devid) == 0) { break; } listp = listp->next; } devid_free(devid); return (listp); }
/* * check for same drive * * Differentiate between matching on name/dev_t and devid. In the latter * case it is correct to fail but misleading to give the same error msg as * for an overlapping slice. * */ int meta_check_samedrive( mdname_t *np1, /* first comp */ mdname_t *np2, /* second comp */ md_error_t *ep ) { mdcinfo_t *cinfop1, *cinfop2; mdnmtype_t type1 = np1->drivenamep->type; mdnmtype_t type2 = np2->drivenamep->type; int l = 0; char *name1 = NULL; char *name2 = NULL; int retval = CANT_TELL; int fd1 = -1; int fd2 = -1; int rc1 = -2, rc2 = -2; uint_t strl1 = 0, strl2 = 0; int devid1_found = 0; int devid2_found = 0; ddi_devid_t devid1 = NULL; ddi_devid_t devid2 = NULL; dev_list_t *dnlp = NULL; assert(type1 != MDT_FAST_META && type1 != MDT_FAST_COMP); assert(type2 != MDT_FAST_META && type2 != MDT_FAST_COMP); /* * The process of determining if 2 names are the same drive is * as follows: * * Case 1 - The filenames are identical * * Case 2 - Both devices have a devid * get and compare the devids for the devices. If both * devices have a devid then the compare will is all * that is needed we are done. * * Case 3 - One or more devices does not have a devid * start by doing a simple compare of the name, if they * are the same just return. * * If the names differ then keep going and see if the * may be the same underlying devic. First check to * see if the sd name is the same (old code). * * Then check the major and minor numbers to see if * they are the same. If they are then return (old code). * * Next compare the raw name and the component name and * if they are the same then return. * * All else has failed so use the component name (cname) * component number and unit number. If they all are * equal then call them the same drive. * */ if ((np1 == NULL) || (np2 == NULL)) return (NOT_SAMEDRIVE); /* if the name structs are the same then the drives must be */ if (np1 == np2) return (IDENTICAL_NAME_DEVT); name1 = np1->bname; name2 = np2->bname; if ((name1 == NULL) || ((strl1 = strlen(name1)) == 0) || (name2 == NULL) || ((strl2 = strlen(name2)) == 0)) return (NOT_SAMEDRIVE); if ((strl1 == strl2) && (strcmp(name1, name2) == 0)) { /* names are identical */ return (IDENTICAL_NAME_DEVT); } if (is_metaname(name1) || is_metaname(name2)) return (NOT_SAMEDRIVE); /* * Check to see if the devicename is in the static list. If so, * use its devid. Otherwise do the expensive operations * of opening the device, getting the devid, and closing the * device. Add the result into the static list. * * The case where this list will be useful is when there are soft * partitions on multiple drives and a new soft partition is being * created. In that situation the underlying physical device name * for the new soft partition would be compared against each of the * existing soft partititions. Without this static list that would * involve 2 opens, closes, and devid gets for each existing soft * partition */ for (dnlp = devnamelist; (dnlp != NULL) && !(devid1_found && devid2_found); dnlp = dnlp->dev_nxt) { if (!devid1_found && (strcmp(dnlp->dev_name, name1) == 0)) { devid1_found = 1; devid1 = dnlp->devid; if (devid1 == NULL) rc1 = 1; else rc1 = 0; continue; } if (!devid2_found && (strcmp(dnlp->dev_name, name2) == 0)) { devid2_found = 1; devid2 = dnlp->devid; if (devid2 == NULL) rc2 = 1; else rc2 = 0; continue; } } /* * Start by checking if the device has a device id, and if they * are equal. If they are there is no question there is a match. * * The process here is open each disk, get the devid for each * disk. If they both have a devid compare them and return * the results. */ if (!devid1_found) { if ((fd1 = open(name1, O_RDONLY | O_NDELAY)) < 0) { return (NOT_SAMEDRIVE); } rc1 = devid_get(fd1, &devid1); (void) close(fd1); /* add the name and devid to the cache */ add_to_devname_list(name1, devid1); } if (!devid2_found) { if ((fd2 = open(name2, O_RDONLY | O_NDELAY)) < 0) { return (NOT_SAMEDRIVE); } rc2 = devid_get(fd2, &devid2); (void) close(fd2); /* add the name and devid to the cache */ add_to_devname_list(name2, devid2); } if ((rc1 == 0) && (rc2 == 0)) { if (devid_compare(devid1, devid2) == 0) retval = IDENTICAL_DEVIDS; /* same devid */ else retval = NOT_SAMEDRIVE; /* different drives */ } if (retval >= 0) { return (retval); } /* * At this point in time one of the two drives did not have a * device ID. Do not make the assumption that is one drive * did have a device id and the other did not that they are not * the same. One drive could be covered by a device and still * be the same drive. This is a general flaw in the system at * this time. */ /* * The optimization can not happen if we are given an old style name * in the form /dev/XXNN[a-h], since the name caches differently and * allows overlaps to happen. */ if (! ((sscanf(np1->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 && l == strlen(np1->bname)) || (sscanf(np2->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 && l == strlen(np2->bname))) && ((type1 == MDT_COMP) || (type1 == MDT_META)) && ((type2 == MDT_COMP) || (type2 == MDT_META))) if (np1->drivenamep == np2->drivenamep) return (IDENTICAL_NAME_DEVT); else return (NOT_SAMEDRIVE); /* check for same drive */ if (meta_getmajor(np1->dev) != meta_getmajor(np2->dev)) return (NOT_SAMEDRIVE); /* not same drive */ if (((cinfop1 = metagetcinfo(np1, ep)) == NULL) || ((cinfop2 = metagetcinfo(np2, ep)) == NULL)) { if ((strcmp(np1->drivenamep->cname, np2->drivenamep->cname) != 0) && (strcmp(np1->drivenamep->rname, np2->drivenamep->rname) != 0)) { mdclrerror(ep); return (NOT_SAMEDRIVE); /* not same drive */ } else { return (CANT_TELL); /* can't tell */ } } else if ((strncmp(cinfop1->cname, cinfop2->cname, sizeof (cinfop1->cname)) != 0) || (cinfop1->cnum != cinfop2->cnum) || (cinfop1->unit != cinfop2->unit)) { return (NOT_SAMEDRIVE); /* not same drive */ } /* same drive */ return (IDENTICAL_NAME_DEVT); }