166869Sadrian/*- 266869Sadrian * SPDX-License-Identifier: BSD-2-Clause 366869Sadrian * 466869Sadrian * Copyright (c) 2010 Jaakko Heinonen <jh@FreeBSD.org> 566869Sadrian * All rights reserved. 666869Sadrian * 766869Sadrian * Redistribution and use in source and binary forms, with or without 866869Sadrian * modification, are permitted provided that the following conditions 966869Sadrian * are met: 1066869Sadrian * 1. Redistributions of source code must retain the above copyright 1166869Sadrian * notice, this list of conditions and the following disclaimer. 1266869Sadrian * 2. Redistributions in binary form must reproduce the above copyright 1366869Sadrian * notice, this list of conditions and the following disclaimer in the 1466869Sadrian * documentation and/or other materials provided with the distribution. 1566869Sadrian * 1666869Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1766869Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1866869Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1966869Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2066869Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2166869Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2266869Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2366869Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2466869Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2566869Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2666869Sadrian * SUCH DAMAGE. 2766869Sadrian */ 2866869Sadrian 2966869Sadrian#include <sys/param.h> 3066869Sadrian#include <sys/conf.h> 3166869Sadrian#include <sys/types.h> 3266869Sadrian#include <sys/kernel.h> 3366869Sadrian#include <sys/libkern.h> 3466869Sadrian#include <sys/lock.h> 3566869Sadrian#include <sys/malloc.h> 3666869Sadrian#include <sys/mutex.h> 3766869Sadrian#include <sys/queue.h> 3866869Sadrian#include <sys/systm.h> 3966869Sadrian#include <sys/sx.h> 4066869Sadrian 4166869Sadrian#include <fs/devfs/devfs.h> 4266869Sadrian#include <fs/devfs/devfs_int.h> 4366869Sadrian 4466869Sadrianstruct dirlistent { 4566869Sadrian char *dir; 4666869Sadrian int refcnt; 4766869Sadrian LIST_ENTRY(dirlistent) link; 4866869Sadrian}; 4966869Sadrian 5066869Sadrianstatic LIST_HEAD(, dirlistent) devfs_dirlist = 5166869Sadrian LIST_HEAD_INITIALIZER(devfs_dirlist); 5266869Sadrian 5366869Sadrianstatic MALLOC_DEFINE(M_DEVFS4, "DEVFS4", "DEVFS directory list"); 5466869Sadrian 5566869Sadrianstatic struct mtx dirlist_mtx; 5666869SadrianMTX_SYSINIT(dirlist_mtx, &dirlist_mtx, "devfs dirlist lock", MTX_DEF); 5766869Sadrian 5866869Sadrian/* Returns 1 if the path is in the directory list. */ 5966869Sadrianint 6066869Sadriandevfs_dir_find(const char *path) 6166869Sadrian{ 6266869Sadrian struct dirlistent *dle; 6366869Sadrian 6466869Sadrian mtx_lock(&dirlist_mtx); 6566869Sadrian LIST_FOREACH(dle, &devfs_dirlist, link) { 6666869Sadrian if (devfs_pathpath(dle->dir, path) != 0) { 6766869Sadrian mtx_unlock(&dirlist_mtx); 6866869Sadrian return (1); 6966869Sadrian } 7066869Sadrian } 7166869Sadrian mtx_unlock(&dirlist_mtx); 7266869Sadrian 7366869Sadrian return (0); 7466869Sadrian} 7566869Sadrian 7666869Sadrianstatic struct dirlistent * 7766869Sadriandevfs_dir_findent_locked(const char *dir) 7866869Sadrian{ 7966869Sadrian struct dirlistent *dle; 8066869Sadrian 8166869Sadrian mtx_assert(&dirlist_mtx, MA_OWNED); 8292839Simp 8392839Simp LIST_FOREACH(dle, &devfs_dirlist, link) { 8492839Simp if (strcmp(dir, dle->dir) == 0) 8592839Simp return (dle); 8692839Simp } 8766869Sadrian 8866869Sadrian return (NULL); 8992839Simp} 9092839Simp 9166869Sadrianstatic void 9266869Sadriandevfs_dir_ref(const char *dir) 9366869Sadrian{ 9466869Sadrian struct dirlistent *dle, *dle_new; 9575015Sphk 9666869Sadrian if (*dir == '\0') 9766869Sadrian return; 9866869Sadrian 9966869Sadrian dle_new = malloc(sizeof(*dle), M_DEVFS4, M_WAITOK); 10066869Sadrian dle_new->dir = strdup(dir, M_DEVFS4); 10166869Sadrian dle_new->refcnt = 1; 10266869Sadrian 10375015Sphk mtx_lock(&dirlist_mtx); 10475015Sphk dle = devfs_dir_findent_locked(dir); 10575015Sphk if (dle != NULL) { 10675015Sphk dle->refcnt++; 10775015Sphk mtx_unlock(&dirlist_mtx); 10875015Sphk free(dle_new->dir, M_DEVFS4); 10966869Sadrian free(dle_new, M_DEVFS4); 11066869Sadrian return; 11166869Sadrian } 11266869Sadrian LIST_INSERT_HEAD(&devfs_dirlist, dle_new, link); 11366869Sadrian mtx_unlock(&dirlist_mtx); 11466869Sadrian} 11575015Sphk 11675015Sphkvoid 11775015Sphkdevfs_dir_ref_de(struct devfs_mount *dm, struct devfs_dirent *de) 11875936Smckusick{ 11975015Sphk char dirname[SPECNAMELEN + 1], *namep; 12075015Sphk 12166869Sadrian namep = devfs_fqpn(dirname, dm, de, NULL); 12266869Sadrian KASSERT(namep != NULL, ("devfs_ref_dir_de: NULL namep")); 12366869Sadrian 12475936Smckusick devfs_dir_ref(namep); 12575936Smckusick} 12666869Sadrian 12766869Sadrianstatic void 12866869Sadriandevfs_dir_unref(const char *dir) 12966869Sadrian{ 13066869Sadrian struct dirlistent *dle; 13166869Sadrian 13266869Sadrian if (*dir == '\0') 13375936Smckusick return; 13466869Sadrian 13566869Sadrian mtx_lock(&dirlist_mtx); 13666869Sadrian dle = devfs_dir_findent_locked(dir); 13775015Sphk KASSERT(dle != NULL, ("devfs_dir_unref: dir %s not referenced", dir)); 13875015Sphk dle->refcnt--; 13975015Sphk KASSERT(dle->refcnt >= 0, ("devfs_dir_unref: negative refcnt")); 14075015Sphk if (dle->refcnt == 0) { 14175015Sphk LIST_REMOVE(dle, link); 14275015Sphk mtx_unlock(&dirlist_mtx); 14375015Sphk free(dle->dir, M_DEVFS4); 14466869Sadrian free(dle, M_DEVFS4); 14575936Smckusick } else 14666869Sadrian mtx_unlock(&dirlist_mtx); 14766869Sadrian} 14875936Smckusick 14975936Smckusickvoid 15075015Sphkdevfs_dir_unref_de(struct devfs_mount *dm, struct devfs_dirent *de) 15166869Sadrian{ 15275015Sphk char dirname[SPECNAMELEN + 1], *namep; 15375015Sphk 15475015Sphk namep = devfs_fqpn(dirname, dm, de, NULL); 15575015Sphk KASSERT(namep != NULL, ("devfs_unref_dir_de: NULL namep")); 15675015Sphk 15775015Sphk devfs_dir_unref(namep); 15866869Sadrian} 15966869Sadrian 16066869Sadrian/* Returns 1 if the path p1 contains the path p2. */ 16166869Sadrianint 16275015Sphkdevfs_pathpath(const char *p1, const char *p2) 16375015Sphk{ 16466869Sadrian 16570413Sphk for (;;p1++, p2++) { 16666869Sadrian if (*p1 != *p2) { 16766869Sadrian if (*p1 == '/' && *p2 == '\0') 16866869Sadrian return (1); 16966869Sadrian else 17066869Sadrian return (0); 17166869Sadrian } else if (*p1 == '\0') 17266869Sadrian return (1); 17366869Sadrian } 17466869Sadrian /* NOTREACHED */ 17566869Sadrian} 17666869Sadrian