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