Home | History | Annotate | Download | only in util
      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 2008 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[0])) < 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