xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_rename.c (revision c113cb3815ae16f5360027f4685c37e301d6341c)
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
check_open(mdsetname_t * sp,mdname_t * from_np,md_error_t * ep)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
meta_swap(mdsetname_t * sp,mdname_t * from_np,md_common_t * from_mdp,mdname_t * to_np,md_common_t * to_mdp,md_renop_t op,int flags,md_error_t * ep)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_self_name(sp, from_np->key, ep);
235 	}
236 
237 	if (op == MDRNOP_EXCHANGE && from_is_fn) {
238 		(void) add_key_name(sp, from_np, NULL, ep);
239 	}
240 
241 	/* force the name cache to re-read device state */
242 	meta_invalidate_name(from_np);
243 	meta_invalidate_name(to_np);
244 
245 	return (0);
246 }
247 
248 /*
249  * rename a metadevice
250  */
251 int
meta_rename(mdsetname_t * sp,mdname_t * from_np,mdname_t * to_np,mdcmdopts_t options,md_error_t * ep)252 meta_rename(
253 	mdsetname_t	*sp,
254 	mdname_t	*from_np,
255 	mdname_t	*to_np,
256 	mdcmdopts_t	 options,
257 	md_error_t	*ep
258 )
259 {
260 	int		 flags		= (options & MDCMD_FORCE)? FORCE: 0;
261 	int		 rc		= 0;
262 	char		*p;
263 	md_common_t	*from_mdp;
264 	minor_t		to_minor = meta_getminor(to_np->dev);
265 	md_error_t	status = mdnullerror;
266 	md_error_t	*t_ep = &status;
267 
268 	/* must have a set */
269 	assert(sp != NULL);
270 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
271 
272 	mdclrerror(ep);
273 
274 	if (((p = getenv("MD_DEBUG")) != NULL) &&
275 	    (strstr(p, "RENAME") != NULL)) {
276 		flags |= NOISY;
277 	}
278 	/* if DOIT is not set, we are in dryrun mode */
279 	if ((options & MDCMD_DOIT) == 0) {
280 		flags |= DRYRUN;
281 	}
282 
283 
284 	if (metachkmeta(from_np, ep) != 0) {
285 		assert(!mdisok(ep));
286 		return (-1);
287 	}
288 
289 	mdclrerror(ep);
290 
291 	if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) {
292 		assert(!mdisok(ep));
293 		return (-1);
294 	}
295 
296 	if (meta_get_unit(sp, to_np, ep) != NULL) {
297 		if (mdisok(ep)) {
298 			(void) mdmderror(ep, MDE_UNIT_ALREADY_SETUP,
299 					meta_getminor(to_np->dev),
300 					to_np->cname);
301 		}
302 		return (-1);
303 	}
304 	mdclrerror(ep);
305 
306 	/*
307 	 * The dest device name has been added early on
308 	 * by meta_init_make_device call so get the entry from
309 	 * the namespace
310 	 */
311 	if (meta_getnmentbydev(sp->setno, MD_SIDEWILD, to_np->dev,
312 	    NULL, NULL, &to_np->key, ep) == NULL) {
313 		return (-1);
314 	}
315 
316 	/* If FORCE is not set, check if metadevice is open */
317 	if (!(flags & FORCE)) {
318 	    if (check_open(sp, from_np, ep) != 0) {
319 		(void) del_key_name(sp, to_np, t_ep);
320 		(void) metaioctl(MD_IOCREM_DEV, &to_minor, t_ep, NULL);
321 		return (-1);
322 	    }
323 	}
324 
325 	/*
326 	 * All checks are done, now we do the real work.
327 	 * If we are in dryrun mode, clear the deivce node
328 	 * and we are done.
329 	 */
330 	if (flags & DRYRUN) {
331 		(void) del_key_name(sp, to_np, t_ep);
332 		(void) metaioctl(MD_IOCREM_DEV, &to_minor, t_ep, NULL);
333 		return (0); /* success */
334 	}
335 
336 	if (to_np->key == MD_KEYBAD || to_np->key == MD_KEYWILD) {
337 		assert(!mdisok(ep));
338 		return (-1);
339 	}
340 
341 	rc = meta_swap(sp, from_np, from_mdp, to_np, NULL, MDRNOP_RENAME,
342 		flags, ep);
343 
344 	if (rc == 0) {
345 		if (options & MDCMD_PRINT) {
346 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
347 				"%s: has been renamed to %s\n"),
348 				from_np->cname, to_np->cname);
349 		}
350 	}
351 
352 	return (rc);
353 }
354 
355 /*
356  * return TRUE if current <from>, <to> ordering would
357  * prevent <from> from being in the role of <self>
358  */
359 static bool_t
meta_exchange_need_to_flip(md_common_t * from_mdp,md_common_t * to_mdp)360 meta_exchange_need_to_flip(
361 	md_common_t	*from_mdp,
362 	md_common_t	*to_mdp
363 )
364 {
365 	assert(from_mdp);
366 	assert(to_mdp);
367 
368 	/*
369 	 * ?
370 	 *  \
371 	 * <to>
372 	 *    \
373 	 *    <from>
374 	 */
375 
376 	if (MD_HAS_PARENT(from_mdp->parent)) {
377 		if (MD_HAS_PARENT(to_mdp->parent)) {
378 			if (from_mdp->parent ==
379 				meta_getminor(to_mdp->namep->dev)) {
380 				return (TRUE);
381 			}
382 		}
383 	}
384 
385 	/*
386 	 * <from>
387 	 *    \
388 	 *    <to>
389 	 *      \
390 	 *	 ?
391 	 */
392 
393 	if (MD_HAS_PARENT(to_mdp->parent)) {
394 		if (to_mdp->capabilities & MD_CAN_META_CHILD) {
395 			return (TRUE);
396 		}
397 	}
398 
399 	/*
400 	 * <to>
401 	 *   \
402 	 *  <from>
403 	 */
404 
405 	if (MD_HAS_PARENT(from_mdp->parent)) {
406 		if (from_mdp->parent == meta_getminor(to_mdp->namep->dev)) {
407 			if (!(from_mdp->capabilities & MD_CAN_META_CHILD)) {
408 				return (TRUE);
409 			}
410 		}
411 	}
412 
413 	/*
414 	 * <from>	or	<to>
415 	 *   \			  \
416 	 *  <to>		<from>
417 	 *			    \
418 	 *			    ?
419 	 */
420 
421 	return (FALSE);
422 }
423 
424 /*
425  * exchange the names of two metadevices
426  */
427 int
meta_exchange(mdsetname_t * sp,mdname_t * from_np,mdname_t * to_np,mdcmdopts_t options,md_error_t * ep)428 meta_exchange(
429 	mdsetname_t	*sp,
430 	mdname_t	*from_np,
431 	mdname_t	*to_np,
432 	mdcmdopts_t	 options,
433 	md_error_t	*ep
434 )
435 {
436 	int		 flags	= (options & MDCMD_FORCE)? FORCE: 0;
437 	md_common_t	*from_mdp, *to_mdp;
438 	int		 rc;
439 	char		*p, *p2;
440 
441 	/* must have a set */
442 	assert(sp != NULL);
443 	assert(sp->setno == MD_MIN2SET(meta_getminor(from_np->dev)));
444 	assert(sp->setno == MD_MIN2SET(meta_getminor(to_np->dev)));
445 
446 	if (metachkmeta(from_np, ep) != 0) {
447 		assert(!mdisok(ep));
448 		return (-1);
449 	}
450 
451 	if (metachkmeta(to_np, ep) != 0) {
452 		assert(!mdisok(ep));
453 		return (-1);
454 	}
455 
456 	if ((options & MDCMD_DOIT) == 0) {
457 		flags |= DRYRUN;
458 	}
459 
460 	if ((p = getenv("MD_DEBUG")) != NULL) {
461 		if ((p2 = strstr(p, "EXCHANGE=")) != NULL) {
462 			flags |= NOISY;
463 			if ((p2 = strchr(p2, '=')) != NULL) {
464 				if (strcmp((p2+1), "NOFLIP") == 0) {
465 					flags |= NOFLIP;
466 				}
467 			}
468 		} else if (strstr(p, "EXCHANGE") != NULL) {
469 			flags |= NOISY;
470 		}
471 	}
472 
473 	if ((from_mdp = meta_get_unit(sp, from_np, ep)) == NULL) {
474 		assert(!mdisok(ep));
475 		return (-1);
476 	}
477 
478 	if ((to_mdp = meta_get_unit(sp, to_np, ep)) == NULL) {
479 		assert(!mdisok(ep));
480 		return (-1);
481 	}
482 	assert(mdisok(ep));
483 
484 
485 	/* If FORCE is not set, check if metadevice is open */
486 	if (!(flags & FORCE)) {
487 		if (check_open(sp, from_np, ep) != 0) {
488 			return (-1);
489 		}
490 	}
491 
492 	/*
493 	 * All checks are done, now we do the real work.
494 	 * If we are in dryrun mode, we're done.
495 	 */
496 	if (flags & DRYRUN) {
497 		return (0); /* success */
498 	}
499 
500 	/*
501 	 * NOFLIP is used only for debugging; the driver
502 	 * will catch this and return MDE_RENAME_ORDER, if necessary
503 	 */
504 	if (((flags & NOFLIP) == 0) &&
505 	    meta_exchange_need_to_flip(from_mdp, to_mdp)) {
506 		rc = meta_swap(sp, to_np, to_mdp, from_np, from_mdp,
507 			MDRNOP_EXCHANGE, flags, ep);
508 
509 	} else {
510 		rc = meta_swap(sp, from_np, from_mdp, to_np, to_mdp,
511 			MDRNOP_EXCHANGE, flags, ep);
512 	}
513 
514 	if (rc == 0) {
515 		if (options & MDCMD_PRINT) {
516 			(void) fprintf(stdout, dgettext(TEXT_DOMAIN,
517 				"%s and %s have exchanged identities\n"),
518 				from_np->cname, to_np->cname);
519 		}
520 	}
521 
522 	return (rc);
523 }
524