xref: /titanic_41/usr/src/cmd/lvm/util/metasync.c (revision e0724c534a46ca4754330bc022bf1e2a68f5bb93)
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