1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * sync metadevices 30 */ 31 32 #include <meta.h> 33 34 #include <sys/lvm/md_mirror.h> 35 36 #include <ctype.h> 37 38 #include <sdssc.h> 39 40 /* 41 * print usage message 42 */ 43 static void 44 usage( 45 mdsetname_t *sp, 46 int eval 47 ) 48 { 49 (void) fprintf(stderr, gettext("\ 50 usage: %s [-s setname] -r [buffer_size]\n\ 51 %s [-s setname] [buffer_size] metadevices...\n\ 52 %s [-s setname] -c metadevices...\n"), 53 myname, myname, myname); 54 md_exit(sp, eval); 55 } 56 57 /* 58 * crack command line arguments. 59 */ 60 int 61 main( 62 int argc, 63 char *argv[] 64 ) 65 { 66 char *sname = NULL; 67 mdsetname_t *sp = NULL; 68 int rflag = 0; 69 int pflag = 0; 70 daddr_t size = 0; 71 int c; 72 md_error_t status = mdnullerror; 73 md_error_t *ep = &status; 74 int rval = 0; 75 int error; 76 md_resync_cmd_t resync_cmd = MD_RESYNC_START; 77 bool_t called_thru_rpc = FALSE; 78 char *cp; 79 int mn_set = FALSE; 80 int cflag = 0; 81 82 /* 83 * Get the locale set up before calling any other routines 84 * with messages to ouput. Just in case we're not in a build 85 * environment, make sure that TEXT_DOMAIN gets set to 86 * something. 87 */ 88 #if !defined(TEXT_DOMAIN) 89 #define TEXT_DOMAIN "SYS_TEST" 90 #endif 91 (void) setlocale(LC_ALL, ""); 92 (void) textdomain(TEXT_DOMAIN); 93 94 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) { 95 if (sdssc_bind_library() == SDSSC_OKAY) 96 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 97 &error) == SDSSC_PROXY_DONE) 98 exit(error); 99 } else { 100 *cp = '\0'; /* cut off ".rpc_call" */ 101 called_thru_rpc = TRUE; 102 } 103 104 105 /* initialize */ 106 if (md_init(argc, argv, 0, 1, ep) != 0 || 107 meta_check_root(ep) != 0) { 108 mde_perror(ep, ""); 109 md_exit(sp, 1); 110 } 111 112 /* parse args */ 113 optind = 1; 114 opterr = 1; 115 while ((c = getopt(argc, argv, "phs:rc?")) != -1) { 116 switch (c) { 117 case 'h': 118 usage(sp, 0); 119 break; 120 121 case 's': 122 sname = optarg; 123 break; 124 125 case 'r': 126 ++rflag; 127 break; 128 129 case 'p': 130 ++pflag; 131 break; 132 133 case 'c': 134 ++cflag; 135 resync_cmd = MD_RESYNC_KILL; 136 break; 137 138 case '?': 139 if (optopt == '?') 140 usage(sp, 0); 141 /*FALLTHROUGH*/ 142 default: 143 usage(sp, 1); 144 break; 145 } 146 } 147 if ((pflag + rflag) > 1) { 148 usage(sp, 1); 149 mde_perror(ep, ""); 150 md_exit(sp, 1); 151 } 152 argc -= optind; 153 argv += optind; 154 155 if (sname != NULL) { 156 if ((sp = metasetname(sname, ep)) == NULL) { 157 mde_perror(ep, ""); 158 md_exit(sp, 1); 159 } 160 } 161 162 /* 163 * look for buffer size. If one is not specified we pass '0' to 164 * the meta_resync_all() call. This uses whatever size has been 165 * configured via md_mirror:md_resync_bufsz 166 * The default value (if not overridden in /etc/system) is 167 * MD_DEF_RESYNC_BUF_SIZE 168 */ 169 if ((argc > 0) && (isdigit(argv[0][0]))) { 170 if ((size = atoi(argv[optind++])) < 0) { 171 md_eprintf(gettext( 172 "illegal buffer size %s\n"), 173 argv[0]); 174 md_exit(sp, 1); 175 } 176 --argc; 177 ++argv; 178 } 179 180 /* sync all devices in set */ 181 if (rflag) { 182 /* get set */ 183 if (argc != 0) 184 usage(sp, 1); 185 if ((sp == NULL) && 186 ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) && 187 (metaget_setdesc(sp, ep) == NULL)) { 188 mde_perror(ep, ""); 189 md_exit(sp, 1); 190 } 191 192 assert(sp != NULL); 193 /* 194 * For a MN set "metasync -r" can only be called by the 195 * initiator. We must not take the set lock for a MN set as 196 * it will only generate individual metasync commands which 197 * will individually take the lock when executing the 198 * individual metasync commands. 199 * Therefore only take the set lock for non MN sets. 200 */ 201 if (meta_is_mn_set(sp, ep) == 0) { 202 /* grab set lock */ 203 if (meta_lock(sp, TRUE, ep)) { 204 mde_perror(ep, ""); 205 md_exit(sp, 1); 206 } 207 208 /* check for ownership */ 209 if (meta_check_ownership(sp, ep) != 0) { 210 mde_perror(ep, ""); 211 md_exit(sp, 1); 212 } 213 } 214 /* resync all metadevices in set */ 215 if (meta_resync_all(sp, size, ep) != 0) { 216 mde_perror(ep, ""); 217 md_exit(sp, 1); 218 } 219 md_exit(sp, 0); 220 } 221 222 /* sync specified metadevices */ 223 if (argc <= 0) 224 usage(sp, 1); 225 226 /* 227 * Note that if sp is NULL, meta_is_mn_name() derives sp 228 * from argv[0] which is the metadevice arg 229 */ 230 if (meta_is_mn_name(&sp, argv[0], ep)) 231 mn_set = TRUE; 232 233 for (; (argc > 0); --argc, ++argv) { 234 mdname_t *np; 235 int result; 236 237 /* get device */ 238 if ((np = metaname(&sp, argv[0], META_DEVICE, ep)) == NULL) { 239 mde_perror(ep, ""); 240 rval = -1; 241 continue; 242 } 243 assert(sp != NULL); 244 245 /* 246 * If we are not called through an rpc call and the 247 * set associated with the command is an MN set, send 248 * a setsync message to the master of the set and let it 249 * deal with it. 250 */ 251 if (!called_thru_rpc && mn_set) { 252 if ((result = meta_mn_send_setsync(sp, np, size, 253 ep)) != 0) { 254 mde_perror(ep, "Unable to start resync"); 255 md_exit(sp, result); 256 } 257 continue; 258 } 259 260 /* grab set lock */ 261 if (meta_lock(sp, TRUE, ep)) { 262 mde_perror(ep, ""); 263 md_exit(sp, 1); 264 } 265 266 /* check for ownership */ 267 if (meta_check_ownership(sp, ep) != 0) { 268 mde_perror(ep, ""); 269 md_exit(sp, 1); /* no point in continuing */ 270 } 271 272 /* resync or regen (raid only) metadevice */ 273 if (pflag) { 274 /* regen */ 275 if (meta_raid_regen_byname(sp, np, size, ep) != 0) { 276 mde_perror(ep, ""); 277 rval = -1; 278 continue; 279 } 280 } else { 281 if (meta_resync_byname(sp, np, size, ep, resync_cmd) 282 != 0) { 283 mde_perror(ep, ""); 284 rval = -1; 285 continue; 286 } 287 } 288 } 289 290 /* return success */ 291 md_exit(sp, rval); 292 /*NOTREACHED*/ 293 return (rval); 294 } 295