xref: /titanic_52/usr/src/uts/common/avs/ns/nsctl/nsc_freeze.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 #include <sys/types.h>
27 #include <sys/errno.h>
28 #include <sys/cmn_err.h>
29 #include <sys/ksynch.h>
30 #include <sys/kmem.h>
31 #include <sys/ddi.h>
32 
33 #define	__NSC_GEN__
34 #include "nsc_dev.h"
35 #include "../nsctl.h"
36 
37 /*
38  * (Un)Freeze Module
39  *
40  * This module provides a means to 'freeze' a device and ensure
41  * that no SP software has an open reference to that device.  Later
42  * the device can be 'unfrozen' and the SP software can resume
43  * normal operations.
44  *
45  * This module is required because it is possible to place a virtual
46  * volume driver (RAID-0, 1 or 5) into a state whereby it needs to be
47  * disabled for corrective action.  The (un)freeze facility provides a
48  * method of doing this without downtime.
49  *
50  * A device that is frozen should be frozen on all nodes.  It is the
51  * responsibility of the management software or the user to perform
52  * the freeze and unfreeze on the required nodes.
53  */
54 
55 extern nsc_mem_t *_nsc_local_mem;
56 
57 typedef struct _nsc_frz_s {
58 	struct _nsc_frz_s	*next;
59 	nsc_path_t		*token;
60 	char			path[NSC_MAXPATH];
61 } _nsc_frz_t;
62 
63 
64 extern int _nsc_frz_stop(char *, int *);		/* forward decl */
65 
66 static _nsc_frz_t *_nsc_frz_top;
67 static nsc_def_t _nsc_frz_def[];
68 static kmutex_t _nsc_frz_sleep;
69 static nsc_io_t *_nsc_frz_io;
70 
71 
72 void
73 _nsc_init_frz(void)
74 {
75 	mutex_init(&_nsc_frz_sleep, NULL, MUTEX_DRIVER, NULL);
76 
77 	_nsc_frz_io = nsc_register_io("frz",
78 			NSC_FREEZE_ID | NSC_FILTER, _nsc_frz_def);
79 
80 	if (!_nsc_frz_io)
81 		cmn_err(CE_WARN, "nsctl: _nsc_init_frz: register failed");
82 }
83 
84 
85 void
86 _nsc_deinit_frz(void)
87 {
88 	if (_nsc_frz_io)
89 		(void) nsc_unregister_io(_nsc_frz_io, 0);
90 
91 	_nsc_frz_io = NULL;
92 
93 	mutex_destroy(&_nsc_frz_sleep);
94 }
95 
96 
97 /*
98  * int _nsc_frz_start(char *path, int *rvp)
99  *	Freeze a device
100  *
101  * Calling/Exit State:
102  *	Must be called from a context that can block.
103  *	Returns 0 for success, or one of the following error codes:
104  *		EINVAL   - invalid 'path' argument
105  *		ENOMEM   - failed to allocate memory
106  *		EALREADY - 'path' is already frozen
107  *
108  * Description:
109  *	Registers 'path' to be accessed through the NSC_FREEZE_ID
110  *	io module, and forces any open file descriptors for 'path'
111  *	to be re-opened as appropriate.
112  */
113 int
114 _nsc_frz_start(path, rvp)
115 char *path;
116 int *rvp;
117 {
118 	_nsc_frz_t *frz, *xfrz;
119 	int rc;
120 
121 	*rvp = 0;
122 
123 	if (strlen(path) >= NSC_MAXPATH)
124 		return (EINVAL);
125 
126 	frz = nsc_kmem_zalloc(sizeof (*frz), KM_SLEEP, _nsc_local_mem);
127 	if (!frz)
128 		return (ENOMEM);
129 
130 	(void) strcpy(frz->path, path);
131 
132 	mutex_enter(&_nsc_frz_sleep);
133 
134 	for (xfrz = _nsc_frz_top; xfrz; xfrz = xfrz->next)
135 		if (strcmp(frz->path, xfrz->path) == 0)
136 			break;
137 
138 	if (!xfrz) {
139 		frz->next = _nsc_frz_top;
140 		_nsc_frz_top = frz;
141 	}
142 
143 	mutex_exit(&_nsc_frz_sleep);
144 
145 	if (xfrz) {
146 		nsc_kmem_free(frz, sizeof (*frz));
147 		return (EALREADY);
148 	}
149 
150 	frz->token = nsc_register_path(path, NSC_DEVICE, _nsc_frz_io);
151 
152 	if (!frz->token) {
153 		(void) _nsc_frz_stop(path, &rc);
154 		return (EINVAL);
155 	}
156 
157 	return (0);
158 }
159 
160 
161 /*
162  * int _nsc_frz_stop(char *path, int *rvp)
163  *	Unfreeze a device
164  *
165  * Calling/Exit State:
166  *	Must be called from a context that can block.
167  *	Returns 0 or an error code.
168  *
169  * Description:
170  *	Removes the path registration for the NSC_FREEZE_ID io module
171  *	and forces any re-opens as appropriate.
172  */
173 int
174 _nsc_frz_stop(path, rvp)
175 char *path;
176 int *rvp;
177 {
178 	_nsc_frz_t **xfrz, *frz = NULL;
179 	int rc = 0;
180 
181 	*rvp = 0;
182 
183 	mutex_enter(&_nsc_frz_sleep);
184 
185 	for (xfrz = &_nsc_frz_top; *xfrz; xfrz = &(*xfrz)->next)
186 		if (strcmp(path, (*xfrz)->path) == 0) {
187 			frz = *xfrz;
188 			break;
189 		}
190 
191 	if (!frz) {
192 		mutex_exit(&_nsc_frz_sleep);
193 		return (EINVAL);
194 	}
195 
196 	if (frz->token)
197 		rc = nsc_unregister_path(frz->token, NSC_PCATCH);
198 
199 	if (rc) {
200 		mutex_exit(&_nsc_frz_sleep);
201 		return (rc);
202 	}
203 
204 	(*xfrz) = frz->next;
205 
206 	mutex_exit(&_nsc_frz_sleep);
207 
208 	nsc_kmem_free(frz, sizeof (*frz));
209 
210 	return (0);
211 }
212 
213 
214 /*
215  * int _nsc_frz_isfrozen(char *path, int *rvp)
216  *	Tests whether a device is frozen.
217  *
218  * Calling/Exit State:
219  *	Returns 0 or EINVAL.
220  *	Sets *rvp to 1 if the device was not frozen, and 0 otherwise.
221  *	This function returns historical information.
222  */
223 int
224 _nsc_frz_isfrozen(path, rvp)
225 char *path;
226 int *rvp;
227 {
228 	_nsc_frz_t *frz;
229 
230 	*rvp = 1;
231 
232 	if (! _nsc_frz_io)
233 		return (EINVAL);
234 
235 	mutex_enter(&_nsc_frz_sleep);
236 
237 	for (frz = _nsc_frz_top; frz; frz = frz->next)
238 		if (strcmp(frz->path, path) == 0) {
239 			*rvp = 0;
240 			break;
241 		}
242 
243 	mutex_exit(&_nsc_frz_sleep);
244 
245 	return (0);
246 }
247 
248 
249 /*
250  * static int
251  * _nsc_frz_open(char *path, int flag, blind_t *cdp)
252  *	Dummy open function.
253  *
254  * Description:
255  *	This is the "Open" function for the I/O module.
256  *	It is just a dummy.
257  */
258 
259 /* ARGSUSED */
260 
261 static int
262 _nsc_frz_open(path, flag, cdp)
263 char *path;
264 int flag;
265 blind_t *cdp;
266 {
267 	*cdp = 0;
268 	return (0);
269 }
270 
271 
272 /*
273  * static int
274  * _nsc_frz_close()
275  *	Dummy close function.
276  *
277  * Description:
278  *	This is the "Close" function for the I/O module.
279  *	It is just a dummy.
280  */
281 static int
282 _nsc_frz_close() { return (0); }
283 
284 
285 /*
286  * static int
287  * _nsc_frz_attach()
288  *	Attach a device to this i/o module.
289  *
290  * Calling/Exit State:
291  *	Returns EACCES in all cricumstances.
292  *
293  * Description:
294  *	This function is called by the nsctl module when it wishes
295  *	to attach the device to this I/O module (ie. as part of
296  *	nsc_reserve() processing).  This function unconditionally
297  *	returns an error which forces the nsc_reserve() to fail, and
298  *	so no access to possible to the underlying device.
299  */
300 static int
301 _nsc_frz_attach() { return (EACCES); }
302 
303 
304 static nsc_def_t _nsc_frz_def[] = {
305 	"Open",		(uintptr_t)_nsc_frz_open,		0,
306 	"Close",	(uintptr_t)_nsc_frz_close,		0,
307 	"Attach",	(uintptr_t)_nsc_frz_attach,		0,
308 	"Provide",	0,				0,
309 	0,		0,				0
310 };
311