FreeBSD/Linux Kernel Cross Reference
sys/dev/vinum/vinum.c
1 /*-
2 * Copyright (c) 1997, 1998
3 * Nan Yang Computer Services Limited. All rights reserved.
4 *
5 * Written by Greg Lehey
6 *
7 * This software is distributed under the so-called ``Berkeley
8 * License'':
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Nan Yang Computer
21 * Services Limited.
22 * 4. Neither the name of the Company nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * This software is provided ``as is'', and any express or implied
27 * warranties, including, but not limited to, the implied warranties of
28 * merchantability and fitness for a particular purpose are disclaimed.
29 * In no event shall the company or contributors be liable for any
30 * direct, indirect, incidental, special, exemplary, or consequential
31 * damages (including, but not limited to, procurement of substitute
32 * goods or services; loss of use, data, or profits; or business
33 * interruption) however caused and on any theory of liability, whether
34 * in contract, strict liability, or tort (including negligence or
35 * otherwise) arising in any way out of the use of this software, even if
36 * advised of the possibility of such damage.
37 *
38 * $Id: vinum.c,v 1.1.1.1 2003/10/10 03:07:37 grog Exp $
39 * $FreeBSD$
40 */
41
42 #define STATIC static /* nothing while we're testing XXX */
43
44 #include <dev/vinum/vinumhdr.h>
45 #ifdef VINUMDEBUG
46 #include <sys/reboot.h>
47 int debug = 0;
48 extern int total_malloced;
49 extern int malloccount;
50 extern struct mc malloced[];
51 #endif
52 #include <dev/vinum/request.h>
53
54 const struct cdevsw vinum_cdevsw =
55 {
56 vinumopen, vinumclose, vinumread, vinumwrite, vinumioctl,
57 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
58 };
59
60 const struct bdevsw vinum_bdevsw =
61 {
62 vinumopen, vinumclose, vinumstrategy, vinumioctl,
63 nodump, vinumsize, D_DISK
64 };
65
66 /* Called by main() during pseudo-device attachment. */
67 void vinumattach(void *);
68
69 struct _vinum_conf vinum_conf; /* configuration information */
70
71 /*
72 * Called by main() during pseudo-device attachment. All we need
73 * to do is allocate enough space for devices to be configured later, and
74 * add devsw entries.
75 */
76 void
77 vinumattach(void *dummy)
78 {
79 /* modload should prevent multiple loads, so this is worth a panic */
80 if ((vinum_conf.flags & VF_LOADED) != 0)
81 panic("vinum: already loaded");
82
83 log(LOG_INFO, "vinum: loaded\n");
84 #ifdef VINUMDEBUG
85 vinum_conf.flags |= VF_LOADED | VF_HASDEBUG; /* we're loaded now, and we support debug */
86 #else
87 vinum_conf.flags |= VF_LOADED; /* we're loaded now */
88 #endif
89
90 daemonq = NULL; /* initialize daemon's work queue */
91 dqend = NULL;
92
93 vinum_conf.version = VINUMVERSION; /* note what version we are */
94
95 /* allocate space: drives... */
96 DRIVE = (struct drive *) Malloc(sizeof(struct drive) * INITIAL_DRIVES);
97 CHECKALLOC(DRIVE, "vinum: no memory\n");
98 bzero(DRIVE, sizeof(struct drive) * INITIAL_DRIVES);
99 vinum_conf.drives_allocated = INITIAL_DRIVES; /* number of drive slots allocated */
100 vinum_conf.drives_used = 0; /* and number in use */
101
102 /* volumes, ... */
103 VOL = (struct volume *) Malloc(sizeof(struct volume) * INITIAL_VOLUMES);
104 CHECKALLOC(VOL, "vinum: no memory\n");
105 bzero(VOL, sizeof(struct volume) * INITIAL_VOLUMES);
106 vinum_conf.volumes_allocated = INITIAL_VOLUMES; /* number of volume slots allocated */
107 vinum_conf.volumes_used = 0; /* and number in use */
108
109 /* plexes, ... */
110 PLEX = (struct plex *) Malloc(sizeof(struct plex) * INITIAL_PLEXES);
111 CHECKALLOC(PLEX, "vinum: no memory\n");
112 bzero(PLEX, sizeof(struct plex) * INITIAL_PLEXES);
113 vinum_conf.plexes_allocated = INITIAL_PLEXES; /* number of plex slots allocated */
114 vinum_conf.plexes_used = 0; /* and number in use */
115
116 /* and subdisks */
117 SD = (struct sd *) Malloc(sizeof(struct sd) * INITIAL_SUBDISKS);
118 CHECKALLOC(SD, "vinum: no memory\n");
119 bzero(SD, sizeof(struct sd) * INITIAL_SUBDISKS);
120 vinum_conf.subdisks_allocated = INITIAL_SUBDISKS; /* number of sd slots allocated */
121 vinum_conf.subdisks_used = 0; /* and number in use */
122 }
123
124 /*
125 * Check if we have anything open. If confopen is != 0,
126 * that goes for the super device as well, otherwise
127 * only for volumes.
128 *
129 * Return 0 if not inactive, 1 if inactive.
130 */
131 int
132 vinum_inactive(int confopen)
133 {
134 int i;
135 int can_do = 1; /* assume we can do it */
136
137 if (confopen && (vinum_conf.flags & VF_OPEN)) /* open by vinum(8)? */
138 return 0; /* can't do it while we're open */
139 lock_config();
140 for (i = 0; i < vinum_conf.volumes_allocated; i++) {
141 if ((VOL[i].state > volume_down)
142 && (VOL[i].flags & VF_OPEN)) { /* volume is open */
143 can_do = 0;
144 break;
145 }
146 }
147 unlock_config();
148 return can_do;
149 }
150
151 /*
152 * Free all structures.
153 * If cleardrive is 0, save the configuration; otherwise
154 * remove the configuration from the drive.
155 *
156 * Before coming here, ensure that no volumes are open.
157 */
158 void
159 free_vinum(int cleardrive)
160 {
161 int i;
162 int drives_allocated = vinum_conf.drives_allocated;
163
164 if (DRIVE != NULL) {
165 if (cleardrive) { /* remove the vinum config */
166 for (i = 0; i < drives_allocated; i++)
167 remove_drive(i); /* remove the drive */
168 } else { /* keep the config */
169 for (i = 0; i < drives_allocated; i++)
170 free_drive(&DRIVE[i]); /* close files and things */
171 }
172 Free(DRIVE);
173 }
174 while ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN))
175 == (VF_STOPPING | VF_DAEMONOPEN)) { /* at least one daemon open, we're stopping */
176 queue_daemon_request(daemonrq_return, (union daemoninfo) 0); /* stop the daemon */
177 tsleep(&vinumclose, PUSER, "vstop", 1); /* and wait for it */
178 }
179 if (SD != NULL) {
180 for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
181 struct sd *sd = &SD[i];
182
183 if (sd->state != sd_unallocated)
184 free_sd(i);
185 }
186 Free(SD);
187 }
188 if (PLEX != NULL) {
189 for (i = 0; i < vinum_conf.plexes_allocated; i++) {
190 struct plex *plex = &PLEX[i];
191
192 if (plex->state != plex_unallocated) /* we have real data there */
193 free_plex(i);
194 }
195 Free(PLEX);
196 }
197 if (VOL != NULL) {
198 for (i = 0; i < vinum_conf.volumes_allocated; i++) {
199 struct volume *volume = &VOL[i];
200
201 if (volume->state != volume_unallocated)
202 free_volume(i);
203 }
204 Free(VOL);
205 }
206 bzero(&vinum_conf, sizeof(vinum_conf));
207 vinum_conf.version = VINUMVERSION; /* reinstate version number */
208 }
209
210
211 /* ARGSUSED */
212 /* Open a vinum object */
213 int
214 vinumopen(dev_t dev,
215 int flags,
216 int fmt,
217 struct proc *p)
218 {
219 int error;
220 unsigned int index;
221 struct volume *vol;
222 struct plex *plex;
223 struct sd *sd;
224 int devminor; /* minor number */
225
226 devminor = minor(dev);
227 error = 0;
228 /* First, decide what we're looking at */
229 switch (DEVTYPE(dev)) {
230 case VINUM_VOLUME_TYPE:
231 /*
232 * The super device and daemon device are the last two
233 * volume numbers, so check for them first.
234 */
235 if ((devminor == VINUM_DAEMON_VOL) /* daemon device */
236 ||(devminor == VINUM_SUPERDEV_VOL)) { /* or normal super device */
237 error = suser(p->p_ucred, &p->p_acflag); /* are we root? */
238
239 if (error == 0) { /* yes, can do */
240 if (devminor == VINUM_DAEMON_VOL) /* daemon device */
241 vinum_conf.flags |= VF_DAEMONOPEN; /* we're open */
242 else if (devminor == VINUM_SUPERDEV_VOL)
243 vinum_conf.flags |= VF_OPEN; /* we're open */
244 }
245 return error;
246 }
247 /* Must be a real volume. Check. */
248 index = Volno(dev);
249 if (index >= vinum_conf.volumes_allocated)
250 return ENXIO; /* no such device */
251 vol = &VOL[index];
252
253 switch (vol->state) {
254 case volume_unallocated:
255 case volume_uninit:
256 return ENXIO;
257
258 case volume_up:
259 vol->flags |= VF_OPEN; /* note we're open */
260 return 0;
261
262 case volume_down:
263 return EIO;
264
265 default:
266 return EINVAL;
267 }
268
269 case VINUM_PLEX_TYPE:
270 index = Plexno(dev); /* get plex index in vinum_conf */
271 if (index >= vinum_conf.plexes_allocated)
272 return ENXIO; /* no such device */
273 plex = &PLEX[index];
274
275 switch (plex->state) {
276 case plex_unallocated:
277 return ENXIO;
278
279 case plex_referenced:
280 return EINVAL;
281
282 default:
283 plex->flags |= VF_OPEN; /* note we're open */
284 return 0;
285 }
286
287 case VINUM_SD_TYPE:
288 case VINUM_SD2_TYPE:
289 index = Sdno(dev); /* get the subdisk number */
290 if (index >= vinum_conf.subdisks_allocated) /* not a valid SD entry */
291 return ENXIO; /* no such device */
292 sd = &SD[index];
293
294 /*
295 * Opening a subdisk is always a special operation, so
296 * we ignore the state as long as it represents a real
297 * subdisk.
298 */
299 switch (sd->state) {
300 case sd_unallocated:
301 return ENXIO;
302
303 case sd_uninit:
304 case sd_referenced:
305 return EINVAL;
306
307 default:
308 sd->flags |= VF_OPEN; /* note we're open */
309 return 0;
310 }
311 }
312 return 0; /* to keep the compiler happy */
313 }
314
315 /* ARGSUSED */
316 int
317 vinumclose(dev_t dev,
318 int flags,
319 int fmt,
320 struct proc *p)
321 {
322 unsigned int index;
323 struct volume *vol;
324 int devminor;
325
326 devminor = minor(dev);
327 /* First, decide what we're looking at */
328 switch (DEVTYPE(dev)) {
329 case VINUM_VOLUME_TYPE:
330 /*
331 * The super device and daemon device are the last two
332 * volume numbers, so check for them first.
333 */
334 if ((devminor == VINUM_DAEMON_VOL) /* daemon device */
335 ||(devminor == VINUM_SUPERDEV_VOL)) { /* or normal super device */
336 /*
337 * don't worry about whether we're root:
338 * nobody else would get this far.
339 */
340 if (devminor == VINUM_SUPERDEV_VOL) /* normal superdev */
341 vinum_conf.flags &= ~VF_OPEN; /* no longer open */
342 else { /* the daemon device */
343 vinum_conf.flags &= ~VF_DAEMONOPEN; /* no longer open */
344 if (vinum_conf.flags & VF_STOPPING) /* we're trying to stop, */
345 wakeup(&vinumclose); /* we can continue now */
346 }
347 return 0;
348 }
349 /* Real volume */
350 index = Volno(dev);
351 if (index >= vinum_conf.volumes_allocated)
352 return ENXIO; /* no such device */
353 vol = &VOL[index];
354
355 switch (vol->state) {
356 case volume_unallocated:
357 case volume_uninit:
358 return ENXIO;
359
360 case volume_up:
361 vol->flags &= ~VF_OPEN; /* reset our flags */
362 return 0;
363
364 case volume_down:
365 return EIO;
366
367 default:
368 return EINVAL;
369 }
370
371 case VINUM_PLEX_TYPE:
372 if (Volno(dev) >= vinum_conf.volumes_allocated)
373 return ENXIO;
374 /* FALLTHROUGH */
375
376 case VINUM_SD_TYPE:
377 if ((Volno(dev) >= vinum_conf.volumes_allocated) || /* no such volume */
378 (Plexno(dev) >= vinum_conf.plexes_allocated)) /* or no such plex */
379 return ENXIO; /* no such device */
380 /* FALLTHROUGH */
381
382 default:
383 return ENODEV; /* don't know what to do with these */
384 }
385 }
386
387
388 /* size routine */
389 int
390 vinumsize(dev_t dev)
391 {
392 struct volume *vol;
393 int size;
394
395 vol = &VOL[Volno(dev)];
396
397 if (vol->state == volume_up)
398 size = vol->size;
399 else
400 return 0; /* err on the size of conservatism */
401
402 return size;
403 }
404
405 int
406 vinumdump(dev_t dev, daddr_t da, caddr_t ca, size_t size)
407 {
408 return ENXIO; /* Implement this! XXX. */
409 }
410
411 /* Local Variables: */
412 /* fill-column: 60 */
413 /* End: */
Cache object: 697ebab2896b68e74ea9bb4cd4083c06
|