xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_rename.c (revision bd335c6465ddbafe543900df4b03247bfa288eff)
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 2004 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  * Just in case we're not in a build environment, make sure that
31  * TEXT_DOMAIN gets set to something.
32  */
33 #if !defined(TEXT_DOMAIN)
34 #define	TEXT_DOMAIN "SYS_TEST"
35 #endif
36 
37 /*
38  * change the identity of a metadevice
39  * These are the "do it" functions for the metarename command.
40  */
41 
42 #include <string.h>
43 #include <meta.h>
44 #include <sys/lvm/md_rename.h>
45 
46 /* private */
47 #define	FORCE	(0x00000001)
48 #define	NOISY	(0x00000010)
49 #define	NOFLIP	(0x00000020)
50 #define	DRYRUN	(0x00000040)
51 
52 #define	OP_STR(op)						\
53 	((op) == MDRNOP_EXCHANGE?	"exchange":		\
54 	    (op) == MDRNOP_RENAME?	"rename":		\
55 	    (op) == MDRNOP_UNK?		"<unknown>": "garbage")
56 
57 
58 /*
59  * Check if from_np is open
60  * Return 0 if not open, -1 if open
61  */
62 static int
63 check_open(
64 	mdsetname_t	*sp,
65 	mdname_t	*from_np,
66 	md_error_t	*ep)
67 {
68 	int		rc;
69 
70 	if ((rc = meta_isopen(sp, from_np, ep, (mdcmdopts_t)0)) < 0) {
71 		assert(!mdisok(ep));
72 		return (-1);
73 
74 	} else if (rc > 0) {
75 		if (mdisok(ep)) {
76 			(void) mdmderror(ep, MDE_RENAME_BUSY,
77 				meta_getminor(from_np->dev),
78 				from_np->cname);
79 		}
80 		return (-1);
81 	}
82 	return (0);
83 }
84 
85 /*
86  * meta_swap is the common code used by the
87  * meta_rename() and meta_exchange() entry points
88  */
89 
90 static int
91 meta_swap(
92 	mdsetname_t	*sp,
93 	mdname_t	*from_np,
94 	mdname_t	*to_np,
95 	md_renop_t	op,
96 	int		flags,
97 	md_error_t	*ep)
98 {
99 	md_rename_t	txn;
100 
101 	/*
102 	 * If the device exists a key may already exist so need to find it
103 	 * otherwise we'll end up adding the key in again which will lead
104 	 * to an inconsistent n_count for the namespace record.
105 	 */
106 	if (from_np->dev != NODEV) {
107 		(void) meta_getnmentbydev(sp->setno, MD_SIDEWILD, from_np->dev,
108 		    NULL, NULL, &from_np->key, ep);
109 	}
110 
111 	if ((from_np->key == MD_KEYWILD) || (from_np->key == MD_KEYBAD)) {
112 		if (add_key_name(sp, from_np, NULL, ep) != 0) {
113 			assert(!mdisok(ep));
114 			return (-1);
115 		}
116 	}
117 
118 	(void) memset(&txn, 0, sizeof (txn));
119 
120 	txn.op		= op;
121 	txn.revision	= MD_RENAME_VERSION;
122 	txn.flags	= 0;
123 	txn.from.mnum	= meta_getminor(from_np->dev);
124 	txn.from.key	= from_np->key;
125 
126 	if ((txn.from.key == MD_KEYBAD) || (txn.from.key == MD_KEYWILD)) {
127 		(void) mdmderror(ep, MDE_RENAME_SOURCE_BAD, txn.from.mnum,
128 								from_np->cname);
129 		return (-1);
130 	}
131 
132 	if ((to_np->key == MD_KEYWILD) || (to_np->key == MD_KEYBAD)) {
133 		if (add_key_name(sp, to_np, NULL, ep) != 0) {
134 			assert(!mdisok(ep));
135 			return (-1);
136 		}
137 	}
138 
139 	txn.to.mnum	= meta_getminor(to_np->dev);
140 	txn.to.key	= to_np->key;
141 
142 	if ((txn.to.key == MD_KEYBAD) || (txn.to.key == MD_KEYWILD)) {
143 		(void) mdmderror(ep, MDE_RENAME_TARGET_BAD, txn.to.mnum,
144 								to_np->cname);
145 		return (-1);
146 	}
147 
148 	if (flags & NOISY) {
149 		(void) fprintf(stderr, "\top: %s\n", OP_STR(txn.op));
150 		(void) fprintf(stderr, "\trevision: %d, flags: %d\n",
151 				txn.revision, txn.flags);
152 		(void) fprintf(stderr,
153 				"\tfrom(mnum,key): %ld, %d\tto: %ld, %d\n",
154 				txn.from.mnum, txn.from.key,
155 				txn.to.mnum, txn.to.key);
156 	}
157 
158 	mdclrerror(ep);
159 	if (metaioctl(MD_IOCRENAME, &txn, &txn.mde, from_np->cname) != 0) {
160 		(void) del_key_name(sp, to_np, ep);
161 		return (mdstealerror(ep, &txn.mde));
162 	}
163 
164 	/* force the name cache to re-read device state */
165 	meta_invalidate_name(from_np);
166 	meta_invalidate_name(to_np);
167 
168 	return (0);
169 }
170 
171 /*
172  * rename a metadevice
173  */
174 int
175 meta_rename(
176 	mdsetname_t	*sp,
177 	mdname_t	*from_np,
178 	mdname_t	*to_np,
179 	mdcmdopts_t	 options,
180 	md_error_t	*ep
181 )
182 {
183 	int		 flags		= (options & MDCMD_FORCE)? FORCE: 0;
184 	int		 rc		= 0;
185 	mdcinfo_t	*cinfop;
186 	char		*p;
187 	md_set_desc	*sd;
188 	mdkey_t		 side_key = MD_KEYWILD;
189 	md_error_t	 dummy_ep = mdnullerror;
190 	int		 i, j;
191 	md_mnnode_desc	*nd, *nd_del;
192 
193 	/* must have a set */
194 	assert(sp != NULL);
195 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
196 
197 	mdclrerror(ep);
198 
199 	if (((p = getenv("MD_DEBUG")) != NULL) &&
200 	    (strstr(p, "RENAME") != NULL)) {
201 		flags |= NOISY;
202 	}
203 	/* if DOIT is not set, we are in dryrun mode */
204 	if ((options & MDCMD_DOIT) == 0) {
205 		flags |= DRYRUN;
206 	}
207 
208 
209 	if (metachkmeta(from_np, ep) != 0) {
210 		assert(!mdisok(ep));
211 		return (-1);
212 	}
213 
214 	mdclrerror(ep);
215 
216 	if (meta_get_mdunit(sp, from_np, ep) == NULL) {
217 		assert(!mdisok(ep));
218 		return (-1);
219 	}
220 
221 	if (meta_get_mdunit(sp, to_np, ep) != NULL) {
222 		if (mdisok(ep)) {
223 			(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
224 					meta_getminor(to_np->dev),
225 					to_np->cname);
226 		}
227 		return (-1);
228 	}
229 	mdclrerror(ep);
230 
231 	/* If FORCE is not set, check if metadevice is open */
232 	if (!(flags & FORCE)) {
233 		if (check_open(sp, from_np, ep) != 0) {
234 			return (-1);
235 		}
236 	}
237 
238 	/*
239 	 * All checks are done, now we do the real work.
240 	 * If we are in dryrun mode, we're done.
241 	 */
242 	if (flags & DRYRUN) {
243 		return (0); /* success */
244 	}
245 
246 	/*
247 	 * add key for new name to the namespace
248 	 */
249 	if ((cinfop = metagetcinfo(from_np, ep)) == NULL) {
250 		assert(!mdisok(ep));
251 		return (-1);
252 	}
253 
254 	if (metaislocalset(sp)) {
255 		to_np->key = add_name(sp, MD_SIDEWILD, MD_KEYWILD,
256 		    cinfop->dname, meta_getminor(to_np->dev), to_np->bname, ep);
257 	} else {
258 		/*
259 		 * As this is not the local set we have to create a namespace
260 		 * record for each side (host) in the set. We cannot use
261 		 * add_key_names() because the destination device (to_np)
262 		 * should not exist and so the subsequent metagetcinfo()
263 		 * call will fail when it tries to open the device, so we
264 		 * have to use the information from the source device (from_np)
265 		 */
266 		if ((sd = metaget_setdesc(sp, ep)) == (md_set_desc *)NULL) {
267 			return (-1);
268 		}
269 		to_np->key = MD_KEYWILD;
270 
271 		if (MD_MNSET_DESC(sd)) {
272 			nd = sd->sd_nodelist;
273 			while (nd) {
274 				side_key = add_name(sp, (side_t)nd->nd_nodeid,
275 				    to_np->key, cinfop->dname,
276 				    meta_getminor(to_np->dev),
277 				    to_np->bname, ep);
278 				/*
279 				 * Break out if failed to add the key,
280 				 * but delete any name space records that
281 				 * were added.
282 				 */
283 				if (side_key == MD_KEYBAD ||
284 				    side_key == MD_KEYWILD) {
285 					/*
286 					 * If we have a valid to_np->key then
287 					 * a record was added correctly but
288 					 * we do not know for which side, so
289 					 * we need to try to delete all of them.
290 					 */
291 
292 					if (to_np->key != MD_KEYBAD &&
293 					    to_np->key != MD_KEYWILD) {
294 						nd_del = sd->sd_nodelist;
295 						while ((nd_del != nd) &&
296 						(nd_del != NULL)) {
297 						    (void) del_name(sp,
298 						    (side_t)nd_del->nd_nodeid,
299 						    to_np->key, &dummy_ep);
300 						    nd_del = nd_del->nd_next;
301 						}
302 						/* preserve error key state */
303 						to_np->key = side_key;
304 					}
305 					break;
306 				}
307 				to_np->key = side_key;
308 				nd = nd->nd_next;
309 			}
310 		} else {
311 			for (i = 0; i < MD_MAXSIDES; i++) {
312 				if (sd->sd_nodes[i][0] != '\0') {
313 					side_key = add_name(sp, (side_t)i,
314 					    to_np->key, cinfop->dname,
315 					    meta_getminor(to_np->dev),
316 					    to_np->bname, ep);
317 					/*
318 					 * Break out if failed to add the key,
319 					 * but delete any name space records
320 					 * that were added.
321 					 */
322 					if (side_key == MD_KEYBAD ||
323 					    side_key == MD_KEYWILD) {
324 						/*
325 						 * If we have a valid
326 						 * to_np->key then a record was
327 						 * added correctly but we do
328 						 * not know for which side, so
329 						 * we need to try to delete
330 						 * all of them.
331 						 */
332 						if (to_np->key != MD_KEYBAD &&
333 						    to_np->key != MD_KEYWILD) {
334 							for (j = 0; j < i;
335 							    j++) {
336 							    (void) del_name(sp,
337 							    (side_t)j,
338 							    to_np->key,
339 							    &dummy_ep);
340 							}
341 							/*
342 							 * preserve err
343 							 * key state
344 							 */
345 							to_np->key = side_key;
346 						}
347 						break;
348 					}
349 					to_np->key = side_key;
350 				}
351 			}
352 		}
353 	}
354 
355 	if (to_np->key == MD_KEYBAD || to_np->key == MD_KEYWILD) {
356 		assert(!mdisok(ep));
357 		return (-1);
358 	}
359 
360 	rc = meta_swap(sp, from_np, to_np, MDRNOP_RENAME, flags, ep);
361 
362 	if (rc == 0) {
363 		if (options & MDCMD_PRINT) {
364 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
365 				"%s: has been renamed to %s\n"),
366 				from_np->cname, to_np->cname);
367 		}
368 	}
369 
370 	return (rc);
371 }
372 
373 /*
374  * return TRUE if current <from>, <to> ordering would
375  * prevent <from> from being in the role of <self>
376  */
377 static bool_t
378 meta_exchange_need_to_flip(
379 	md_common_t	*from_mdp,
380 	md_common_t	*to_mdp
381 )
382 {
383 	assert(from_mdp);
384 	assert(to_mdp);
385 
386 	/*
387 	 * ?
388 	 *  \
389 	 * <to>
390 	 *    \
391 	 *    <from>
392 	 */
393 
394 	if (MD_HAS_PARENT(from_mdp->parent)) {
395 		if (MD_HAS_PARENT(to_mdp->parent)) {
396 			if (from_mdp->parent ==
397 				meta_getminor(to_mdp->namep->dev)) {
398 				return (TRUE);
399 			}
400 		}
401 	}
402 
403 	/*
404 	 * <from>
405 	 *    \
406 	 *    <to>
407 	 *      \
408 	 *	 ?
409 	 */
410 
411 	if (MD_HAS_PARENT(to_mdp->parent)) {
412 		if (to_mdp->capabilities & MD_CAN_META_CHILD) {
413 			return (TRUE);
414 		}
415 	}
416 
417 	/*
418 	 * <to>
419 	 *   \
420 	 *  <from>
421 	 */
422 
423 	if (MD_HAS_PARENT(from_mdp->parent)) {
424 		if (from_mdp->parent == meta_getminor(to_mdp->namep->dev)) {
425 			if (!(from_mdp->capabilities & MD_CAN_META_CHILD)) {
426 				return (TRUE);
427 			}
428 		}
429 	}
430 
431 	/*
432 	 * <from>	or	<to>
433 	 *   \			  \
434 	 *  <to>		<from>
435 	 *			    \
436 	 *			    ?
437 	 */
438 
439 	return (FALSE);
440 }
441 
442 /*
443  * exchange the names of two metadevices
444  */
445 int
446 meta_exchange(
447 	mdsetname_t	*sp,
448 	mdname_t	*from_np,
449 	mdname_t	*to_np,
450 	mdcmdopts_t	 options,
451 	md_error_t	*ep
452 )
453 {
454 	int		 flags	= (options & MDCMD_FORCE)? FORCE: 0;
455 	md_common_t	*from_mdp, *to_mdp;
456 	int		 rc;
457 	char		*p, *p2;
458 
459 	/* must have a set */
460 	assert(sp != NULL);
461 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
462 	assert(sp->setno == MD_MIN2SET(meta_getminor(to_np->dev)));
463 
464 	if (metachkmeta(from_np, ep) != 0) {
465 		assert(!mdisok(ep));
466 		return (-1);
467 	}
468 
469 	if (metachkmeta(to_np, ep) != 0) {
470 		assert(!mdisok(ep));
471 		return (-1);
472 	}
473 
474 	if ((options & MDCMD_DOIT) == 0) {
475 		flags |= DRYRUN;
476 	}
477 
478 	if ((p = getenv("MD_DEBUG")) != NULL) {
479 		if ((p2 = strstr(p, "EXCHANGE=")) != NULL) {
480 			flags |= NOISY;
481 			if ((p2 = strchr(p2, '=')) != NULL) {
482 				if (strcmp((p2+1), "NOFLIP") == 0) {
483 					flags |= NOFLIP;
484 				}
485 			}
486 		} else if (strstr(p, "EXCHANGE") != NULL) {
487 			flags |= NOISY;
488 		}
489 	}
490 
491 	if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) {
492 		assert(!mdisok(ep));
493 		return (-1);
494 	}
495 
496 	if ((to_mdp = meta_get_unit(sp, to_np, ep)) == NULL) {
497 		assert(!mdisok(ep));
498 		return (-1);
499 	}
500 	assert(mdisok(ep));
501 
502 	/* If FORCE is not set, check if metadevice is open */
503 	if (!(flags & FORCE)) {
504 		if (check_open(sp, from_np, ep) != 0) {
505 			return (-1);
506 		}
507 	}
508 
509 	/*
510 	 * All checks are done, now we do the real work.
511 	 * If we are in dryrun mode, we're done.
512 	 */
513 	if (flags & DRYRUN) {
514 		return (0); /* success */
515 	}
516 
517 	/*
518 	 * NOFLIP is used only for debugging; the driver
519 	 * will catch this and return MDE_RENAME_ORDER, if necessary
520 	 */
521 	if (((flags & NOFLIP) == 0) &&
522 	    meta_exchange_need_to_flip(from_mdp, to_mdp)) {
523 
524 		rc = meta_swap(sp, to_np, from_np, MDRNOP_EXCHANGE, flags, ep);
525 
526 	} else {
527 		rc = meta_swap(sp, from_np, to_np, MDRNOP_EXCHANGE, flags, ep);
528 	}
529 
530 	if (rc == 0) {
531 		if (options & MDCMD_PRINT) {
532 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
533 				"%s and %s have exchanged identities\n"),
534 				from_np->cname, to_np->cname);
535 		}
536 	}
537 
538 	return (rc);
539 }
540