xref: /freebsd/sys/fs/devfs/devfs_dir.c (revision d318c565d74496343ec299b3ace0ae9eb744dba1)
1*d318c565SJaakko Heinonen /*-
2*d318c565SJaakko Heinonen  * Copyright (c) 2010 Jaakko Heinonen <jh@FreeBSD.org>
3*d318c565SJaakko Heinonen  * All rights reserved.
4*d318c565SJaakko Heinonen  *
5*d318c565SJaakko Heinonen  * Redistribution and use in source and binary forms, with or without
6*d318c565SJaakko Heinonen  * modification, are permitted provided that the following conditions
7*d318c565SJaakko Heinonen  * are met:
8*d318c565SJaakko Heinonen  * 1. Redistributions of source code must retain the above copyright
9*d318c565SJaakko Heinonen  *    notice, this list of conditions and the following disclaimer.
10*d318c565SJaakko Heinonen  * 2. Redistributions in binary form must reproduce the above copyright
11*d318c565SJaakko Heinonen  *    notice, this list of conditions and the following disclaimer in the
12*d318c565SJaakko Heinonen  *    documentation and/or other materials provided with the distribution.
13*d318c565SJaakko Heinonen  *
14*d318c565SJaakko Heinonen  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*d318c565SJaakko Heinonen  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*d318c565SJaakko Heinonen  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*d318c565SJaakko Heinonen  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*d318c565SJaakko Heinonen  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*d318c565SJaakko Heinonen  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*d318c565SJaakko Heinonen  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*d318c565SJaakko Heinonen  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*d318c565SJaakko Heinonen  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*d318c565SJaakko Heinonen  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*d318c565SJaakko Heinonen  * SUCH DAMAGE.
25*d318c565SJaakko Heinonen  *
26*d318c565SJaakko Heinonen  * $FreeBSD$
27*d318c565SJaakko Heinonen  */
28*d318c565SJaakko Heinonen 
29*d318c565SJaakko Heinonen #include <sys/param.h>
30*d318c565SJaakko Heinonen #include <sys/conf.h>
31*d318c565SJaakko Heinonen #include <sys/types.h>
32*d318c565SJaakko Heinonen #include <sys/kernel.h>
33*d318c565SJaakko Heinonen #include <sys/libkern.h>
34*d318c565SJaakko Heinonen #include <sys/lock.h>
35*d318c565SJaakko Heinonen #include <sys/malloc.h>
36*d318c565SJaakko Heinonen #include <sys/mutex.h>
37*d318c565SJaakko Heinonen #include <sys/queue.h>
38*d318c565SJaakko Heinonen #include <sys/systm.h>
39*d318c565SJaakko Heinonen #include <sys/sx.h>
40*d318c565SJaakko Heinonen 
41*d318c565SJaakko Heinonen #include <fs/devfs/devfs.h>
42*d318c565SJaakko Heinonen #include <fs/devfs/devfs_int.h>
43*d318c565SJaakko Heinonen 
44*d318c565SJaakko Heinonen struct dirlistent {
45*d318c565SJaakko Heinonen 	char			*dir;
46*d318c565SJaakko Heinonen 	int			refcnt;
47*d318c565SJaakko Heinonen 	LIST_ENTRY(dirlistent)	link;
48*d318c565SJaakko Heinonen };
49*d318c565SJaakko Heinonen 
50*d318c565SJaakko Heinonen static LIST_HEAD(, dirlistent) devfs_dirlist =
51*d318c565SJaakko Heinonen     LIST_HEAD_INITIALIZER(devfs_dirlist);
52*d318c565SJaakko Heinonen 
53*d318c565SJaakko Heinonen static MALLOC_DEFINE(M_DEVFS4, "DEVFS4", "DEVFS directory list");
54*d318c565SJaakko Heinonen 
55*d318c565SJaakko Heinonen static struct mtx dirlist_mtx;
56*d318c565SJaakko Heinonen MTX_SYSINIT(dirlist_mtx, &dirlist_mtx, "devfs dirlist lock", MTX_DEF);
57*d318c565SJaakko Heinonen 
58*d318c565SJaakko Heinonen /* Returns 1 if the path is in the directory list. */
59*d318c565SJaakko Heinonen int
60*d318c565SJaakko Heinonen devfs_dir_find(const char *path)
61*d318c565SJaakko Heinonen {
62*d318c565SJaakko Heinonen 	struct dirlistent *dle;
63*d318c565SJaakko Heinonen 
64*d318c565SJaakko Heinonen 	mtx_lock(&dirlist_mtx);
65*d318c565SJaakko Heinonen 	LIST_FOREACH(dle, &devfs_dirlist, link) {
66*d318c565SJaakko Heinonen 		if (devfs_pathpath(dle->dir, path) != 0) {
67*d318c565SJaakko Heinonen 			mtx_unlock(&dirlist_mtx);
68*d318c565SJaakko Heinonen 			return (1);
69*d318c565SJaakko Heinonen 		}
70*d318c565SJaakko Heinonen 	}
71*d318c565SJaakko Heinonen 	mtx_unlock(&dirlist_mtx);
72*d318c565SJaakko Heinonen 
73*d318c565SJaakko Heinonen 	return (0);
74*d318c565SJaakko Heinonen }
75*d318c565SJaakko Heinonen 
76*d318c565SJaakko Heinonen static struct dirlistent *
77*d318c565SJaakko Heinonen devfs_dir_findent_locked(const char *dir)
78*d318c565SJaakko Heinonen {
79*d318c565SJaakko Heinonen 	struct dirlistent *dle;
80*d318c565SJaakko Heinonen 
81*d318c565SJaakko Heinonen 	mtx_assert(&dirlist_mtx, MA_OWNED);
82*d318c565SJaakko Heinonen 
83*d318c565SJaakko Heinonen 	LIST_FOREACH(dle, &devfs_dirlist, link) {
84*d318c565SJaakko Heinonen 		if (strcmp(dir, dle->dir) == 0)
85*d318c565SJaakko Heinonen 			return (dle);
86*d318c565SJaakko Heinonen 	}
87*d318c565SJaakko Heinonen 
88*d318c565SJaakko Heinonen 	return (NULL);
89*d318c565SJaakko Heinonen }
90*d318c565SJaakko Heinonen 
91*d318c565SJaakko Heinonen static void
92*d318c565SJaakko Heinonen devfs_dir_ref(const char *dir)
93*d318c565SJaakko Heinonen {
94*d318c565SJaakko Heinonen 	struct dirlistent *dle, *dle_new;
95*d318c565SJaakko Heinonen 
96*d318c565SJaakko Heinonen 	if (*dir == '\0')
97*d318c565SJaakko Heinonen 		return;
98*d318c565SJaakko Heinonen 
99*d318c565SJaakko Heinonen 	dle_new = malloc(sizeof(*dle), M_DEVFS4, M_WAITOK);
100*d318c565SJaakko Heinonen 	dle_new->dir = strdup(dir, M_DEVFS4);
101*d318c565SJaakko Heinonen 	dle_new->refcnt = 1;
102*d318c565SJaakko Heinonen 
103*d318c565SJaakko Heinonen 	mtx_lock(&dirlist_mtx);
104*d318c565SJaakko Heinonen 	dle = devfs_dir_findent_locked(dir);
105*d318c565SJaakko Heinonen 	if (dle != NULL) {
106*d318c565SJaakko Heinonen 		dle->refcnt++;
107*d318c565SJaakko Heinonen 		mtx_unlock(&dirlist_mtx);
108*d318c565SJaakko Heinonen 		free(dle_new->dir, M_DEVFS4);
109*d318c565SJaakko Heinonen 		free(dle_new, M_DEVFS4);
110*d318c565SJaakko Heinonen 		return;
111*d318c565SJaakko Heinonen 	}
112*d318c565SJaakko Heinonen 	LIST_INSERT_HEAD(&devfs_dirlist, dle_new, link);
113*d318c565SJaakko Heinonen 	mtx_unlock(&dirlist_mtx);
114*d318c565SJaakko Heinonen }
115*d318c565SJaakko Heinonen 
116*d318c565SJaakko Heinonen void
117*d318c565SJaakko Heinonen devfs_dir_ref_de(struct devfs_mount *dm, struct devfs_dirent *de)
118*d318c565SJaakko Heinonen {
119*d318c565SJaakko Heinonen 	char dirname[SPECNAMELEN + 1], *namep;
120*d318c565SJaakko Heinonen 
121*d318c565SJaakko Heinonen 	namep = devfs_fqpn(dirname, dm, de, NULL);
122*d318c565SJaakko Heinonen 	KASSERT(namep != NULL, ("devfs_ref_dir_de: NULL namep"));
123*d318c565SJaakko Heinonen 
124*d318c565SJaakko Heinonen 	devfs_dir_ref(namep);
125*d318c565SJaakko Heinonen }
126*d318c565SJaakko Heinonen 
127*d318c565SJaakko Heinonen static void
128*d318c565SJaakko Heinonen devfs_dir_unref(const char *dir)
129*d318c565SJaakko Heinonen {
130*d318c565SJaakko Heinonen 	struct dirlistent *dle;
131*d318c565SJaakko Heinonen 
132*d318c565SJaakko Heinonen 	if (*dir == '\0')
133*d318c565SJaakko Heinonen 		return;
134*d318c565SJaakko Heinonen 
135*d318c565SJaakko Heinonen 	mtx_lock(&dirlist_mtx);
136*d318c565SJaakko Heinonen 	dle = devfs_dir_findent_locked(dir);
137*d318c565SJaakko Heinonen 	KASSERT(dle != NULL, ("devfs_dir_unref: dir %s not referenced", dir));
138*d318c565SJaakko Heinonen 	dle->refcnt--;
139*d318c565SJaakko Heinonen 	KASSERT(dle->refcnt >= 0, ("devfs_dir_unref: negative refcnt"));
140*d318c565SJaakko Heinonen 	if (dle->refcnt == 0) {
141*d318c565SJaakko Heinonen 		LIST_REMOVE(dle, link);
142*d318c565SJaakko Heinonen 		mtx_unlock(&dirlist_mtx);
143*d318c565SJaakko Heinonen 		free(dle->dir, M_DEVFS4);
144*d318c565SJaakko Heinonen 		free(dle, M_DEVFS4);
145*d318c565SJaakko Heinonen 	} else
146*d318c565SJaakko Heinonen 		mtx_unlock(&dirlist_mtx);
147*d318c565SJaakko Heinonen }
148*d318c565SJaakko Heinonen 
149*d318c565SJaakko Heinonen void
150*d318c565SJaakko Heinonen devfs_dir_unref_de(struct devfs_mount *dm, struct devfs_dirent *de)
151*d318c565SJaakko Heinonen {
152*d318c565SJaakko Heinonen 	char dirname[SPECNAMELEN + 1], *namep;
153*d318c565SJaakko Heinonen 
154*d318c565SJaakko Heinonen 	namep = devfs_fqpn(dirname, dm, de, NULL);
155*d318c565SJaakko Heinonen 	KASSERT(namep != NULL, ("devfs_unref_dir_de: NULL namep"));
156*d318c565SJaakko Heinonen 
157*d318c565SJaakko Heinonen 	devfs_dir_unref(namep);
158*d318c565SJaakko Heinonen }
159*d318c565SJaakko Heinonen 
160*d318c565SJaakko Heinonen /* Returns 1 if the path p1 contains the path p2. */
161*d318c565SJaakko Heinonen int
162*d318c565SJaakko Heinonen devfs_pathpath(const char *p1, const char *p2)
163*d318c565SJaakko Heinonen {
164*d318c565SJaakko Heinonen 
165*d318c565SJaakko Heinonen 	for (;;p1++, p2++) {
166*d318c565SJaakko Heinonen 		if (*p1 != *p2) {
167*d318c565SJaakko Heinonen 			if (*p1 == '/' && *p2 == '\0')
168*d318c565SJaakko Heinonen 				return (1);
169*d318c565SJaakko Heinonen 			else
170*d318c565SJaakko Heinonen 				return (0);
171*d318c565SJaakko Heinonen 		} else if (*p1 == '\0')
172*d318c565SJaakko Heinonen 			return (1);
173*d318c565SJaakko Heinonen 	}
174*d318c565SJaakko Heinonen 	/* NOTREACHED */
175*d318c565SJaakko Heinonen }
176