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