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
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]
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)
36 #include <sys/types.h>
38 #include <sys/mntent.h>
42 * data structures for parallelization
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 */
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
;
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 */
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
)
111 extern char *strdup();
113 if ((fd
= open64(devnm
, O_RDONLY
)) == -1) {
117 if (ioctl(fd
, DKIOCINFO
, &dki
) == -1) {
119 fprintf(stderr
, "device: `%s'\n", devnm
);
124 if ((rdp
= (struct rawdev
*)malloc(sizeof (struct rawdev
))) == NULL
) {
125 (void) fprintf(stderr
, "out of memory in preenlib\n");
128 if ((rdp
->devname
= strdup(devnm
)) == NULL
) {
129 (void) fprintf(stderr
, "out of memory in preenlib\n");
135 if (preen_subdev(devnm
, &dki
, (void *)rdp
)) {
136 preen_addunit(rdp
, dki
.dki_dname
, NULL
, NULL
, dki
.dki_unit
);
139 rdp
->nxtrd
= unchecked
;
145 preen_subdev(char *name
, struct dk_cinfo
*dkiop
, void *dp
)
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
) {
156 (void) fprintf(stderr
, "preen_subdev: %s\n", dlerror());
159 fptr
= (int (*)())dlsym(dlhandle
, BUILD_NAME
);
162 (void) fprintf(stderr
, "preen_subdev: %s\n", dlerror());
165 (*fptr
)(name
, dkiop
, dp
);
170 * select a device from the "unchecked" list, and add it to the
174 preen_getdev(char *devnm
)
179 if (unchecked
== NULL
)
182 rdp
= get_runnable(&unchecked
);
185 for (dp
= rdp
->alldevs
; dp
; dp
= dp
->nxtdev
) {
190 (void) strcpy(devnm
, rdp
->devname
);
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)
210 ldp
->nxtrd
= dp
->nxtrd
;
225 get_runnable(struct rawdev
**devlist
)
227 struct rawdev
*last
, *rdp
;
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
);
245 * remove from list...
249 last
->nxtrd
= rdp
->nxtrd
;
251 *devlist
= rdp
->nxtrd
;
259 * add the given driver/unit reference to the `rawdev' structure identified
261 * If a new `driver' structure needs to be created, associate the given
262 * choosing function and driver private data with it.
267 char *dname
, /* driver name */
268 int (*cf
)(), /* candidate choosing function */
269 void *datap
, /* driver private data */
270 uint_t unit
) /* unit number */
275 struct rawdev
*rdp
= (struct rawdev
*)cookie
;
278 * locate the driver struct
281 for (drvid
= 0; drvid
< ndrivers
; drvid
++) {
282 if (strcmp(dlist
[drvid
].name
, dname
) == 0) {
290 * driver struct doesn't exist yet -- create one
294 drvid
= alloc_driver(dname
, cf
, datap
);
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
)
308 * allocate a new `struct onedev' and chain it in
311 devp
= alloc_dev(drvid
);
312 devp
->nxtdev
= rdp
->alldevs
;
317 * add `unit' to the unitmap in devp
324 alloc_driver(char *name
, int (*cf
)(), void *datap
)
327 extern char *strdup();
329 if (ndrivers
== ndalloc
) {
332 reallocarray(dlist
, DRIVER_ALLOC
, sizeof (struct driver
)) :
334 malloc(sizeof (struct driver
) * DRIVER_ALLOC
);
336 (void) fprintf(stderr
, "out of memory in preenlib\n");
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");
361 devp
= (struct onedev
*)malloc(sizeof (struct onedev
));
363 (void) fprintf(stderr
, "out of memory in preenlib\n");
368 devp
->unitmap
= NULL
;
375 addunit(struct onedev
*devp
, uint_t unit
)
379 newsize
= howmany(unit
+1, WORDSIZE
);
380 if (devp
->mapsize
< newsize
) {
381 devp
->unitmap
= devp
->mapsize
?
382 reallocarray(devp
->unitmap
, newsize
,
384 malloc(newsize
* sizeof (uint_t
));
385 if (devp
->unitmap
== NULL
) {
386 (void) fprintf(stderr
, "out of memory in preenlib\n");
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
));
397 chooseone(int devmapsize
, ulong_t
*devmap
, int drvmapsize
, ulong_t
*drvmap
)
401 for (i
= 0; i
< min(devmapsize
, drvmapsize
); i
++) {
402 if (devmap
[i
] & drvmap
[i
])
409 * mark the given driver/unit pair as busy. This is called from
414 makebusy(struct onedev
*dev
)
416 struct driver
*drvp
= &dlist
[dev
->drvid
];
417 int newsize
= dev
->mapsize
;
420 if (drvp
->mapsize
< newsize
) {
421 drvp
->busymap
= drvp
->mapsize
?
422 reallocarray(drvp
->busymap
, newsize
,
424 malloc(newsize
* sizeof (uint_t
));
425 if (drvp
->busymap
== NULL
) {
426 (void) fprintf(stderr
, "out of memory in preenlib\n");
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
444 notbusy(struct rawdev
*rd
)
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
]);