void delete_hotspares_impl(mdhspname_t *hspnp, md_hsp_t *hspp, boolean_e verbose) { md_hs_t *hsp; uint_t hsi; char *cname, *bname, *hs_state; md_error_t e = mdnullerror; int deleted_hs = 0; for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { mdnamelist_t *nlp; hsp = &hspp->hotspares.hotspares_val[hsi]; if (verbose == True) monitord_print(6, "hsi %d\n", hsi); cname = hsp->hsnamep->cname; bname = hsp->hsnamep->bname; nlp = NULL; metanamelist_append(&nlp, hsp->hsnamep); hs_state = hs_state_to_name(hsp, NULL); /* print hotspare */ if (verbose == True) monitord_print(6, "\t%-19s\t%-19s\t%-12s\n", cname, bname, hs_state); if (hsp->state == HSS_AVAILABLE) { if (hotspare_ok(bname)) continue; monitord_print(6, gettext( "NOTICE: Hotspare %s in %s has failed.\n" "\tDeleting %s since it is not in use\n\n"), bname, hspnp->hspname, bname); if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) { mde_perror(&e, ""); } else { deleted_hs++; } } else { if (verbose == True) monitord_print(6, gettext( "%s in use - skipping\n"), cname); } } }
int main(int argc, char **argv) { char c; char *sname = MD_LOCAL_NAME; mddevopts_t options = 0; md_error_t status = mdnullerror; md_error_t *ep = &status; mdsetname_t *sp = NULL; mdsetname_t *local_sp = NULL; char *argname; int todo = 0; int ret = 0; int md_upgd_stat = 0; int error; md_set_desc *sd; /* * Get the locale set up before calling any other routines * with messages to ouput. Just in case we're not in a build * environment, make sure that TEXT_DOMAIN gets set to * something. */ #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((sdssc_bind_library() == SDSSC_OKAY) && (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, &error) == SDSSC_PROXY_DONE)) exit(error); openlog("metadevadm", LOG_ODELAY, LOG_USER); /* initialize */ if (md_init(argc, argv, 0, 1, ep) != 0 || meta_check_root(ep) != 0) { closelog(); mde_perror(ep, ""); md_exit(sp, 1); } /* parse args */ optind = 1; opterr = 1; while ((c = getopt(argc, argv, "vlhnrs:u:")) != -1) { switch (c) { case 'v': options |= DEV_VERBOSE; break; case 'n': options |= DEV_NOACTION; break; case 'r': options |= DEV_RELOAD; todo = 1; break; case 's': sname = optarg; break; case 'u': todo = 1; options |= DEV_UPDATE; argname = optarg; if (argname == NULL) { usage("metadevadm"); closelog(); md_exit(sp, 0); } break; case 'l': options |= DEV_LOG; break; case 'h': default: usage("metadevadm"); closelog(); md_exit(sp, 0); } } if ((sp = metasetname(sname, ep)) == NULL) { mde_perror(ep, ""); closelog(); md_exit(sp, 1); } if (!metaislocalset(sp)) { if ((sd = metaget_setdesc(sp, ep)) == NULL) { mde_perror(ep, ""); closelog(); md_exit(sp, 1); } if (MD_MNSET_DESC(sd)) { (void) printf("%s\n", gettext("metadevadm cannot be " "run on multi-owner disksets\n")); closelog(); md_exit(sp, 0); } } if ((options & DEV_VERBOSE) && (todo != 1)) { usage("metadevadm"); closelog(); md_exit(sp, 0); } if ((options & DEV_NOACTION) && (todo != 1)) { usage("metadevadm"); closelog(); md_exit(sp, 0); } if (todo == 0) { usage("metadevadm"); closelog(); md_exit(sp, 0); } if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { mde_perror(ep, ""); closelog(); md_exit(local_sp, 1); } /* lock the local set */ if (meta_lock(local_sp, TRUE, ep) != 0) { mde_perror(ep, ""); closelog(); md_exit(local_sp, 1); } /* grab set lock */ if (meta_lock(sp, TRUE, ep)) { mde_perror(ep, ""); closelog(); md_exit(local_sp, 1); } /* check for ownership */ if (meta_check_ownership(sp, ep) != 0) { /* * If the set is not owned by this node then only update the * local set's replica. */ options |= DEV_LOCAL_SET; } /* * check for upgrade. If upgrade in progress then just exit. */ if (metaioctl(MD_UPGRADE_STAT, &md_upgd_stat, ep, NULL) != 0) { mde_perror(ep, ""); closelog(); (void) meta_unlock(sp, ep); md_exit(local_sp, 1); } if (md_upgd_stat == 0) { ret = meta_fixdevid(sp, options, argname, ep); if (ret == METADEVADM_ERR) { /* * If the call failed, for a DEV_RELOAD still need to * update the .conf file to provide the latest devid * information so exit later. */ if (options & DEV_UPDATE) { closelog(); (void) meta_unlock(sp, ep); md_exit(local_sp, 1); } } } /* * Sync replica list in kernel to replica list in conf files. * This will update driver name and minor number in conf file * if reload was run. Will update device id in conf file if * update was run. */ meta_sync_db_locations(sp, ep); closelog(); (void) meta_unlock(sp, ep); md_exit(local_sp, ret); return (0); }
/* * initialize all devices in set */ static int init_all( mdsetname_t **spp, mdcmdopts_t options, bool_t called_thru_rpc, md_error_t *ep ) { md_tab_t *tabp = NULL; size_t setlen; uint_t more; int done; int eval = -1; /* * Only take the lock if this is not a MN set * We can only enter this code for a MN set if we are the initiator * and in this case, we don't want to take locks. */ if (meta_is_mn_set((*spp), ep) == 0) { /* grab set lock */ if (meta_lock(*spp, TRUE, ep)) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } /* check for ownership */ if (meta_check_ownership(*spp, ep) != 0) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } /* lock is held across init_entries */ options |= MDCMD_NOLOCK; } /* get md.tab, preen entries */ if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { mde_perror(ep, ""); mdclrerror(ep); return (eval); } setlen = strlen((*spp)->setname); for (more = 0; (more < tabp->nlines); ++more) { md_tab_line_t *linep = &tabp->lines[more]; char *cname = linep->cname; char *p; size_t len; /* better have args */ assert((linep->argc > 0) && (linep->argv[0] != NULL)); /* only do metadevices and hotspare pools in set */ if (linep->type & TAB_MD_HSP) { if ((p = strrchr(cname, '/')) == NULL) { len = 0; } else { len = p - cname; } if ((len == setlen) && (strncmp(cname, (*spp)->setname, len) == 0)) { linep->flags = DO_AGAIN; } else { linep->flags = DONT_DO; } } else { linep->flags = DONT_DO; } } eval = 1; /* while more devices get made */ do { done = init_entries(spp, tabp, options, MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep); } while (done > 0); /* now do it and report errors */ if (init_entries(spp, tabp, options, MD_RETRY_BUSY, called_thru_rpc, ep) >= 0) eval = 0; /* success */ mdclrerror(ep); /* cleanup, return success */ out: meta_tab_free(tabp); return (eval); }
static int init_entries( mdsetname_t **spp, md_tab_t *tabp, mdcmdopts_t options, uint_t flags, bool_t called_thru_rpc, md_error_t *ep ) { uint_t cnt = 0; uint_t line; int rval = 0; int ret; /* for all matching entries, which haven't already been done */ for (line = 0; (line < tabp->nlines); ++line) { md_tab_line_t *linep = &tabp->lines[line]; char *uname = linep->argv[0]; /* see if already done */ if (linep->flags != DO_AGAIN) continue; /* clear the metadev/hsp caches between inits */ metaflushmetanames(); /* try it */ if ((called_thru_rpc == FALSE) && meta_is_mn_name(spp, uname, ep)) { /* * MN set, send command to all nodes * Note that is sp is NULL, meta_is_mn_name() derives * sp from linep->argv which is the metadevice arg */ ret = mn_send_command(spp, linep->argc, linep->argv, options, flags, linep->context, ep); } else { char *cname = NULL; cname = meta_name_getname(spp, uname, META_DEVICE, ep); if (cname == NULL) { mde_perror(ep, ""); mdclrerror(ep); } else { ret = meta_init_name(spp, linep->argc, linep->argv, cname, options, ep); Free(cname); if (ret != 0) { if (!(flags & MD_IGNORE_STDERR)) { mderrorextra(ep, linep->context); mde_perror(ep, ""); rval = -1; } mdclrerror(ep); } } } if (ret == 0) { linep->flags = IS_DONE; ++cnt; } } /* return success */ if (rval != 0) return (rval); return (cnt); }
/* * mainline. crack command line arguments. */ int main( int argc, char *argv[] ) { char *sname = MD_LOCAL_NAME; mdsetname_t *sp = NULL; int aflag = 0; int pflag = 0; int set_flag = 0; mdcmdopts_t options = (MDCMD_PRINT|MDCMD_DOIT); int c; md_error_t status = mdnullerror; md_error_t *ep = &status; int eval = 1; int error; bool_t called_thru_rpc = FALSE; char *cp; int mnset = FALSE; /* * Get the locale set up before calling any other routines * with messages to ouput. Just in case we're not in a build * environment, make sure that TEXT_DOMAIN gets set to * something. */ #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((cp = strstr(argv[0], ".rpc_call")) == NULL) { if (sdssc_bind_library() == SDSSC_OKAY) if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, &error) == SDSSC_PROXY_DONE) exit(error); } else { *cp = '\0'; /* cut off ".rpc_call" */ called_thru_rpc = TRUE; } /* initialize */ if (md_init(argc, argv, 0, 1, ep) != 0 || meta_check_root(ep) != 0) goto errout; /* parse args */ optind = 1; opterr = 1; while ((c = getopt(argc, argv, "hs:afrp?")) != -1) { switch (c) { case 'h': usage(sp, 0); break; case 's': sname = optarg; set_flag++; break; case 'a': ++aflag; options |= MDCMD_FORCE; break; case 'f': options |= MDCMD_FORCE; break; case 'r': options |= MDCMD_RECURSE | MDCMD_FORCE; break; case 'p': ++pflag; break; case '?': if (optopt == '?') usage(sp, 0); /*FALLTHROUGH*/ default: usage(sp, 1); break; } } argc -= optind; argv += optind; /* with mn sets if -a, set name must have been specified by -s */ if (called_thru_rpc && aflag && !set_flag) { md_eprintf(gettext( "-a parameter requires the use of -s in multi-node sets")); md_exit(sp, 1); } /* get set context */ if ((sp = metasetname(sname, ep)) == NULL) { mde_perror(ep, ""); md_exit(sp, 1); } if (called_thru_rpc) { /* Check if the device is open on all nodes */ options |= MDCMD_MN_OPEN_CHECK; } if (aflag) { /* clear all devices */ if (argc != 0) usage(sp, 1); /* * If a MN set, we will generate a series of individual * metaclear commands which will each grab the set lock. * Therefore do not grab the set lock now. */ if (!meta_is_mn_set(sp, ep)) { /* grab set lock */ if (meta_lock(sp, TRUE, ep)) goto errout; /* check for ownership */ if (meta_check_ownership(sp, ep) != 0) goto errout; } else { mnset = TRUE; } /* reset all devices in set */ if (meta_reset_all(sp, options, ep) != 0) { if (!mnset) mde_perror(ep, ""); } else eval = 0; } else { /* * We are dealing with either a single or multiple names. * The set for the command is either denoted by the -s option * or the set of the first name. */ if (argc <= 0) usage(sp, 1); if (meta_is_mn_name(&sp, argv[0], ep)) mnset = TRUE; eval = 0; for (; (argc > 0); --argc, ++argv) { char *cname; /* * If we are dealing with a MN set and we were not * called thru an rpc call, we are just to send this * command string to the master of the set and let it * deal with it. */ if (!called_thru_rpc && mnset) { /* get the canonical name */ if (pflag) { /* * If -p, set cname to the device * argument. */ cname = Strdup(argv[0]); } else { /* * For hotspares and metadevices, set * cname to the full name, * setname/hspxxx or setname/dxxx */ cname = meta_name_getname(&sp, argv[0], META_DEVICE, ep); if (cname == NULL) { mde_perror(ep, ""); eval = 1; continue; } } if (meta_mn_send_metaclear_command(sp, cname, options, pflag, ep) != 0) { eval = 1; } Free(cname); } else { if (pflag) { /* * clear all soft partitions on named * devices */ if (meta_sp_reset_component(sp, argv[0], options, ep) != 0) { mde_perror(ep, ""); eval = 1; continue; } } else { /* * get the canonical name and * setup sp if it has been * specified as part of the * metadevice/hsp name param */ cname = meta_name_getname(&sp, argv[0], META_DEVICE, ep); if (cname == NULL) { mde_perror(ep, ""); eval = 1; continue; } /* clear named devices */ if (clear_name(&sp, cname, options, ep) != 0) { mde_perror(ep, ""); eval = 1; Free(cname); continue; } Free(cname); } } } } /* update md.cf */ if (meta_update_md_cf(sp, ep) != 0) { mde_perror(ep, ""); eval = 1; } md_exit(sp, eval); errout: mde_perror(ep, ""); md_exit(sp, eval); /*NOTREACHED*/ return (eval); }
/* * This routine is called from preenlib the first time. It is then * recursively called through preen_subdev. * * The argument passed in (uname) starts with the special device from * /etc/vfstab. Recursive calls pass in the underlying physical device * names. */ void preen_build_devs( char *uname, /* name of metadevice */ struct dk_cinfo *dkiop, /* associated controller info */ void *dp /* magic info */ ) { char *setname = NULL; char *tname = NULL; mdsetname_t *sp; mdname_t *namep; /* metadevice name */ mdnamelist_t *nlp = NULL; /* list of real devices */ mdnamelist_t *p; devid_nmlist_t *nm_list = NULL; md_error_t status = mdnullerror; md_error_t *ep = &status; int ep_valid = 0; /* does ep contain a real error */ struct stat statb; static int md_major = -1; side_t sideno; /* * The rest of the code in this library can't work within a * non-global zone so we just return the top level metadevice back * to be fscked. */ if (getzoneid() != GLOBAL_ZONEID) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } if (stat(uname, &statb) != 0) return; if (md_major == -1 && get_major_from_n2m(MD_MODULE, &md_major) != 0) return; /* * If the path passed in is not a metadevice, then add that * device to the list (preen_addunit) since it has to be a * physical device. */ if (major(statb.st_rdev) != md_major) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } /* * Bind to the cluster library */ if (sdssc_bind_library() == SDSSC_ERROR) return; if (md_init_daemon("fsck", ep) != 0) { ep_valid = 1; goto out; } /* * parse the path name to get the diskset name. */ parse_device(NULL, uname, &tname, &setname); Free(tname); if ((sp = metasetname(setname, ep)) == NULL) { ep_valid = 1; goto out; } /* check for ownership */ if (meta_check_ownership(sp, ep) != 0) { /* * Don't own the set but we are here implies * that this is a clustered proxy device. Simply add * the unit. */ preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); ep_valid = 1; goto out; } /* * get list of underlying physical devices. */ if ((namep = metaname(&sp, uname, UNKNOWN, ep)) == NULL) { ep_valid = 1; goto out; } if (namep->dev == NODEV64) { goto out; } if (meta_getdevs(sp, namep, &nlp, ep) != 0) { ep_valid = 1; goto out; } if ((sideno = getmyside(sp, ep)) == MD_SIDEWILD) { ep_valid = 1; goto out; } /* gather and add the underlying devs */ for (p = nlp; (p != NULL); p = p->next) { mdname_t *devnp = p->namep; int fd; struct dk_cinfo cinfo; ddi_devid_t md_did; char *devname; char *minor_name = NULL; char mname[MAXPATHLEN]; /* * we don't want to use the rname anymore because * that may have changed. Use the device id information * to find the correct ctd name and open based on that. * If there isn't a devid or we have a did device, then * use the rname. In clustering, it's corrected for us. * If no devid it's at least worth a try. */ if (((md_did = meta_getdidbykey(sp->setno, sideno, devnp->key, ep)) == NULL) || ((minor_name = meta_getdidminorbykey(sp->setno, sideno, devnp->key, ep)) == NULL)) { devname = devnp->rname; if (md_did) Free(md_did); } else { if (strstr(minor_name, ",raw") == NULL) { (void) snprintf(mname, MAXPATHLEN, "%s,raw", minor_name); } else { (void) snprintf(mname, MAXPATHLEN, "%s", minor_name); } /* * We need to make sure we call this with a specific * mname (raw mname) so that we get the exact slice * with the given device id. Otherwise we could try * to open a slice that doesn't really exist. */ if (meta_deviceid_to_nmlist("/dev", md_did, mname, &nm_list) != 0) { (void) mdsyserror(ep, errno, devnp->rname); ep_valid = 1; Free(md_did); Free(minor_name); goto out; } devname = Strdup(nm_list->devname); Free(md_did); Free(minor_name); devid_free_nmlist(nm_list); } /* get device name and (real) cinfo */ if ((fd = open(devname, O_RDONLY, 0)) < 0) { (void) mdsyserror(ep, errno, devname); ep_valid = 1; /* * We need to scan all sub devices even if some fail * since exit here would end up in not finishing fsck * on all devices and prevent us from going into * multiuser mode. */ continue; } if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { (void) mdsyserror(ep, errno, devname); (void) close(fd); ep_valid = 1; /* Continue here too. See comment from before */ continue; } (void) close(fd); /* sd/ssd bug */ /* * preen_subdev fails when the device name has been * resolved to the physical layer. Hence it is added * to preen_addunit. */ if (preen_subdev(devname, &cinfo, dp) != 0) { preen_addunit(dp, cinfo.dki_dname, NULL, NULL, cinfo.dki_unit); } } /* cleanup, if we fail, just add this composite device to the list */ out: if (setname != NULL) Free(setname); if (ep_valid != 0) { mde_perror(&status, ""); mdclrerror(&status); } metafreenamelist(nlp); }