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