DEVFS - Cleanup, remove debug messages.
[dragonfly.git] / sys / vfs / devfs / devfs_core.c
CommitLineData
21864bc5
MD
1/*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/mount.h>
38#include <sys/vnode.h>
39#include <sys/types.h>
40#include <sys/lock.h>
41#include <sys/msgport.h>
42#include <sys/msgport2.h>
43#include <sys/spinlock2.h>
44#include <sys/sysctl.h>
45#include <sys/ucred.h>
46#include <sys/param.h>
47#include <sys/sysref2.h>
7cbab9da 48#include <sys/systm.h>
21864bc5
MD
49#include <vfs/devfs/devfs.h>
50#include <vfs/devfs/devfs_rules.h>
51
52MALLOC_DEFINE(M_DEVFS, "devfs", "Device File System (devfs) allocations");
7cbab9da 53DEVFS_DECLARE_CLONE_BITMAP(ops_id);
21864bc5
MD
54/*
55 * SYSREF Integration - reference counting, allocation,
56 * sysid and syslink integration.
57 */
58static void devfs_cdev_terminate(cdev_t dev);
59static struct sysref_class cdev_sysref_class = {
60 .name = "cdev",
61 .mtype = M_DEVFS,
62 .proto = SYSREF_PROTO_DEV,
63 .offset = offsetof(struct cdev, si_sysref),
64 .objsize = sizeof(struct cdev),
65 .mag_capacity = 32,
66 .flags = 0,
67 .ops = {
68 .terminate = (sysref_terminate_func_t)devfs_cdev_terminate
69 }
70};
71
72static struct objcache *devfs_node_cache;
73static struct objcache *devfs_msg_cache;
74static struct objcache *devfs_dev_cache;
75
76static struct objcache_malloc_args devfs_node_malloc_args = {
77 sizeof(struct devfs_node), M_DEVFS };
78struct objcache_malloc_args devfs_msg_malloc_args = {
79 sizeof(struct devfs_msg), M_DEVFS };
80struct objcache_malloc_args devfs_dev_malloc_args = {
81 sizeof(struct cdev), M_DEVFS };
82
83static struct devfs_dev_head devfs_dev_list = TAILQ_HEAD_INITIALIZER(devfs_dev_list);
84static struct devfs_mnt_head devfs_mnt_list = TAILQ_HEAD_INITIALIZER(devfs_mnt_list);
85static struct devfs_chandler_head devfs_chandler_list = TAILQ_HEAD_INITIALIZER(devfs_chandler_list);
86static struct devfs_alias_head devfs_alias_list = TAILQ_HEAD_INITIALIZER(devfs_alias_list);
87
88struct lock devfs_lock;
89static struct lwkt_port devfs_dispose_port;
90static struct lwkt_port devfs_msg_port;
91static struct thread *td_core;
21864bc5
MD
92
93static ino_t d_ino = 0;
94static __uint32_t msg_id = 0;
95static struct spinlock ino_lock;
96static int devfs_debug_enable = 0;
97
98static ino_t devfs_fetch_ino(void);
99static int devfs_gc_dirs(struct devfs_node *);
100static int devfs_gc_links(struct devfs_node *, struct devfs_node *, size_t);
101static int devfs_create_all_dev_worker(struct devfs_node *);
102static int devfs_create_dev_worker(cdev_t, uid_t, gid_t, int);
103static int devfs_destroy_dev_worker(cdev_t);
104static int devfs_destroy_subnames_worker(char *);
105static int devfs_destroy_dev_by_ops_worker(struct dev_ops *, int);
106static int devfs_propagate_dev(cdev_t, int);
ca8d7677 107static int devfs_unlink_dev(cdev_t dev);
21864bc5
MD
108
109static int devfs_chandler_add_worker(char *, d_clone_t *);
110static int devfs_chandler_del_worker(char *);
111
112static void devfs_msg_autofree_reply(lwkt_port_t, lwkt_msg_t);
113static void devfs_msg_core(void *);
114
115static int devfs_find_device_by_name_worker(devfs_msg_t);
116static int devfs_find_device_by_udev_worker(devfs_msg_t);
117
118static int devfs_apply_reset_rules_caller(char *, int);
119static int devfs_apply_reset_rules_worker(struct devfs_node *, int);
120
121static int devfs_scan_callback_worker(devfs_scan_t *);
122
123static struct devfs_node *devfs_resolve_or_create_dir(struct devfs_node *, char *, size_t, int);
124
125static int devfs_make_alias_worker(struct devfs_alias *);
126static int devfs_alias_remove(cdev_t);
127static int devfs_alias_reap(void);
128static int devfs_alias_propagate(struct devfs_alias *);
129static int devfs_alias_apply(struct devfs_node *, struct devfs_alias *);
130static int devfs_alias_check_create(struct devfs_node *);
131
ca8d7677
MD
132static int devfs_clr_subnames_flag_worker(char *, uint32_t);
133static int devfs_destroy_subnames_without_flag_worker(char *, uint32_t);
134
21864bc5
MD
135/*
136 * devfs_debug() is a SYSCTL and TUNABLE controlled debug output function using kvprintf
137 */
138int
139devfs_debug(int level, char *fmt, ...)
140{
141 __va_list ap;
142
143 __va_start(ap, fmt);
144 if (level <= devfs_debug_enable)
145 kvprintf(fmt, ap);
146 __va_end(ap);
147
148 return 0;
149}
150
151/*
ca8d7677
MD
152 * devfs_allocp() Allocates a new devfs node with the specified
153 * parameters. The node is also automatically linked into the topology
154 * if a parent is specified. It also calls the rule and alias stuff to
155 * be applied on the new node
21864bc5
MD
156 */
157struct devfs_node *
ca8d7677
MD
158devfs_allocp(devfs_nodetype devfsnodetype, char *name,
159 struct devfs_node *parent, struct mount *mp, cdev_t dev)
21864bc5
MD
160{
161 struct devfs_node *node = NULL;
162 size_t namlen = strlen(name);
163 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp -1- for %s\n", name?name:"NULL");
164
165 node = objcache_get(devfs_node_cache, M_WAITOK);
166
ca8d7677
MD
167 bzero(node, sizeof(*node));
168
21864bc5
MD
169 atomic_add_int(&(DEVFS_MNTDATA(mp)->leak_count), 1);
170
ca8d7677 171 node->d_dev = NULL;
21864bc5
MD
172 node->nchildren = 1;
173 node->mp = mp;
174 node->d_dir.d_ino = devfs_fetch_ino();
21864bc5
MD
175 node->cookie_jar = 2; /* Leave 0 and 1 for '.' and '..', respectively */
176
177 /* Access Control members */
178 node->mode = DEVFS_DEFAULT_MODE; /* files access mode and type */
179 node->uid = DEVFS_DEFAULT_UID; /* owner user id */
180 node->gid = DEVFS_DEFAULT_GID; /* owner group id */
181
21864bc5
MD
182 switch (devfsnodetype) {
183 case Proot:
894bbb25
AH
184 /* Ensure that we don't recycle the root vnode */
185 node->flags |= DEVFS_NODE_LINKED;
21864bc5
MD
186 case Pdir:
187 TAILQ_INIT(DEVFS_DENODE_HEAD(node));
188 node->d_dir.d_type = DT_DIR;
189 node->nchildren = 2;
190 break;
191
192 case Plink:
193 node->d_dir.d_type = DT_LNK;
194 break;
195
196 case Preg:
197 node->d_dir.d_type = DT_REG;
198 break;
199
200 case Pdev:
201 if (dev != NULL) {
202 node->d_dir.d_type = DT_CHR;
203 node->d_dev = dev;
204 node->d_dir.d_ino = dev->si_inode;
205
206 node->mode = dev->si_perms; /* files access mode and type */
207 node->uid = dev->si_uid; /* owner user id */
208 node->gid = dev->si_gid; /* owner group id */
209
210 devfs_alias_check_create(node);
211 }
212 break;
213
214 default:
215 panic("devfs_allocp: unknown node type");
216 }
217
218 node->v_node = NULL;
219 node->node_type = devfsnodetype;
220
221 /* Init the dirent structure of each devfs vnode */
ca8d7677
MD
222 KKASSERT(namlen < 256);
223
21864bc5 224 node->d_dir.d_namlen = namlen;
ca8d7677 225 node->d_dir.d_name = kmalloc(namlen+1, M_DEVFS, M_WAITOK);
21864bc5
MD
226 memcpy(node->d_dir.d_name, name, namlen);
227 node->d_dir.d_name[namlen] = '\0';
228
229 /* Initialize the parent node element */
230 node->parent = parent;
231
232 /* Apply rules */
233 devfs_rule_check_apply(node);
234
ca8d7677
MD
235 /* xtime members */
236 nanotime(&node->atime);
237 node->mtime = node->ctime = node->atime;
238
239 /*
240 * Associate with parent as last step, clean out namecache
241 * reference.
242 */
21864bc5
MD
243 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp: about to insert node\n");
244 if ((parent != NULL) &&
ca8d7677
MD
245 ((parent->node_type == Proot) || (parent->node_type == Pdir))) {
246 devfs_debug(DEVFS_DEBUG_DEBUG,
247 "devfs_allocp: node inserted %p\n",
248 node);
21864bc5
MD
249 parent->nchildren++;
250 node->cookie = parent->cookie_jar++;
251 node->flags |= DEVFS_NODE_LINKED;
ca8d7677 252 TAILQ_INSERT_TAIL(DEVFS_DENODE_HEAD(parent), node, link);
21864bc5 253
ca8d7677
MD
254 /* This forces negative namecache lookups to clear */
255 ++mp->mnt_namecache_gen;
256 }
21864bc5
MD
257
258 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp -end:2-\n");
259 return node;
260}
261
262/*
263 * devfs_allocv() allocates a new vnode based on a devfs node.
264 */
265int
266devfs_allocv(struct vnode **vpp, struct devfs_node *node)
267{
268 struct vnode *vp;
269 int error = 0;
270
271 KKASSERT(node);
272
273 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -1-\n");
274
275try_again:
276 while ((vp = node->v_node) != NULL) {
277 error = vget(vp, LK_EXCLUSIVE);
278 if (error != ENOENT) {
279 *vpp = vp;
280 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv, code path 2...\n");
281 goto out;
282 }
283 }
284 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -3-\n");
285
21864bc5
MD
286 if ((error = getnewvnode(VT_DEVFS, node->mp, vpp, 0, 0)) != 0)
287 goto out;
288
289 vp = *vpp;
290
291 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -4-\n");
292
293 if (node->v_node != NULL) {
294 vp->v_type = VBAD;
295 vx_put(vp);
296 goto try_again;
297 }
298
299 vp->v_data = node;
300 node->v_node = vp;
301 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -5-\n");
302
303 switch (node->node_type) {
304 case Proot:
305 vp->v_flag |= VROOT;
306 case Pdir:
307 vp->v_type = VDIR;
308 break;
309
310 case Plink:
311 vp->v_type = VLNK;
312 break;
313
314 case Preg:
315 vp->v_type = VREG;
316 break;
317
318 case Pdev:
319 vp->v_type = VCHR;
320 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -6-\n");
321 KKASSERT(node->d_dev);
322
323 if (node->d_dev) {
324 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -7-\n");
325 vp->v_uminor = node->d_dev->si_uminor;
326 vp->v_umajor = 0;
9b823501 327#if 0
21864bc5 328 vp->v_rdev = node->d_dev;
9b823501
AH
329#endif
330 v_associate_rdev(vp, node->d_dev);
21864bc5 331 vp->v_ops = &node->mp->mnt_vn_spec_ops;
21864bc5
MD
332 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -8-\n");
333 } else {
334 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv: type is Pdev but d_dev is not set!!!!\n");
335 }
336 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -9-\n");
337 break;
338
339 default:
340 panic("devfs_allocv: unknown node type");
341 }
342
343out:
344 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -10-\n");
345 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocv -end:11-\n");
346 return error;
347}
348
349/*
350 * devfs_allocvp allocates both a devfs node (with the given settings) and a vnode
351 * based on the newly created devfs node.
352 */
353int
354devfs_allocvp(struct mount *mp, struct vnode **vpp, devfs_nodetype devfsnodetype,
355 char *name, struct devfs_node *parent, cdev_t dev)
356{
357 struct devfs_node *node;
358
359 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocvp -1-\n");
360 node = devfs_allocp(devfsnodetype, name, parent, mp, dev);
361 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocvp -2-\n");
362 if (node != NULL)
363 devfs_allocv(vpp, node);
364 else
365 *vpp = NULL;
366
367 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocvp -end:3-\n");
368
369 return 0;
370}
371
372/*
ca8d7677
MD
373 * Destroy the devfs_node. The node must be unlinked from the topology.
374 *
375 * This function will also destroy any vnode association with the node
376 * and device.
377 *
378 * The cdev_t itself remains intact.
21864bc5
MD
379 */
380int
381devfs_freep(struct devfs_node *node)
382{
ca8d7677
MD
383 struct vnode *vp;
384
21864bc5 385 KKASSERT(node);
ca8d7677
MD
386 KKASSERT(((node->flags & DEVFS_NODE_LINKED) == 0) ||
387 (node->node_type == Proot));
388 KKASSERT((node->flags & DEVFS_DESTROYED) == 0);
21864bc5
MD
389
390 atomic_subtract_int(&(DEVFS_MNTDATA(node->mp)->leak_count), 1);
391 if (node->symlink_name) {
392 kfree(node->symlink_name, M_DEVFS);
393 node->symlink_name = NULL;
394 }
395
ca8d7677
MD
396 /*
397 * Remove the node from the orphan list if it is still on it.
398 */
399 if (node->flags & DEVFS_ORPHANED)
21864bc5
MD
400 devfs_tracer_del_orphan(node);
401
ca8d7677
MD
402 /*
403 * Disassociate the vnode from the node. This also prevents the
404 * vnode's reclaim code from double-freeing the node.
405 */
406 if ((vp = node->v_node) != NULL) {
9b823501 407#if 0
ca8d7677 408 vp->v_rdev = NULL;
9b823501
AH
409#endif
410 v_release_rdev(vp);
ca8d7677
MD
411 vp->v_data = NULL;
412 node->v_node = NULL;
413 }
414 if (node->d_dir.d_name)
415 kfree(node->d_dir.d_name, M_DEVFS);
416 node->flags |= DEVFS_DESTROYED;
417
21864bc5
MD
418 objcache_put(devfs_node_cache, node);
419
420 return 0;
421}
422
423/*
ca8d7677
MD
424 * Unlink the devfs node from the topology and add it to the orphan list.
425 * The node will later be destroyed by freep.
426 *
427 * Any vnode association, including the v_rdev and v_data, remains intact
428 * until the freep.
21864bc5
MD
429 */
430int
431devfs_unlinkp(struct devfs_node *node)
432{
433 struct devfs_node *parent;
434 KKASSERT(node);
435
436 devfs_tracer_add_orphan(node);
ca8d7677
MD
437 devfs_debug(DEVFS_DEBUG_DEBUG,
438 "devfs_unlinkp for %s\n", node->d_dir.d_name);
21864bc5
MD
439 parent = node->parent;
440
ca8d7677
MD
441 /*
442 * If the parent is known we can unlink the node out of the topology
443 */
21864bc5
MD
444 if (parent) {
445 TAILQ_REMOVE(DEVFS_DENODE_HEAD(parent), node, link);
446 parent->nchildren--;
447 KKASSERT((parent->nchildren >= 0));
448 node->flags &= ~DEVFS_NODE_LINKED;
449 }
450 node->parent = NULL;
21864bc5
MD
451 return 0;
452}
453
454/*
ca8d7677
MD
455 * devfs_reaperp() is a recursive function that iterates through all the
456 * topology, unlinking and freeing all devfs nodes.
21864bc5
MD
457 */
458int
459devfs_reaperp(struct devfs_node *node)
460{
461 struct devfs_node *node1, *node2;
462
21864bc5 463 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
ca8d7677
MD
464 devfs_debug(DEVFS_DEBUG_DEBUG,
465 "This node is Pdir or Proot; has %d children\n",
466 node->nchildren);
21864bc5 467 if (node->nchildren > 2) {
ca8d7677
MD
468 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node),
469 link, node2) {
21864bc5
MD
470 devfs_reaperp(node1);
471 }
472 }
473 }
21864bc5
MD
474 devfs_unlinkp(node);
475 devfs_freep(node);
476
477 return 0;
478}
479
480/*
ca8d7677
MD
481 * devfs_gc() is devfs garbage collector. It takes care of unlinking and
482 * freeing a node, but also removes empty directories and links that link
483 * via devfs auto-link mechanism to the node being deleted.
21864bc5
MD
484 */
485int
486devfs_gc(struct devfs_node *node)
487{
488 struct devfs_node *root_node = DEVFS_MNTDATA(node->mp)->root_node;
489
490 devfs_gc_links(root_node, node, node->nlinks);
491 devfs_unlinkp(node);
492 devfs_gc_dirs(root_node);
493
494 devfs_freep(node);
495
496 return 0;
497}
498
499/*
500 * devfs_gc_dirs() is a helper function for devfs_gc, unlinking and freeing
501 * empty directories.
502 */
503static int
504devfs_gc_dirs(struct devfs_node *node)
505{
506 struct devfs_node *node1, *node2;
507
21864bc5 508 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
ca8d7677
MD
509 devfs_debug(DEVFS_DEBUG_DEBUG,
510 "This node is Pdir or Proot; has %d children\n",
511 node->nchildren);
21864bc5 512 if (node->nchildren > 2) {
ca8d7677
MD
513 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node),
514 link, node2) {
21864bc5
MD
515 devfs_gc_dirs(node1);
516 }
517 }
518
519 if (node->nchildren == 2) {
ca8d7677
MD
520 devfs_debug(DEVFS_DEBUG_DEBUG,
521 "This node is called %s and it is empty\n",
522 node->d_dir.d_name);
21864bc5
MD
523 devfs_unlinkp(node);
524 devfs_freep(node);
525 }
526 }
527
528 return 0;
529}
530
531/*
532 * devfs_gc_links() is a helper function for devfs_gc, unlinking and freeing
533 * eauto-linked nodes linking to the node being deleted.
534 */
535static int
ca8d7677
MD
536devfs_gc_links(struct devfs_node *node, struct devfs_node *target,
537 size_t nlinks)
21864bc5
MD
538{
539 struct devfs_node *node1, *node2;
540
541 if (nlinks > 0) {
542 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
543 devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren);
544 if (node->nchildren > 2) {
545 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
546 nlinks = devfs_gc_links(node1, target, nlinks);
547 }
548 }
549 } else if (node->link_target == target) {
550 nlinks--;
551 devfs_unlinkp(node);
552 devfs_freep(node);
553 }
554 }
555
556 KKASSERT(nlinks >= 0);
557
558 return nlinks;
559}
560
561/*
ca8d7677
MD
562 * devfs_create_dev() is the asynchronous entry point for device creation.
563 * It just sends a message with the relevant details to the devfs core.
564 *
565 * This function will reference the passed device. The reference is owned
566 * by devfs and represents all of the device's node associations.
21864bc5
MD
567 */
568int
569devfs_create_dev(cdev_t dev, uid_t uid, gid_t gid, int perms)
570{
571 __uint64_t id;
ca8d7677
MD
572 devfs_debug(DEVFS_DEBUG_DEBUG,
573 "devfs_create_dev -1-, name: %s (%p)\n",
574 dev->si_name, dev);
575 reference_dev(dev);
21864bc5 576 id = devfs_msg_send_dev(DEVFS_DEVICE_CREATE, dev, uid, gid, perms);
ca8d7677
MD
577 devfs_debug(DEVFS_DEBUG_DEBUG,
578 "devfs_create_dev -end:2- (unique id: %x) / (%p)\n",
579 id, dev);
21864bc5
MD
580 return 0;
581}
582
583/*
ca8d7677
MD
584 * devfs_destroy_dev() is the asynchronous entry point for device destruction.
585 * It just sends a message with the relevant details to the devfs core.
21864bc5
MD
586 */
587int
588devfs_destroy_dev(cdev_t dev)
589{
590 devfs_msg_send_dev(DEVFS_DEVICE_DESTROY, dev, 0, 0, 0);
591 return 0;
592}
593
594/*
ca8d7677
MD
595 * devfs_mount_add() is the synchronous entry point for adding a new devfs
596 * mount. It sends a synchronous message with the relevant details to the
597 * devfs core.
21864bc5
MD
598 */
599int
600devfs_mount_add(struct devfs_mnt_data *mnt)
601{
602 devfs_msg_t msg;
603
604 msg = devfs_msg_get();
ca8d7677 605 msg->mdv_mnt = mnt;
21864bc5
MD
606 msg = devfs_msg_send_sync(DEVFS_MOUNT_ADD, msg);
607 devfs_msg_put(msg);
608
609 return 0;
610}
611
612/*
613 * devfs_mount_del() is the synchronous entry point for removing a devfs mount.
614 * It sends a synchronous message with the relevant details to the devfs core.
615 */
616int
617devfs_mount_del(struct devfs_mnt_data *mnt)
618{
619 devfs_msg_t msg;
620
621 msg = devfs_msg_get();
ca8d7677 622 msg->mdv_mnt = mnt;
21864bc5
MD
623 msg = devfs_msg_send_sync(DEVFS_MOUNT_DEL, msg);
624 devfs_msg_put(msg);
625
626 return 0;
627}
628
629/*
ca8d7677 630 * devfs_destroy_subnames() is the synchronous entry point for device destruction
21864bc5
MD
631 * by subname. It just sends a message with the relevant details to the devfs core.
632 */
633int
634devfs_destroy_subnames(char *name)
635{
ca8d7677
MD
636 devfs_msg_t msg;
637
638 msg = devfs_msg_get();
639 msg->mdv_load = name;
640 msg = devfs_msg_send_sync(DEVFS_DESTROY_SUBNAMES, msg);
641 devfs_msg_put(msg);
642 return 0;
643}
644
645int
646devfs_clr_subnames_flag(char *name, uint32_t flag)
647{
648 devfs_msg_t msg;
649
650 msg = devfs_msg_get();
651 msg->mdv_flags.name = name;
652 msg->mdv_flags.flag = flag;
653 msg = devfs_msg_send_sync(DEVFS_CLR_SUBNAMES_FLAG, msg);
654 devfs_msg_put(msg);
655
656 return 0;
657}
658
659int
660devfs_destroy_subnames_without_flag(char *name, uint32_t flag)
661{
662 devfs_msg_t msg;
663
664 msg = devfs_msg_get();
665 msg->mdv_flags.name = name;
666 msg->mdv_flags.flag = flag;
667 msg = devfs_msg_send_sync(DEVFS_DESTROY_SUBNAMES_WO_FLAG, msg);
668 devfs_msg_put(msg);
669
21864bc5
MD
670 return 0;
671}
672
673/*
ca8d7677
MD
674 * devfs_create_all_dev is the asynchronous entry point to trigger device
675 * node creation. It just sends a message with the relevant details to
676 * the devfs core.
21864bc5
MD
677 */
678int
679devfs_create_all_dev(struct devfs_node *root)
680{
681 devfs_msg_send_generic(DEVFS_CREATE_ALL_DEV, root);
682 return 0;
683}
684
685/*
ca8d7677
MD
686 * devfs_destroy_dev_by_ops is the asynchronous entry point to destroy all
687 * devices with a specific set of dev_ops and minor. It just sends a
688 * message with the relevant details to the devfs core.
21864bc5
MD
689 */
690int
691devfs_destroy_dev_by_ops(struct dev_ops *ops, int minor)
692{
693 devfs_msg_send_ops(DEVFS_DESTROY_DEV_BY_OPS, ops, minor);
694 return 0;
695}
696
697/*
ca8d7677
MD
698 * devfs_clone_handler_add is the synchronous entry point to add a new
699 * clone handler. It just sends a message with the relevant details to
700 * the devfs core.
21864bc5
MD
701 */
702int
703devfs_clone_handler_add(char *name, d_clone_t *nhandler)
704{
ca8d7677
MD
705 devfs_msg_t msg;
706
707 msg = devfs_msg_get();
708 msg->mdv_chandler.name = name;
709 msg->mdv_chandler.nhandler = nhandler;
710 msg = devfs_msg_send_sync(DEVFS_CHANDLER_ADD, msg);
711 devfs_msg_put(msg);
21864bc5
MD
712 return 0;
713}
714
715/*
ca8d7677
MD
716 * devfs_clone_handler_del is the synchronous entry point to remove a
717 * clone handler. It just sends a message with the relevant details to
718 * the devfs core.
21864bc5
MD
719 */
720int
721devfs_clone_handler_del(char *name)
722{
ca8d7677
MD
723 devfs_msg_t msg;
724
725 msg = devfs_msg_get();
726 msg->mdv_chandler.name = name;
727 msg->mdv_chandler.nhandler = NULL;
728 msg = devfs_msg_send_sync(DEVFS_CHANDLER_DEL, msg);
729 devfs_msg_put(msg);
21864bc5
MD
730 return 0;
731}
732
733/*
ca8d7677
MD
734 * devfs_find_device_by_name is the synchronous entry point to find a
735 * device given its name. It sends a synchronous message with the
736 * relevant details to the devfs core and returns the answer.
21864bc5
MD
737 */
738cdev_t
739devfs_find_device_by_name(const char *fmt, ...)
740{
741 cdev_t found = NULL;
742 devfs_msg_t msg;
743 char target[PATH_MAX+1];
744 __va_list ap;
745 int i;
746
747 if (fmt == NULL)
748 return NULL;
749
750
751 __va_start(ap, fmt);
752 i = kvcprintf(fmt, NULL, target, 10, ap);
753 target[i] = '\0';
754 __va_end(ap);
755
756
757 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name: %s -1-\n", target);
758 msg = devfs_msg_get();
ca8d7677 759 msg->mdv_name = target;
21864bc5 760 msg = devfs_msg_send_sync(DEVFS_FIND_DEVICE_BY_NAME, msg);
ca8d7677 761 found = msg->mdv_cdev;
21864bc5
MD
762 devfs_msg_put(msg);
763
764 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name found? %s -end:2-\n", (found)?"YES":"NO");
765 return found;
766}
767
768/*
ca8d7677
MD
769 * devfs_find_device_by_udev is the synchronous entry point to find a
770 * device given its udev number. It sends a synchronous message with
771 * the relevant details to the devfs core and returns the answer.
21864bc5
MD
772 */
773cdev_t
774devfs_find_device_by_udev(udev_t udev)
775{
776 cdev_t found = NULL;
777 devfs_msg_t msg;
778
779 msg = devfs_msg_get();
ca8d7677 780 msg->mdv_udev = udev;
21864bc5 781 msg = devfs_msg_send_sync(DEVFS_FIND_DEVICE_BY_UDEV, msg);
ca8d7677 782 found = msg->mdv_cdev;
21864bc5
MD
783 devfs_msg_put(msg);
784
ca8d7677
MD
785 devfs_debug(DEVFS_DEBUG_DEBUG,
786 "devfs_find_device_by_udev found? %s -end:3-\n",
787 ((found) ? found->si_name:"NO"));
21864bc5
MD
788 return found;
789}
790
791/*
ca8d7677
MD
792 * devfs_make_alias is the asynchronous entry point to register an alias
793 * for a device. It just sends a message with the relevant details to the
794 * devfs core.
21864bc5
MD
795 */
796int
797devfs_make_alias(char *name, cdev_t dev_target)
798{
ca8d7677
MD
799 struct devfs_alias *alias;
800
801 alias = kmalloc(sizeof(struct devfs_alias), M_DEVFS, M_WAITOK);
21864bc5
MD
802 memcpy(alias->name, name, strlen(name) + 1);
803 alias->dev_target = dev_target;
804
805 devfs_msg_send_generic(DEVFS_MAKE_ALIAS, alias);
806 return 0;
807}
808
809/*
ca8d7677
MD
810 * devfs_apply_rules is the asynchronous entry point to trigger application
811 * of all rules. It just sends a message with the relevant details to the
812 * devfs core.
21864bc5
MD
813 */
814int
815devfs_apply_rules(char *mntto)
816{
817 char *new_name;
818 size_t namelen;
819
820 namelen = strlen(mntto) + 1;
821
822 new_name = kmalloc(namelen, M_DEVFS, M_WAITOK);
823
824 memcpy(new_name, mntto, namelen);
825
826 devfs_msg_send_name(DEVFS_APPLY_RULES, new_name);
827 return 0;
828}
829
830/*
831 * devfs_reset_rules is the asynchronous entry point to trigger reset of all rules.
832 * It just sends a message with the relevant details to the devfs core.
833 */
834int
835devfs_reset_rules(char *mntto)
836{
837 char *new_name;
838 size_t namelen;
839
840 namelen = strlen(mntto) + 1;
841
842 new_name = kmalloc(namelen, M_DEVFS, M_WAITOK);
843
844 memcpy(new_name, mntto, namelen);
845
846 devfs_msg_send_name(DEVFS_RESET_RULES, new_name);
847 return 0;
848}
849
850
851/*
852 * devfs_scan_callback is the asynchronous entry point to call a callback
853 * on all cdevs.
854 * It just sends a message with the relevant details to the devfs core.
855 */
856int
857devfs_scan_callback(devfs_scan_t *callback)
858{
859 devfs_msg_t msg;
860
861 /* Make sure that function pointers have the size of a generic pointer (innecessary) */
862 KKASSERT(sizeof(callback) == sizeof(void *));
863
864 msg = devfs_msg_get();
ca8d7677 865 msg->mdv_load = callback;
21864bc5
MD
866 msg = devfs_msg_send_sync(DEVFS_SCAN_CALLBACK, msg);
867 devfs_msg_put(msg);
868
869 return 0;
870}
871
872
873/*
874 * Acts as a message drain. Any message that is replied to here gets destroyed and
875 * the memory freed.
876 */
877static void
878devfs_msg_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
879{
880 devfs_msg_put((devfs_msg_t)msg);
881}
882
883/*
884 * devfs_msg_get allocates a new devfs msg and returns it.
885 */
886devfs_msg_t
887devfs_msg_get()
888{
889 return objcache_get(devfs_msg_cache, M_WAITOK);
890}
891
892/*
893 * devfs_msg_put deallocates a given devfs msg.
894 */
895int
896devfs_msg_put(devfs_msg_t msg)
897{
898 objcache_put(devfs_msg_cache, msg);
899 return 0;
900}
901
902/*
903 * devfs_msg_send is the generic asynchronous message sending facility
904 * for devfs. By default the reply port is the automatic disposal port.
905 */
906__uint32_t
907devfs_msg_send(uint32_t cmd, devfs_msg_t devfs_msg)
908{
909 lwkt_port_t port = &devfs_msg_port;
910
911 lwkt_initmsg(&devfs_msg->hdr, &devfs_dispose_port, 0);
912
913 devfs_msg->hdr.u.ms_result = cmd;
914 devfs_msg->id = atomic_fetchadd_int(&msg_id, 1);
915
916 lwkt_sendmsg(port, (lwkt_msg_t)devfs_msg);
917
918 return devfs_msg->id;
919}
920
921/*
922 * devfs_msg_send_sync is the generic synchronous message sending
923 * facility for devfs. It initializes a local reply port and waits
924 * for the core's answer. This answer is then returned.
925 */
926devfs_msg_t
927devfs_msg_send_sync(uint32_t cmd, devfs_msg_t devfs_msg)
928{
929 struct lwkt_port rep_port;
930 devfs_msg_t msg_incoming;
931 lwkt_port_t port = &devfs_msg_port;
932
933 lwkt_initport_thread(&rep_port, curthread);
934 lwkt_initmsg(&devfs_msg->hdr, &rep_port, 0);
935
936 devfs_msg->hdr.u.ms_result = cmd;
937 devfs_msg->id = atomic_fetchadd_int(&msg_id, 1);
938
939 lwkt_sendmsg(port, (lwkt_msg_t)devfs_msg);
940 msg_incoming = lwkt_waitport(&rep_port, 0);
941
942 return msg_incoming;
943}
944
945/*
946 * sends a message with a generic argument.
947 */
948__uint32_t
949devfs_msg_send_generic(uint32_t cmd, void *load)
950{
951 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677 952 devfs_msg->mdv_load = load;
21864bc5
MD
953
954 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_generic -1- (%p)\n", load);
955
956 return devfs_msg_send(cmd, devfs_msg);
957}
958
959/*
960 * sends a message with a name argument.
961 */
962__uint32_t
963devfs_msg_send_name(uint32_t cmd, char *name)
964{
965 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677 966 devfs_msg->mdv_name = name;
21864bc5
MD
967
968 return devfs_msg_send(cmd, devfs_msg);
969}
970
971/*
972 * sends a message with a mount argument.
973 */
974__uint32_t
975devfs_msg_send_mount(uint32_t cmd, struct devfs_mnt_data *mnt)
976{
977 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677 978 devfs_msg->mdv_mnt = mnt;
21864bc5
MD
979
980 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_mp -1- (%p)\n", mnt);
981
982 return devfs_msg_send(cmd, devfs_msg);
983}
984
985/*
986 * sends a message with an ops argument.
987 */
988__uint32_t
989devfs_msg_send_ops(uint32_t cmd, struct dev_ops *ops, int minor)
990{
991 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677
MD
992 devfs_msg->mdv_ops.ops = ops;
993 devfs_msg->mdv_ops.minor = minor;
21864bc5
MD
994
995 return devfs_msg_send(cmd, devfs_msg);
996}
997
998/*
999 * sends a message with a clone handler argument.
1000 */
1001__uint32_t
1002devfs_msg_send_chandler(uint32_t cmd, char *name, d_clone_t handler)
1003{
1004 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677
MD
1005 devfs_msg->mdv_chandler.name = name;
1006 devfs_msg->mdv_chandler.nhandler = handler;
21864bc5
MD
1007
1008 return devfs_msg_send(cmd, devfs_msg);
1009}
1010
1011/*
1012 * sends a message with a device argument.
1013 */
1014__uint32_t
1015devfs_msg_send_dev(uint32_t cmd, cdev_t dev, uid_t uid, gid_t gid, int perms)
1016{
1017 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677
MD
1018 devfs_msg->mdv_dev.dev = dev;
1019 devfs_msg->mdv_dev.uid = uid;
1020 devfs_msg->mdv_dev.gid = gid;
1021 devfs_msg->mdv_dev.perms = perms;
21864bc5
MD
1022
1023 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_dev -1- (%p)\n", dev);
1024
1025 return devfs_msg_send(cmd, devfs_msg);
1026}
1027
1028/*
1029 * sends a message with a link argument.
1030 */
21864bc5
MD
1031__uint32_t
1032devfs_msg_send_link(uint32_t cmd, char *name, char *target, struct mount *mp)
1033{
1034 devfs_msg_t devfs_msg = devfs_msg_get();
ca8d7677
MD
1035 devfs_msg->mdv_link.name = name;
1036 devfs_msg->mdv_link.target = target;
1037 devfs_msg->mdv_link.mp = mp;
21864bc5
MD
1038
1039
1040 return devfs_msg_send(cmd, devfs_msg);
1041}
1042
1043/*
1044 * devfs_msg_core is the main devfs thread. It handles all incoming messages
1045 * and calls the relevant worker functions. By using messages it's assured
1046 * that events occur in the correct order.
1047 */
1048static void
1049devfs_msg_core(void *arg)
1050{
ca8d7677
MD
1051 uint8_t run = 1;
1052 devfs_msg_t msg;
21864bc5
MD
1053 cdev_t dev;
1054 struct devfs_mnt_data *mnt;
1055 struct devfs_node *node;
1056
1057 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -1-\n");
1058 lwkt_initport_thread(&devfs_msg_port, curthread);
1059 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -2-\n");
1060 wakeup(td_core/*devfs_id*/);
1061 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -3-\n");
1062
ca8d7677 1063 while (run) {
21864bc5 1064 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -loop:4-\n");
ca8d7677 1065 msg = (devfs_msg_t)lwkt_waitport(&devfs_msg_port, 0);
21864bc5
MD
1066 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core, new msg: %x (unique id: %x)\n", (unsigned int)msg->hdr.u.ms_result, msg->id);
1067 lockmgr(&devfs_lock, LK_EXCLUSIVE);
ca8d7677
MD
1068 switch (msg->hdr.u.ms_result) {
1069
1070 case DEVFS_DEVICE_CREATE:
1071 dev = msg->mdv_dev.dev;
1072 devfs_debug(DEVFS_DEBUG_DEBUG,
1073 "devfs_msg_core device create msg %s(%p)\n",
1074 dev->si_name, dev);
1075 devfs_create_dev_worker(dev,
1076 msg->mdv_dev.uid,
1077 msg->mdv_dev.gid,
1078 msg->mdv_dev.perms);
21864bc5
MD
1079 break;
1080
1081 case DEVFS_DEVICE_DESTROY:
ca8d7677
MD
1082 devfs_debug(DEVFS_DEBUG_DEBUG,
1083 "devfs_msg_core device destroy msg\n");
1084 dev = msg->mdv_dev.dev;
21864bc5 1085 devfs_destroy_dev_worker(dev);
ca8d7677 1086 break;
21864bc5
MD
1087
1088 case DEVFS_DESTROY_SUBNAMES:
ca8d7677 1089 devfs_destroy_subnames_worker(msg->mdv_load);
21864bc5
MD
1090 break;
1091
1092 case DEVFS_DESTROY_DEV_BY_OPS:
ca8d7677
MD
1093 devfs_destroy_dev_by_ops_worker(msg->mdv_ops.ops,
1094 msg->mdv_ops.minor);
21864bc5
MD
1095 break;
1096
1097 case DEVFS_CREATE_ALL_DEV:
1098 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core device create ALL msg\n");
ca8d7677 1099 node = (struct devfs_node *)msg->mdv_load;
21864bc5
MD
1100 devfs_create_all_dev_worker(node);
1101 break;
1102
1103 case DEVFS_MOUNT_ADD:
ca8d7677 1104 mnt = msg->mdv_mnt;
21864bc5
MD
1105 TAILQ_INSERT_TAIL(&devfs_mnt_list, mnt, link);
1106 devfs_create_all_dev_worker(mnt->root_node);
1107 break;
1108
1109 case DEVFS_MOUNT_DEL:
ca8d7677 1110 mnt = msg->mdv_mnt;
21864bc5 1111 TAILQ_REMOVE(&devfs_mnt_list, mnt, link);
21864bc5 1112 devfs_reaperp(mnt->root_node);
0709f681
MD
1113 if (mnt->leak_count) {
1114 devfs_debug(DEVFS_DEBUG_SHOW,
1115 "Leaked %d devfs_node elements!\n",
1116 mnt->leak_count);
1117 }
21864bc5
MD
1118 break;
1119
1120 case DEVFS_CHANDLER_ADD:
ca8d7677 1121 devfs_chandler_add_worker(msg->mdv_chandler.name, msg->mdv_chandler.nhandler);
21864bc5
MD
1122 break;
1123
1124 case DEVFS_CHANDLER_DEL:
ca8d7677 1125 devfs_chandler_del_worker(msg->mdv_chandler.name);
21864bc5
MD
1126 break;
1127
1128 case DEVFS_FIND_DEVICE_BY_NAME:
1129 devfs_find_device_by_name_worker(msg);
1130 break;
1131
1132 case DEVFS_FIND_DEVICE_BY_UDEV:
1133 devfs_find_device_by_udev_worker(msg);
1134 break;
1135
1136 case DEVFS_MAKE_ALIAS:
ca8d7677 1137 devfs_make_alias_worker((struct devfs_alias *)msg->mdv_load);
21864bc5
MD
1138 break;
1139
1140 case DEVFS_APPLY_RULES:
ca8d7677 1141 devfs_apply_reset_rules_caller(msg->mdv_name, 1);
21864bc5
MD
1142 break;
1143
1144 case DEVFS_RESET_RULES:
ca8d7677 1145 devfs_apply_reset_rules_caller(msg->mdv_name, 0);
21864bc5
MD
1146 break;
1147
1148 case DEVFS_SCAN_CALLBACK:
ca8d7677 1149 devfs_scan_callback_worker((devfs_scan_t *)msg->mdv_load);
21864bc5
MD
1150 break;
1151
ca8d7677
MD
1152 case DEVFS_CLR_SUBNAMES_FLAG:
1153 devfs_clr_subnames_flag_worker(msg->mdv_flags.name,
1154 msg->mdv_flags.flag);
1155 break;
21864bc5 1156
ca8d7677
MD
1157 case DEVFS_DESTROY_SUBNAMES_WO_FLAG:
1158 devfs_destroy_subnames_without_flag_worker(msg->mdv_flags.name,
1159 msg->mdv_flags.flag);
21864bc5
MD
1160 break;
1161
ca8d7677
MD
1162 case DEVFS_TERMINATE_CORE:
1163 run = 0;
1164 break;
1165 case DEVFS_SYNC:
1166 break;
1167 default:
1168 devfs_debug(DEVFS_DEBUG_DEBUG,
1169 "devfs_msg_core: unknown message "
1170 "received at core\n");
1171 break;
1172 }
21864bc5
MD
1173 lockmgr(&devfs_lock, LK_RELEASE);
1174
ca8d7677
MD
1175 lwkt_replymsg((lwkt_msg_t)msg, 0);
1176 }
21864bc5
MD
1177 wakeup(td_core/*devfs_id*/);
1178 lwkt_exit();
1179}
1180
1181/*
1182 * Worker function to insert a new dev into the dev list and initialize its
1183 * permissions. It also calls devfs_propagate_dev which in turn propagates
1184 * the change to all mount points.
ca8d7677
MD
1185 *
1186 * The passed dev is already referenced. This reference is eaten by this
1187 * function and represents the dev's linkage into devfs_dev_list.
21864bc5
MD
1188 */
1189static int
1190devfs_create_dev_worker(cdev_t dev, uid_t uid, gid_t gid, int perms)
1191{
1192 KKASSERT(dev);
ca8d7677
MD
1193 devfs_debug(DEVFS_DEBUG_DEBUG,
1194 "devfs_create_dev_worker -1- -%s- (%p)\n",
1195 dev->si_name, dev);
21864bc5
MD
1196
1197 dev->si_uid = uid;
1198 dev->si_gid = gid;
1199 dev->si_perms = perms;
1200
1201 devfs_link_dev(dev);
21864bc5
MD
1202 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev_worker -2-\n");
1203 devfs_propagate_dev(dev, 1);
1204
1205 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev_worker -end:3-\n");
1206 return 0;
1207}
1208
1209/*
1210 * Worker function to delete a dev from the dev list and free the cdev.
1211 * It also calls devfs_propagate_dev which in turn propagates the change
1212 * to all mount points.
1213 */
1214static int
1215devfs_destroy_dev_worker(cdev_t dev)
1216{
ca8d7677
MD
1217 int error;
1218
21864bc5
MD
1219 KKASSERT(dev);
1220 KKASSERT((lockstatus(&devfs_lock, curthread)) == LK_EXCLUSIVE);
1221
1222 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_worker -1- %s\n", dev->si_name);
ca8d7677 1223 error = devfs_unlink_dev(dev);
21864bc5 1224 devfs_propagate_dev(dev, 0);
ca8d7677
MD
1225 if (error == 0)
1226 release_dev(dev); /* link ref */
21864bc5
MD
1227 release_dev(dev);
1228 release_dev(dev);
21864bc5
MD
1229
1230 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_worker -end:5-\n");
1231 return 0;
1232}
1233
1234/*
1235 * Worker function to destroy all devices with a certain basename.
1236 * Calls devfs_destroy_dev_worker for the actual destruction.
1237 */
1238static int
1239devfs_destroy_subnames_worker(char *name)
1240{
1241 cdev_t dev, dev1;
21864bc5
MD
1242 size_t len = strlen(name);
1243
ca8d7677 1244 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
21864bc5 1245 if (!strncmp(dev->si_name, name, len)) {
ca8d7677 1246 if (dev->si_name[len] != '\0') {
21864bc5 1247 devfs_destroy_dev_worker(dev);
ca8d7677
MD
1248 /* release_dev(dev); */
1249 }
21864bc5 1250 }
ca8d7677
MD
1251 }
1252 return 0;
1253}
1254
1255static int
1256devfs_clr_subnames_flag_worker(char *name, uint32_t flag)
1257{
1258 cdev_t dev, dev1;
1259 size_t len = strlen(name);
1260
1261 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1262 if (!strncmp(dev->si_name, name, len)) {
1263 if (dev->si_name[len] != '\0') {
1264 dev->si_flags &= ~flag;
1265 }
1266 }
1267 }
1268
1269 return 0;
1270}
1271
1272static int
1273devfs_destroy_subnames_without_flag_worker(char *name, uint32_t flag)
1274{
1275 cdev_t dev, dev1;
1276 size_t len = strlen(name);
1277
1278 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1279 if (!strncmp(dev->si_name, name, len)) {
1280 if (dev->si_name[len] != '\0') {
1281 if (!(dev->si_flags & flag)) {
1282 devfs_destroy_dev_worker(dev);
1283 }
1284 }
1285 }
1286 }
21864bc5
MD
1287
1288 return 0;
1289}
1290
1291/*
1292 * Worker function that creates all device nodes on top of a devfs
1293 * root node.
1294 */
1295static int
1296devfs_create_all_dev_worker(struct devfs_node *root)
1297{
1298 cdev_t dev;
1299
1300 KKASSERT(root);
1301 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_all_dev_worker -1-\n");
1302
1303 TAILQ_FOREACH(dev, &devfs_dev_list, link) {
1304 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_all_dev_worker -loop:2- -%s-\n", dev->si_name);
1305 devfs_create_device_node(root, dev, NULL, NULL);
1306 }
1307 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_all_dev_worker -end:3-\n");
1308 return 0;
1309}
1310
1311/*
1312 * Worker function that destroys all devices that match a specific
1313 * dev_ops and/or minor. If minor is less than 0, it is not matched
1314 * against. It also propagates all changes.
1315 */
1316static int
1317devfs_destroy_dev_by_ops_worker(struct dev_ops *ops, int minor)
1318{
1319 cdev_t dev, dev1;
1320
1321 KKASSERT(ops);
ca8d7677
MD
1322 devfs_debug(DEVFS_DEBUG_DEBUG,
1323 "devfs_destroy_dev_by_ops_worker -1-\n");
1324
1325 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1326 if (dev->si_ops != ops)
1327 continue;
1328 if ((minor < 0) || (dev->si_uminor == minor)) {
1329 devfs_debug(DEVFS_DEBUG_DEBUG,
1330 "devfs_destroy_dev_by_ops_worker "
1331 "-loop:2- -%s-\n",
1332 dev->si_name);
1333 devfs_destroy_dev_worker(dev);
21864bc5 1334 }
ca8d7677
MD
1335 }
1336 devfs_debug(DEVFS_DEBUG_DEBUG,
1337 "devfs_destroy_dev_by_ops_worker -end:3-\n");
21864bc5
MD
1338 return 0;
1339}
1340
1341/*
1342 * Worker function that registers a new clone handler in devfs.
1343 */
1344static int
1345devfs_chandler_add_worker(char *name, d_clone_t *nhandler)
1346{
1347 struct devfs_clone_handler *chandler = NULL;
1348 u_char len = strlen(name);
1349
ca8d7677 1350 if (len == 0)
21864bc5
MD
1351 return 1;
1352
ca8d7677 1353 TAILQ_FOREACH(chandler, &devfs_chandler_list, link) {
21864bc5
MD
1354 if (chandler->namlen == len) {
1355 if (!memcmp(chandler->name, name, len)) {
1356 /* Clonable basename already exists */
1357 return 1;
1358 }
1359 }
1360 }
1361
ca8d7677 1362 chandler = kmalloc(sizeof(*chandler), M_DEVFS, M_WAITOK | M_ZERO);
21864bc5
MD
1363 memcpy(chandler->name, name, len+1);
1364 chandler->namlen = len;
1365 chandler->nhandler = nhandler;
1366
1367 TAILQ_INSERT_TAIL(&devfs_chandler_list, chandler, link);
1368 return 0;
1369}
1370
1371/*
1372 * Worker function that removes a given clone handler from the
1373 * clone handler list.
1374 */
1375static int
1376devfs_chandler_del_worker(char *name)
1377{
1378 struct devfs_clone_handler *chandler, *chandler2;
1379 u_char len = strlen(name);
1380
ca8d7677 1381 if (len == 0)
21864bc5
MD
1382 return 1;
1383
ca8d7677
MD
1384 TAILQ_FOREACH_MUTABLE(chandler, &devfs_chandler_list, link, chandler2) {
1385 if (chandler->namlen != len)
1386 continue;
1387 if (memcmp(chandler->name, name, len))
1388 continue;
1389 TAILQ_REMOVE(&devfs_chandler_list, chandler, link);
1390 kfree(chandler, M_DEVFS);
21864bc5
MD
1391 }
1392
1393 return 0;
1394}
1395
1396/*
1397 * Worker function that finds a given device name and changes
1398 * the message received accordingly so that when replied to,
1399 * the answer is returned to the caller.
1400 */
1401static int
1402devfs_find_device_by_name_worker(devfs_msg_t devfs_msg)
1403{
1404 cdev_t dev, dev1;
1405 cdev_t found = NULL;
21864bc5 1406
ca8d7677
MD
1407 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1408 if (!strcmp(devfs_msg->mdv_name, dev->si_name)) {
21864bc5
MD
1409 found = dev;
1410 break;
1411 }
ca8d7677
MD
1412 }
1413 devfs_msg->mdv_cdev = found;
21864bc5
MD
1414
1415 return 0;
1416}
1417
1418/*
1419 * Worker function that finds a given device udev and changes
1420 * the message received accordingly so that when replied to,
1421 * the answer is returned to the caller.
1422 */
1423static int
1424devfs_find_device_by_udev_worker(devfs_msg_t devfs_msg)
1425{
1426 cdev_t dev, dev1;
1427 cdev_t found = NULL;
21864bc5 1428
ca8d7677
MD
1429 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1430 if (((udev_t)dev->si_inode) == devfs_msg->mdv_udev) {
21864bc5
MD
1431 found = dev;
1432 break;
1433 }
ca8d7677
MD
1434 }
1435 devfs_msg->mdv_cdev = found;
21864bc5
MD
1436
1437 return 0;
1438}
1439
1440/*
1441 * Worker function that inserts a given alias into the
1442 * alias list, and propagates the alias to all mount
1443 * points.
1444 */
1445static int
1446devfs_make_alias_worker(struct devfs_alias *alias)
1447{
1448 struct devfs_alias *alias2;
1449 size_t len = strlen(alias->name);
1450 int found = 0;
1451
1452 TAILQ_FOREACH(alias2, &devfs_alias_list, link) {
1453 if (!memcmp(alias->name, alias2->name, len)) {
1454 found = 1;
1455 break;
1456 }
1457 }
1458
1459 if (!found) {
1460 TAILQ_INSERT_TAIL(&devfs_alias_list, alias, link);
1461 devfs_alias_propagate(alias);
1462 } else {
ca8d7677
MD
1463 devfs_debug(DEVFS_DEBUG_DEBUG,
1464 "Warning: duplicate devfs_make_alias for %s\n",
1465 alias->name);
21864bc5
MD
1466 kfree(alias, M_DEVFS);
1467 }
1468
1469 return 0;
1470}
1471
1472/*
1473 * Function that removes and frees all aliases.
1474 */
1475static int
1476devfs_alias_reap(void)
1477{
1478 struct devfs_alias *alias, *alias2;
1479
1480 TAILQ_FOREACH_MUTABLE(alias, &devfs_alias_list, link, alias2) {
1481 TAILQ_REMOVE(&devfs_alias_list, alias, link);
1482 kfree(alias, M_DEVFS);
1483 }
1484 return 0;
1485}
1486
1487/*
1488 * Function that removes an alias matching a specific cdev and frees
1489 * it accordingly.
1490 */
1491static int
1492devfs_alias_remove(cdev_t dev)
1493{
1494 struct devfs_alias *alias, *alias2;
1495
1496 TAILQ_FOREACH_MUTABLE(alias, &devfs_alias_list, link, alias2) {
1497 if (alias->dev_target == dev) {
1498 TAILQ_REMOVE(&devfs_alias_list, alias, link);
1499 kfree(alias, M_DEVFS);
1500 }
1501 }
1502 return 0;
1503}
1504
1505/*
1506 * This function propagates a new alias to all mount points.
1507 */
1508static int
1509devfs_alias_propagate(struct devfs_alias *alias)
1510{
1511 struct devfs_mnt_data *mnt;
1512
1513 TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
1514 devfs_alias_apply(mnt->root_node, alias);
1515 }
1516 return 0;
1517}
1518
1519/*
1520 * This function is a recursive function iterating through
1521 * all device nodes in the topology and, if applicable,
1522 * creating the relevant alias for a device node.
1523 */
1524static int
1525devfs_alias_apply(struct devfs_node *node, struct devfs_alias *alias)
1526{
1527 struct devfs_node *node1, *node2;
1528
1529 KKASSERT(alias != NULL);
1530
1531 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
1532 devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren);
1533 if (node->nchildren > 2) {
ca8d7677 1534 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
21864bc5
MD
1535 devfs_alias_apply(node1, alias);
1536 }
1537 }
1538 } else {
1539 if (node->d_dev == alias->dev_target)
1540 devfs_alias_create(alias->name, node);
1541 }
1542 return 0;
1543}
1544
1545/*
1546 * This function checks if any alias possibly is applicable
1547 * to the given node. If so, the alias is created.
1548 */
1549static int
1550devfs_alias_check_create(struct devfs_node *node)
1551{
1552 struct devfs_alias *alias;
1553
1554 TAILQ_FOREACH(alias, &devfs_alias_list, link) {
1555 if (node->d_dev == alias->dev_target)
1556 devfs_alias_create(alias->name, node);
1557 }
1558 return 0;
1559}
1560
1561/*
1562 * This function creates an alias with a given name
1563 * linking to a given devfs node. It also increments
1564 * the link count on the target node.
1565 */
1566int
1567devfs_alias_create(char *name_orig, struct devfs_node *target)
1568{
1569 struct mount *mp = target->mp;
1570 struct devfs_node *parent = DEVFS_MNTDATA(mp)->root_node;
1571 struct devfs_node *linknode;
21864bc5
MD
1572 char *create_path = NULL;
1573 char *name, name_buf[PATH_MAX];
1574
21864bc5
MD
1575 KKASSERT((lockstatus(&devfs_lock, curthread)) == LK_EXCLUSIVE);
1576
1577 devfs_resolve_name_path(name_orig, name_buf, &create_path, &name);
1578
1579 if (create_path)
1580 parent = devfs_resolve_or_create_path(parent, create_path, 1);
1581
1582
1583 if (devfs_find_device_node_by_name(parent, name)) {
ca8d7677
MD
1584 devfs_debug(DEVFS_DEBUG_DEBUG,
1585 "Node already exists: %s "
1586 "(devfs_make_alias_worker)!\n",
1587 name);
21864bc5
MD
1588 return 1;
1589 }
1590
1591
1592 linknode = devfs_allocp(Plink, name, parent, mp, NULL);
1593 if (linknode == NULL)
1594 return 1;
1595
1596 linknode->link_target = target;
1597 target->nlinks++;
894bbb25
AH
1598#if 0
1599 linknode->flags |= DEVFS_LINK;
1600#endif
21864bc5
MD
1601
1602 return 0;
1603}
1604
1605/*
1606 * This function is called by the core and handles mount point
1607 * strings. It either calls the relevant worker (devfs_apply_
1608 * reset_rules_worker) on all mountpoints or only a specific
1609 * one.
1610 */
1611static int
1612devfs_apply_reset_rules_caller(char *mountto, int apply)
1613{
21864bc5
MD
1614 struct devfs_mnt_data *mnt;
1615 size_t len = strlen(mountto);
1616
1617 if (mountto[0] != '*') {
1618 TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
1619 if ((len == mnt->mntonnamelen) &&
1620 (!memcmp(mnt->mp->mnt_stat.f_mntonname, mountto, len))) {
1621 devfs_apply_reset_rules_worker(mnt->root_node, apply);
1622 break;
1623 }
1624 }
1625 } else {
1626 TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
1627 devfs_apply_reset_rules_worker(mnt->root_node, apply);
1628 }
1629 }
1630
1631 kfree(mountto, M_DEVFS);
1632 return 0;
1633}
1634
1635/*
1636 * This worker function applies or resets, depending on the arguments, a rule
1637 * to the whole given topology. *RECURSIVE*
1638 */
1639static int
1640devfs_apply_reset_rules_worker(struct devfs_node *node, int apply)
1641{
1642 struct devfs_node *node1, *node2;
1643
1644 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
1645 devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren);
1646 if (node->nchildren > 2) {
1647 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
1648 devfs_apply_reset_rules_worker(node1, apply);
1649 }
1650 }
1651 }
1652
1653 if (apply)
1654 devfs_rule_check_apply(node);
1655 else
1656 devfs_rule_reset_node(node);
1657
1658 return 0;
1659}
1660
1661
1662/*
1663 * This function calls a given callback function for
1664 * every dev node in the devfs dev list.
1665 */
1666static int
1667devfs_scan_callback_worker(devfs_scan_t *callback)
1668{
1669 cdev_t dev, dev1;
1670
1671 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_scan_callback: %p -1-\n", callback);
1672
1673 TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) {
1674 callback(dev);
1675 }
1676
1677 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_scan_callback: finished\n");
1678 return 0;
1679}
1680
1681
1682/*
1683 * This function tries to resolve a given directory, or if not
1684 * found and creation requested, creates the given directory.
1685 */
1686static struct devfs_node *
ca8d7677
MD
1687devfs_resolve_or_create_dir(struct devfs_node *parent, char *dir_name,
1688 size_t name_len, int create)
21864bc5
MD
1689{
1690 struct devfs_node *node, *found = NULL;
1691
1692 TAILQ_FOREACH(node, DEVFS_DENODE_HEAD(parent), link) {
1693 if (name_len == node->d_dir.d_namlen) {
1694 if (!memcmp(dir_name, node->d_dir.d_name, name_len)) {
1695 found = node;
1696 break;
1697 }
1698 }
1699 }
1700
1701 if ((found == NULL) && (create)) {
1702 found = devfs_allocp(Pdir, dir_name, parent, parent->mp, NULL);
1703 }
1704
1705 return found;
1706}
1707
1708/*
1709 * This function tries to resolve a complete path. If creation is requested,
1710 * if a given part of the path cannot be resolved (because it doesn't exist),
1711 * it is created.
1712 */
1713struct devfs_node *
1714devfs_resolve_or_create_path(struct devfs_node *parent, char *path, int create)
1715{
1716 struct devfs_node *node = parent;
1717 char buf[PATH_MAX];
1718 size_t idx = 0;
1719
1720
1721 if (path == NULL)
1722 return parent;
1723
1724
1725 for (; *path != '\0' ; path++) {
1726 if (*path != '/') {
1727 buf[idx++] = *path;
1728 } else {
1729 buf[idx] = '\0';
1730 node = devfs_resolve_or_create_dir(node, buf, idx, create);
1731 if (node == NULL)
1732 return NULL;
1733 idx = 0;
1734 }
1735 }
1736 buf[idx] = '\0';
1737 return devfs_resolve_or_create_dir(node, buf, idx, create);
1738}
1739
1740/*
1741 * Takes a full path and strips it into a directory path and a name.
1742 * For a/b/c/foo, it returns foo in namep and a/b/c in pathp. It
1743 * requires a working buffer with enough size to keep the whole
1744 * fullpath.
1745 */
1746int
1747devfs_resolve_name_path(char *fullpath, char *buf, char **pathp, char **namep)
1748{
1749 char *name = NULL;
1750 char *path = NULL;
1751 size_t len = strlen(fullpath) + 1;
1752 int i;
1753
1754 KKASSERT((fullpath != NULL) && (buf != NULL) && (pathp != NULL) && (namep != NULL));
1755
1756 memcpy(buf, fullpath, len);
1757
1758 for (i = len-1; i>= 0; i--) {
1759 if (buf[i] == '/') {
1760 buf[i] = '\0';
1761 name = &(buf[i+1]);
1762 path = buf;
1763 break;
1764 }
1765 }
1766
1767 *pathp = path;
1768
1769 if (name) {
1770 *namep = name;
1771 } else {
1772 *namep = buf;
1773 }
1774
1775 return 0;
1776}
1777
1778/*
ca8d7677 1779 * This function creates a new devfs node for a given device. It can
21864bc5
MD
1780 * handle a complete path as device name, and accordingly creates
1781 * the path and the final device node.
ca8d7677
MD
1782 *
1783 * The reference count on the passed dev remains unchanged.
21864bc5
MD
1784 */
1785struct devfs_node *
ca8d7677
MD
1786devfs_create_device_node(struct devfs_node *root, cdev_t dev,
1787 char *dev_name, char *path_fmt, ...)
21864bc5
MD
1788{
1789 struct devfs_node *parent, *node = NULL;
1790 char *path = NULL;
1791 char *name, name_buf[PATH_MAX];
1792 __va_list ap;
1793 int i, found;
1794
1795 char *create_path = NULL;
1796 char *names = "pqrsPQRS";
1797
21864bc5
MD
1798 if (path_fmt != NULL) {
1799 path = kmalloc(PATH_MAX+1, M_DEVFS, M_WAITOK);
1800
1801 __va_start(ap, path_fmt);
1802 i = kvcprintf(path_fmt, NULL, path, 10, ap);
1803 path[i] = '\0';
1804 __va_end(ap);
1805 }
1806
1807 parent = devfs_resolve_or_create_path(root, path, 1);
1808 KKASSERT(parent);
1809
21864bc5
MD
1810 devfs_resolve_name_path(((dev_name == NULL) && (dev))?(dev->si_name):(dev_name), name_buf, &create_path, &name);
1811
1812 if (create_path)
1813 parent = devfs_resolve_or_create_path(parent, create_path, 1);
1814
1815
1816 if (devfs_find_device_node_by_name(parent, name)) {
894bbb25
AH
1817 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_device_node: "
1818 "DEVICE %s ALREADY EXISTS!!! Ignoring creation request.\n", name);
21864bc5
MD
1819 goto out;
1820 }
1821 devfs_debug(DEVFS_DEBUG_DEBUG, "parent->d_dir.d_name=%s\n", parent->d_dir.d_name);
1822 node = devfs_allocp(Pdev, name, parent, parent->mp, dev);
1823 devfs_debug(DEVFS_DEBUG_DEBUG, "node->d_dir.d_name=%s\n", node->d_dir.d_name);
1824
894bbb25 1825#if 0
21864bc5
MD
1826 /* Ugly unix98 pty magic, to hide pty master (ptm) devices and their directory */
1827 if ((dev) && (strlen(dev->si_name) >= 4) && (!memcmp(dev->si_name, "ptm/", 4))) {
894bbb25
AH
1828 node->parent->flags |= DEVFS_HIDDEN;
1829 node->flags |= DEVFS_HIDDEN;
21864bc5 1830 }
894bbb25 1831#endif
21864bc5
MD
1832 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_device_node: marker A\n");
1833 /* Ugly pty magic, to tag pty devices as such and hide them if needed */
1834 if ((strlen(name) >= 3) && (!memcmp(name, "pty", 3)))
1835 node->flags |= (DEVFS_PTY | DEVFS_INVISIBLE);
1836
1837 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_device_node: marker B\n");
1838 if ((strlen(name) >= 3) && (!memcmp(name, "tty", 3))) {
1839 found = 0;
1840 for (i = 0; i < strlen(names); i++) {
1841 if (name[3] == names[i]) {
1842 found = 1;
1843 break;
1844 }
1845 }
1846 if (found)
1847 node->flags |= (DEVFS_PTY | DEVFS_INVISIBLE);
1848 }
1849 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_device_node: marker C\n");
1850
1851out:
1852 if (path_fmt != NULL)
1853 kfree(path, M_DEVFS);
21864bc5
MD
1854
1855 return node;
1856}
1857
1858/*
1859 * This function finds a given device node in the topology with a given
1860 * cdev.
1861 */
1862struct devfs_node *
1863devfs_find_device_node(struct devfs_node *node, cdev_t target)
1864{
1865 struct devfs_node *node1, *node2, *found = NULL;
1866
1867 if ((node->node_type == Proot) || (node->node_type == Pdir)) {
1868 devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren);
1869 if (node->nchildren > 2) {
1870 TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
1871 if ((found = devfs_find_device_node(node1, target)))
1872 return found;
1873 }
1874 }
1875 } else if (node->node_type == Pdev) {
1876 if (node->d_dev == target)
1877 return node;
1878 }
21864bc5
MD
1879
1880 return NULL;
1881}
1882
1883/*
1884 * This function finds a device node in the topology by its
1885 * name and returns it.
1886 */
1887struct devfs_node *
1888devfs_find_device_node_by_name(struct devfs_node *parent, char *target)
1889{
1890 struct devfs_node *node, *found = NULL;
1891 size_t len = strlen(target);
1892
1893 TAILQ_FOREACH(node, DEVFS_DENODE_HEAD(parent), link) {
1894 if ((len == node->d_dir.d_namlen) && (!memcmp(node->d_dir.d_name, target, len))) {
1895 found = node;
1896 break;
1897 }
1898 }
1899
1900 return found;
1901}
1902
1903/*
ca8d7677
MD
1904 * This function takes a cdev and removes its devfs node in the
1905 * given topology. The cdev remains intact.
21864bc5
MD
1906 */
1907int
1908devfs_destroy_device_node(struct devfs_node *root, cdev_t target)
1909{
1910 struct devfs_node *node, *parent;
21864bc5 1911 char *name, name_buf[PATH_MAX];
21864bc5
MD
1912 char *create_path = NULL;
1913
1914 KKASSERT(target);
1915
21864bc5
MD
1916 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_device_node\n");
1917 memcpy(name_buf, target->si_name, strlen(target->si_name)+1);
1918
1919 devfs_resolve_name_path(target->si_name, name_buf, &create_path, &name);
1920 devfs_debug(DEVFS_DEBUG_DEBUG, "create_path: %s\n", create_path);
1921 devfs_debug(DEVFS_DEBUG_DEBUG, "name: %s\n", name);
1922
1923 if (create_path)
1924 parent = devfs_resolve_or_create_path(root, create_path, 0);
1925 else
1926 parent = root;
1927 devfs_debug(DEVFS_DEBUG_DEBUG, "-> marker <-\n");
1928 if (parent == NULL)
1929 return 1;
1930 devfs_debug(DEVFS_DEBUG_DEBUG, "->d_dir.d_name=%s\n", parent->d_dir.d_name);
1931 node = devfs_find_device_node_by_name(parent, name);
ca8d7677
MD
1932 devfs_debug(DEVFS_DEBUG_DEBUG,
1933 "->d_dir.d_name=%s\n",
1934 ((node) ? (node->d_dir.d_name) : "SHIT!"));
1935 if (node)
21864bc5 1936 devfs_gc(node);
21864bc5
MD
1937
1938 return 0;
1939}
1940
1941/*
1942 * Just set perms and ownership for given node.
1943 */
1944int
1945devfs_set_perms(struct devfs_node *node, uid_t uid, gid_t gid, u_short mode, u_long flags)
1946{
1947 node->mode = mode; /* files access mode and type */
1948 node->uid = uid; /* owner user id */
1949 node->gid = gid; /* owner group id */
21864bc5
MD
1950
1951 return 0;
1952}
1953
1954/*
1955 * Propagates a device attach/detach to all mount
1956 * points. Also takes care of automatic alias removal
1957 * for a deleted cdev.
1958 */
1959static int
1960devfs_propagate_dev(cdev_t dev, int attach)
1961{
1962 struct devfs_mnt_data *mnt;
1963
1964 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_propagate_dev -1-\n");
1965 TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
ca8d7677
MD
1966 devfs_debug(DEVFS_DEBUG_DEBUG,
1967 "devfs_propagate_dev -loop:2-\n");
21864bc5
MD
1968 if (attach) {
1969 /* Device is being attached */
ca8d7677
MD
1970 devfs_create_device_node(mnt->root_node, dev,
1971 NULL, NULL );
21864bc5
MD
1972 } else {
1973 /* Device is being detached */
21864bc5
MD
1974 devfs_alias_remove(dev);
1975 devfs_destroy_device_node(mnt->root_node, dev);
1976 }
1977 }
1978 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_propagate_dev -end:3-\n");
1979 return 0;
1980}
1981
1982/*
1983 * devfs_node_to_path takes a node and a buffer of a size of
1984 * at least PATH_MAX, resolves the full path from the root
1985 * node and writes it in a humanly-readable format into the
1986 * buffer.
1987 * If DEVFS_STASH_DEPTH is less than the directory level up
1988 * to the root node, only the last DEVFS_STASH_DEPTH levels
1989 * of the path are resolved.
1990 */
1991int
1992devfs_node_to_path(struct devfs_node *node, char *buffer)
1993{
1994#define DEVFS_STASH_DEPTH 32
1995 struct devfs_node *node_stash[DEVFS_STASH_DEPTH];
1996 int i, offset;
1997 memset(buffer, 0, PATH_MAX);
1998
1999 for (i = 0; (i < DEVFS_STASH_DEPTH) && (node->node_type != Proot); i++) {
2000 node_stash[i] = node;
2001 node = node->parent;
2002 }
2003 i--;
2004
2005 for (offset = 0; i >= 0; i--) {
2006 memcpy(buffer+offset, node_stash[i]->d_dir.d_name, node_stash[i]->d_dir.d_namlen);
2007 offset += node_stash[i]->d_dir.d_namlen;
2008 if (i > 0) {
2009 *(buffer+offset) = '/';
2010 offset++;
2011 }
2012 }
2013#undef DEVFS_STASH_DEPTH
2014 return 0;
2015}
2016
2017/*
2018 * devfs_clone either returns a basename from a complete name by
2019 * returning the length of the name without trailing digits, or,
2020 * if clone != 0, calls the device's clone handler to get a new
2021 * device, which in turn is returned in devp.
2022 */
2023int
2024devfs_clone(char *name, size_t *namlenp, cdev_t *devp, int clone, struct ucred *cred)
2025{
2026 KKASSERT(namlenp);
2027
2028 size_t len = *namlenp;
2029 int error = 1;
2030 struct devfs_clone_handler *chandler;
2031 struct dev_clone_args ap;
2032
2033 if (!clone) {
2034 for (; (len > 0) && (DEVFS_ISDIGIT(name[len-1])); len--);
2035 }
2036
2037 TAILQ_FOREACH(chandler, &devfs_chandler_list, link) {
2038 devfs_debug(DEVFS_DEBUG_DEBUG, "len=%d, chandler->namlen=%d\n", len, chandler->namlen);
2039 devfs_debug(DEVFS_DEBUG_DEBUG, "name=%s, chandler->name=%s\n", name, chandler->name);
2040 if ((chandler->namlen == len) &&
2041 (!memcmp(chandler->name, name, len)) &&
2042 (chandler->nhandler)) {
2043 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_nclone: found clone handler for the base name at %p\n", chandler->nhandler);
2044 if (clone) {
2045 ap.a_dev = NULL;
2046 ap.a_name = name;
2047 ap.a_namelen = len;
2048 ap.a_cred = cred;
2049 error = (chandler->nhandler)(&ap);
2050 KKASSERT(devp);
2051 *devp = ap.a_dev;
2052 } else {
2053 *namlenp = len;
2054 error = 0;
2055 }
2056
2057 break;
2058 }
2059 }
2060
2061 return error;
2062}
2063
2064
2065/*
2066 * Registers a new orphan in the orphan list.
2067 */
2068void
2069devfs_tracer_add_orphan(struct devfs_node *node)
2070{
2071 struct devfs_orphan *orphan;
2072
2073 KKASSERT(node);
2074 orphan = kmalloc(sizeof(struct devfs_orphan), M_DEVFS, M_WAITOK);
2075 orphan->node = node;
2076
ca8d7677
MD
2077 KKASSERT((node->flags & DEVFS_ORPHANED) == 0);
2078 node->flags |= DEVFS_ORPHANED;
21864bc5
MD
2079 TAILQ_INSERT_TAIL(DEVFS_ORPHANLIST(node->mp), orphan, link);
2080}
2081
2082/*
2083 * Removes an orphan from the orphan list.
2084 */
2085void
2086devfs_tracer_del_orphan(struct devfs_node *node)
2087{
2088 struct devfs_orphan *orphan;
2089
2090 KKASSERT(node);
2091
2092 TAILQ_FOREACH(orphan, DEVFS_ORPHANLIST(node->mp), link) {
2093 if (orphan->node == node) {
ca8d7677 2094 node->flags &= ~DEVFS_ORPHANED;
21864bc5
MD
2095 TAILQ_REMOVE(DEVFS_ORPHANLIST(node->mp), orphan, link);
2096 kfree(orphan, M_DEVFS);
2097 break;
2098 }
2099 }
2100}
2101
2102/*
2103 * Counts the orphans in the orphan list, and if cleanup
2104 * is specified, also frees the orphan and removes it from
2105 * the list.
2106 */
2107size_t
2108devfs_tracer_orphan_count(struct mount *mp, int cleanup)
2109{
2110 struct devfs_orphan *orphan, *orphan2;
2111 size_t count = 0;
2112
2113 TAILQ_FOREACH_MUTABLE(orphan, DEVFS_ORPHANLIST(mp), link, orphan2) {
2114 count++;
2115 if (cleanup) {
21864bc5 2116 TAILQ_REMOVE(DEVFS_ORPHANLIST(mp), orphan, link);
ca8d7677
MD
2117 orphan->node->flags &= ~DEVFS_ORPHANED;
2118 devfs_freep(orphan->node);
21864bc5
MD
2119 kfree(orphan, M_DEVFS);
2120 }
2121 }
2122
2123 return count;
2124}
2125
2126/*
2127 * Fetch an ino_t from the global d_ino by increasing it
2128 * while spinlocked.
2129 */
2130static ino_t
2131devfs_fetch_ino(void)
2132{
2133 ino_t ret;
2134
2135 spin_lock_wr(&ino_lock);
2136 ret = d_ino++;
2137 spin_unlock_wr(&ino_lock);
2138
2139 return ret;
2140}
2141
2142/*
2143 * Allocates a new cdev and initializes it's most basic
2144 * fields.
2145 */
2146cdev_t
2147devfs_new_cdev(struct dev_ops *ops, int minor)
2148{
21864bc5
MD
2149 cdev_t dev = sysref_alloc(&cdev_sysref_class);
2150 sysref_activate(&dev->si_sysref);
2151 reference_dev(dev);
ca8d7677
MD
2152 devfs_debug(DEVFS_DEBUG_DEBUG,
2153 "new_cdev: clearing first %d bytes\n",
2154 offsetof(struct cdev, si_sysref));
21864bc5
MD
2155 memset(dev, 0, offsetof(struct cdev, si_sysref));
2156
2157 dev->si_uid = 0;
2158 dev->si_gid = 0;
2159 dev->si_perms = 0;
2160 dev->si_drv1 = NULL;
2161 dev->si_drv2 = NULL;
2162 dev->si_lastread = 0; /* time_second */
2163 dev->si_lastwrite = 0; /* time_second */
2164
2165 dev->si_ops = ops;
894bbb25 2166 dev->si_flags = 0;
21864bc5
MD
2167 dev->si_umajor = 0;
2168 dev->si_uminor = minor;
7cbab9da 2169 dev->si_inode = makeudev(devfs_reference_ops(ops), minor);
21864bc5
MD
2170
2171 return dev;
2172}
2173
ca8d7677
MD
2174static void
2175devfs_cdev_terminate(cdev_t dev)
21864bc5
MD
2176{
2177 int locked = 0;
2178
2179 /* Check if it is locked already. if not, we acquire the devfs lock */
2180 if (!(lockstatus(&devfs_lock, curthread)) == LK_EXCLUSIVE) {
2181 lockmgr(&devfs_lock, LK_EXCLUSIVE);
2182 locked = 1;
2183 }
2184
2185 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_cdev_terminate: Taking care of dev->si_name=%s\n", dev->si_name);
2186
2187 /* Propagate destruction, just in case */
2188 devfs_propagate_dev(dev, 0);
2189
2190 /* If we acquired the lock, we also get rid of it */
2191 if (locked)
2192 lockmgr(&devfs_lock, LK_RELEASE);
2193
7cbab9da
AH
2194 devfs_release_ops(dev->si_ops);
2195
21864bc5
MD
2196 /* Finally destroy the device */
2197 sysref_put(&dev->si_sysref);
2198}
2199
21864bc5
MD
2200/*
2201 * Links a given cdev into the dev list.
2202 */
2203int
2204devfs_link_dev(cdev_t dev)
2205{
ca8d7677 2206 KKASSERT((dev->si_flags & SI_DEVFS_LINKED) == 0);
21864bc5
MD
2207 dev->si_flags |= SI_DEVFS_LINKED;
2208 TAILQ_INSERT_TAIL(&devfs_dev_list, dev, link);
2209
2210 return 0;
2211}
2212
2213/*
ca8d7677
MD
2214 * Removes a given cdev from the dev list. The caller is responsible for
2215 * releasing the reference on the device associated with the linkage.
2216 *
2217 * Returns EALREADY if the dev has already been unlinked.
21864bc5 2218 */
ca8d7677 2219static int
21864bc5
MD
2220devfs_unlink_dev(cdev_t dev)
2221{
2222 if ((dev->si_flags & SI_DEVFS_LINKED)) {
2223 TAILQ_REMOVE(&devfs_dev_list, dev, link);
2224 dev->si_flags &= ~SI_DEVFS_LINKED;
ca8d7677 2225 return (0);
21864bc5 2226 }
ca8d7677 2227 return (EALREADY);
21864bc5
MD
2228}
2229
894bbb25
AH
2230int
2231devfs_node_is_accessible(struct devfs_node *node)
2232{
2233 if ((node) && (!(node->flags & DEVFS_HIDDEN)))
2234 return 1;
2235 else
2236 return 0;
2237}
2238
7cbab9da
AH
2239int
2240devfs_reference_ops(struct dev_ops *ops)
2241{
2242 int unit;
2243
2244 if (ops->head.refs == 0) {
2245 ops->head.id = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(ops_id), 255);
2246 if (ops->head.id == -1) {
2247 /* Ran out of unique ids */
2248 kprintf("devfs_reference_ops: WARNING: ran out of unique ids\n");
2249 }
2250 }
2251 unit = ops->head.id;
2252 ++ops->head.refs;
2253
2254 return unit;
2255}
2256
2257void
2258devfs_release_ops(struct dev_ops *ops)
2259{
2260 --ops->head.refs;
2261
2262 if (ops->head.refs == 0) {
2263 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(ops_id), ops->head.id);
2264 }
2265}
2266
21864bc5
MD
2267void
2268devfs_config(void *arg)
2269{
2270 devfs_msg_t msg;
2271
2272 msg = devfs_msg_get();
2273
2274 kprintf("devfs_config: sync'ing up\n");
2275 msg = devfs_msg_send_sync(DEVFS_SYNC, msg);
2276 devfs_msg_put(msg);
2277}
2278
2279/*
2280 * Called on init of devfs; creates the objcaches and
2281 * spawns off the devfs core thread. Also initializes
2282 * locks.
2283 */
2284static void
2285devfs_init(void)
2286{
2287 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_init() called\n");
2288 /* Create objcaches for nodes, msgs and devs */
2289 devfs_node_cache = objcache_create("devfs-node-cache", 0, 0,
2290 NULL, NULL, NULL,
2291 objcache_malloc_alloc,
2292 objcache_malloc_free,
2293 &devfs_node_malloc_args );
2294
2295 devfs_msg_cache = objcache_create("devfs-msg-cache", 0, 0,
2296 NULL, NULL, NULL,
2297 objcache_malloc_alloc,
2298 objcache_malloc_free,
2299 &devfs_msg_malloc_args );
2300
2301 devfs_dev_cache = objcache_create("devfs-dev-cache", 0, 0,
2302 NULL, NULL, NULL,
2303 objcache_malloc_alloc,
2304 objcache_malloc_free,
2305 &devfs_dev_malloc_args );
2306
7cbab9da
AH
2307 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(ops_id));
2308#if 0
2309 devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(ops_id), 0);
2310#endif
2311
21864bc5
MD
2312 /* Initialize the reply-only port which acts as a message drain */
2313 lwkt_initport_replyonly(&devfs_dispose_port, devfs_msg_autofree_reply);
2314
2315 /* Initialize *THE* devfs lock */
2316 lockinit(&devfs_lock, "devfs_core lock", 0, 0);
2317
2318
2319 lwkt_create(devfs_msg_core, /*args*/NULL, &td_core, NULL,
2320 0, 0, "devfs_msg_core");
2321
2322 tsleep(td_core/*devfs_id*/, 0, "devfsc", 0);
2323
2324 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_init finished\n");
2325}
2326
2327/*
2328 * Called on unload of devfs; takes care of destroying the core
2329 * and the objcaches. Also removes aliases that are no longer needed.
2330 */
2331static void
2332devfs_uninit(void)
2333{
2334 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_uninit() called\n");
2335
2336 devfs_msg_send(DEVFS_TERMINATE_CORE, NULL);
2337
2338 tsleep(td_core/*devfs_id*/, 0, "devfsc", 0);
2339 tsleep(td_core/*devfs_id*/, 0, "devfsc", 10000);
2340
7cbab9da
AH
2341 devfs_clone_bitmap_uninit(&DEVFS_CLONE_BITMAP(ops_id));
2342
21864bc5
MD
2343 /* Destroy the objcaches */
2344 objcache_destroy(devfs_msg_cache);
2345 objcache_destroy(devfs_node_cache);
2346 objcache_destroy(devfs_dev_cache);
2347
2348 devfs_alias_reap();
2349}
2350
2351/*
2352 * This is a sysctl handler to assist userland devname(3) to
2353 * find the device name for a given udev.
2354 */
2355static int
2356devfs_sysctl_devname_helper(SYSCTL_HANDLER_ARGS)
2357{
2358 udev_t udev;
2359 cdev_t found;
2360 int error;
2361
2362
2363 if ((error = SYSCTL_IN(req, &udev, sizeof(udev_t))))
2364 return (error);
2365
2366 devfs_debug(DEVFS_DEBUG_DEBUG, "devfs sysctl, received udev: %d\n", udev);
2367
2368 if (udev == NOUDEV)
2369 return(EINVAL);
2370
2371 if ((found = devfs_find_device_by_udev(udev)) == NULL)
2372 return(ENOENT);
2373
2374 return(SYSCTL_OUT(req, found->si_name, strlen(found->si_name) + 1));
2375}
2376
2377
2378SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
2379 NULL, 0, devfs_sysctl_devname_helper, "", "helper for devname(3)");
2380
2381static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "devfs");
2382TUNABLE_INT("vfs.devfs.debug", &devfs_debug_enable);
2383SYSCTL_INT(_vfs_devfs, OID_AUTO, debug, CTLFLAG_RW, &devfs_debug_enable, 0, "Enable DevFS debugging");
2384
2385SYSINIT(vfs_devfs_register, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, devfs_init, NULL);
2386SYSUNINIT(vfs_devfs_register, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, devfs_uninit, NULL);