Merge commit 'ad3ad82ad2fb99c424a8482bd1908d08b990ccea'
[unleashed.git] / usr / src / cmd / fs.d / preenlib.c
blobb0de09735fc7cc100e67d9c4fa3252a1cd99712d
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
22 #pragma ident "%Z%%M% %I% %E% SMI"
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
29 * common routines for parallelization (used by both fsck and quotacheck)
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <dlfcn.h>
35 #include <macros.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <sys/mntent.h>
39 #include <sys/dkio.h>
42 * data structures for parallelization
44 struct driver {
45 char *name; /* driver name (from DKIOCINFO) */
46 uint_t mapsize; /* size of `busymap' */
47 uint_t *busymap; /* bitmask of active units */
48 int (*choosefunc)(); /* driver specific chooser */
49 void *data; /* driver private data */
52 struct onedev {
53 int drvid; /* index in driver array */
54 uint_t mapsize; /* size of `unitmap' */
55 uint_t *unitmap; /* unit #'s (from DKIOCINFO) */
56 struct onedev *nxtdev;
59 struct rawdev {
60 char *devname; /* name passed to preen_addev */
61 struct onedev *alldevs; /* info about each component device */
62 struct rawdev *nxtrd; /* next entry in list */
65 static int debug = 0;
68 * defines used in building shared object names
71 /* the directory where we find shared objects */
72 #define OBJECT_DIRECTORY "/usr/lib/drv"
74 /* a shared object name is OBJECT_PREFIX || driver_name */
75 #define OBJECT_PREFIX "preen_"
77 /* the version of the driver interface we support */
78 #define OBJECT_VERSION 1
80 /* the "build" entry point for a driver specific object is named this */
81 #define BUILD_ENTRY preen_build_devs
82 #define BUILD_NAME "preen_build_devs"
84 #define DRIVER_ALLOC 10
85 static int ndrivers, ndalloc;
86 static struct driver *dlist;
88 static struct rawdev *unchecked, *active, *get_runnable();
89 static struct onedev *alloc_dev();
90 static int chooseone();
92 #define WORDSIZE (NBBY * sizeof (uint_t))
94 void preen_addunit(void *, char *, int (*)(), void *, uint_t);
95 int preen_subdev(char *, struct dk_cinfo *, void *);
97 static int alloc_driver(char *, int (*)(), void *);
98 static void addunit(struct onedev *, uint_t);
99 static void makebusy(struct onedev *);
100 static void notbusy(struct rawdev *);
103 * add the given device to the list of devices to be checked
106 preen_addev(char *devnm)
108 struct rawdev *rdp;
109 int fd;
110 struct dk_cinfo dki;
111 extern char *strdup();
113 if ((fd = open64(devnm, O_RDONLY)) == -1) {
114 perror(devnm);
115 return (-1);
117 if (ioctl(fd, DKIOCINFO, &dki) == -1) {
118 perror("DKIOCINFO");
119 fprintf(stderr, "device: `%s'\n", devnm);
120 (void) close(fd);
121 return (-1);
123 (void) close(fd);
124 if ((rdp = (struct rawdev *)malloc(sizeof (struct rawdev))) == NULL) {
125 (void) fprintf(stderr, "out of memory in preenlib\n");
126 return (-1);
128 if ((rdp->devname = strdup(devnm)) == NULL) {
129 (void) fprintf(stderr, "out of memory in preenlib\n");
130 return (-1);
132 rdp->alldevs = NULL;
133 rdp->nxtrd = NULL;
135 if (preen_subdev(devnm, &dki, (void *)rdp)) {
136 preen_addunit(rdp, dki.dki_dname, NULL, NULL, dki.dki_unit);
139 rdp->nxtrd = unchecked;
140 unchecked = rdp;
141 return (0);
145 preen_subdev(char *name, struct dk_cinfo *dkiop, void *dp)
147 char modname[255];
148 void *dlhandle;
149 int (*fptr)();
151 (void) sprintf(modname, "%s/%s%s.so.%d",
152 OBJECT_DIRECTORY, OBJECT_PREFIX, dkiop->dki_dname, OBJECT_VERSION);
153 dlhandle = dlopen(modname, RTLD_LAZY);
154 if (dlhandle == NULL) {
155 if (debug)
156 (void) fprintf(stderr, "preen_subdev: %s\n", dlerror());
157 return (1);
159 fptr = (int (*)())dlsym(dlhandle, BUILD_NAME);
160 if (fptr == NULL) {
161 if (debug)
162 (void) fprintf(stderr, "preen_subdev: %s\n", dlerror());
163 return (1);
165 (*fptr)(name, dkiop, dp);
166 return (0);
170 * select a device from the "unchecked" list, and add it to the
171 * active list.
174 preen_getdev(char *devnm)
176 struct rawdev *rdp;
177 struct onedev *dp;
179 if (unchecked == NULL)
180 return (0);
182 rdp = get_runnable(&unchecked);
184 if (rdp) {
185 for (dp = rdp->alldevs; dp; dp = dp->nxtdev) {
186 makebusy(dp);
188 rdp->nxtrd = active;
189 active = rdp;
190 (void) strcpy(devnm, rdp->devname);
191 return (1);
192 } else {
193 return (2);
198 preen_releasedev(char *name)
200 struct rawdev *dp, *ldp;
202 for (ldp = NULL, dp = active; dp != NULL; ldp = dp, dp = dp->nxtrd) {
203 if (strcmp(dp->devname, name) == 0)
204 break;
207 if (dp == NULL)
208 return (-1);
209 if (ldp != NULL) {
210 ldp->nxtrd = dp->nxtrd;
211 } else {
212 active = dp->nxtrd;
215 notbusy(dp);
217 * free(dp->devname);
218 * free(dp);
220 return (0);
223 static
224 struct rawdev *
225 get_runnable(struct rawdev **devlist)
227 struct rawdev *last, *rdp;
228 struct onedev *devp;
229 struct driver *drvp;
230 int rc = 1;
232 for (last = NULL, rdp = *devlist; rdp; last = rdp, rdp = rdp->nxtrd) {
233 for (devp = rdp->alldevs; devp != NULL; devp = devp->nxtdev) {
234 drvp = &dlist[devp->drvid];
235 rc = (*drvp->choosefunc)(devp->mapsize, devp->unitmap,
236 drvp->mapsize, drvp->busymap);
237 if (rc != 0)
238 break;
240 if (rc == 0)
241 break;
245 * remove from list...
247 if (rdp) {
248 if (last) {
249 last->nxtrd = rdp->nxtrd;
250 } else {
251 *devlist = rdp->nxtrd;
255 return (rdp);
259 * add the given driver/unit reference to the `rawdev' structure identified
260 * by `cookie'
261 * If a new `driver' structure needs to be created, associate the given
262 * choosing function and driver private data with it.
264 void
265 preen_addunit(
266 void *cookie,
267 char *dname, /* driver name */
268 int (*cf)(), /* candidate choosing function */
269 void *datap, /* driver private data */
270 uint_t unit) /* unit number */
272 int drvid;
273 struct driver *dp;
274 struct onedev *devp;
275 struct rawdev *rdp = (struct rawdev *)cookie;
278 * locate the driver struct
280 dp = NULL;
281 for (drvid = 0; drvid < ndrivers; drvid++) {
282 if (strcmp(dlist[drvid].name, dname) == 0) {
283 dp = &dlist[drvid];
284 break;
288 if (dp == NULL) {
290 * driver struct doesn't exist yet -- create one
292 if (cf == NULL)
293 cf = chooseone;
294 drvid = alloc_driver(dname, cf, datap);
295 dp = &dlist[drvid];
298 for (devp = rdp->alldevs; devp != NULL; devp = devp->nxtdev) {
300 * see if this device already references the given driver
302 if (devp->drvid == drvid)
303 break;
306 if (devp == NULL) {
308 * allocate a new `struct onedev' and chain it in
309 * rdp->alldevs...
311 devp = alloc_dev(drvid);
312 devp->nxtdev = rdp->alldevs;
313 rdp->alldevs = devp;
317 * add `unit' to the unitmap in devp
319 addunit(devp, unit);
322 static
324 alloc_driver(char *name, int (*cf)(), void *datap)
326 struct driver *dp;
327 extern char *strdup();
329 if (ndrivers == ndalloc) {
330 dlist = ndalloc ?
331 (struct driver *)
332 reallocarray(dlist, DRIVER_ALLOC, sizeof (struct driver)) :
333 (struct driver *)
334 malloc(sizeof (struct driver) * DRIVER_ALLOC);
335 if (dlist == NULL) {
336 (void) fprintf(stderr, "out of memory in preenlib\n");
337 exit(1);
339 ndalloc += DRIVER_ALLOC;
342 dp = &dlist[ndrivers];
343 dp->name = strdup(name);
344 if (dp->name == NULL) {
345 (void) fprintf(stderr, "out of memory in preenlib\n");
346 exit(1);
348 dp->choosefunc = cf;
349 dp->data = datap;
350 dp->mapsize = 0;
351 dp->busymap = NULL;
352 return (ndrivers++);
355 static
356 struct onedev *
357 alloc_dev(int did)
359 struct onedev *devp;
361 devp = (struct onedev *)malloc(sizeof (struct onedev));
362 if (devp == NULL) {
363 (void) fprintf(stderr, "out of memory in preenlib\n");
364 exit(1);
366 devp->drvid = did;
367 devp->mapsize = 0;
368 devp->unitmap = NULL;
369 devp->nxtdev = NULL;
370 return (devp);
373 static
374 void
375 addunit(struct onedev *devp, uint_t unit)
377 uint_t newsize;
379 newsize = howmany(unit+1, WORDSIZE);
380 if (devp->mapsize < newsize) {
381 devp->unitmap = devp->mapsize ?
382 reallocarray(devp->unitmap, newsize,
383 sizeof (uint_t)) :
384 malloc(newsize * sizeof (uint_t));
385 if (devp->unitmap == NULL) {
386 (void) fprintf(stderr, "out of memory in preenlib\n");
387 exit(1);
389 (void) memset((char *)&devp->unitmap[devp->mapsize], 0,
390 (uint_t)((newsize - devp->mapsize) * sizeof (uint_t)));
391 devp->mapsize = newsize;
393 devp->unitmap[unit / WORDSIZE] |= (1 << (unit % WORDSIZE));
396 static int
397 chooseone(int devmapsize, ulong_t *devmap, int drvmapsize, ulong_t *drvmap)
399 int i;
401 for (i = 0; i < min(devmapsize, drvmapsize); i++) {
402 if (devmap[i] & drvmap[i])
403 return (1);
405 return (0);
409 * mark the given driver/unit pair as busy. This is called from
410 * preen_getdev.
412 static
413 void
414 makebusy(struct onedev *dev)
416 struct driver *drvp = &dlist[dev->drvid];
417 int newsize = dev->mapsize;
418 int i;
420 if (drvp->mapsize < newsize) {
421 drvp->busymap = drvp->mapsize ?
422 reallocarray(drvp->busymap, newsize,
423 sizeof (uint_t)) :
424 malloc(newsize * sizeof (uint_t));
425 if (drvp->busymap == NULL) {
426 (void) fprintf(stderr, "out of memory in preenlib\n");
427 exit(1);
429 (void) memset((char *)&drvp->busymap[drvp->mapsize], 0,
430 (uint_t)((newsize - drvp->mapsize) * sizeof (uint_t)));
431 drvp->mapsize = newsize;
434 for (i = 0; i < newsize; i++)
435 drvp->busymap[i] |= dev->unitmap[i];
439 * make each device in the given `rawdev' un-busy.
440 * Called from preen_releasedev
442 static
443 void
444 notbusy(struct rawdev *rd)
446 struct onedev *devp;
447 struct driver *drvp;
448 int i;
450 for (devp = rd->alldevs; devp; devp = devp->nxtdev) {
451 drvp = &dlist[devp->drvid];
452 for (i = 0; i < devp->mapsize; i++)
453 drvp->busymap[i] &= ~(devp->unitmap[i]);