MFC:
Various fixes for DEVFS, in particular "devfs ruleset already running". Approved by: re@ (scottl)
This commit is contained in:
parent
9e1e30a0a8
commit
051ea6d1a8
@ -169,7 +169,6 @@ struct devfs_dirent {
|
||||
struct devfs_mount {
|
||||
struct mount *dm_mount;
|
||||
struct devfs_dirent *dm_rootdir;
|
||||
struct devfs_dirent *dm_basedir;
|
||||
unsigned dm_generation;
|
||||
struct devfs_dirent **dm_dirent;
|
||||
struct devfs_dirent **dm_overflow;
|
||||
@ -178,6 +177,8 @@ struct devfs_mount {
|
||||
devfs_rsnum dm_ruleset;
|
||||
};
|
||||
|
||||
extern unsigned devfs_rule_depth;
|
||||
|
||||
/*
|
||||
* This is what we fill in dm_dirent[N] for a deleted entry.
|
||||
*/
|
||||
@ -186,12 +187,12 @@ struct devfs_mount {
|
||||
#define VFSTODEVFS(mp) ((struct devfs_mount *)((mp)->mnt_data))
|
||||
|
||||
void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de);
|
||||
int devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td);
|
||||
int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td);
|
||||
void devfs_rules_newmount(struct devfs_mount *dm, struct thread *td);
|
||||
int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td);
|
||||
struct cdev **devfs_itod (int inode);
|
||||
struct devfs_dirent **devfs_itode (struct devfs_mount *dm, int inode);
|
||||
int devfs_populate (struct devfs_mount *dm);
|
||||
void devfs_populate (struct devfs_mount *dm);
|
||||
struct devfs_dirent *devfs_newdirent (char *name, int namelen);
|
||||
void devfs_purge (struct devfs_dirent *dd);
|
||||
struct devfs_dirent *devfs_vmkdir (char *name, int namelen, struct devfs_dirent *dotdot);
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#include <fs/devfs/devfs.h>
|
||||
#include <fs/devfs/devfs_int.h>
|
||||
|
||||
static struct cdev *devfs_inot[NDEVFSINO];
|
||||
static struct cdev **devfs_overflow;
|
||||
@ -70,6 +71,42 @@ SYSCTL_UINT(_vfs_devfs, OID_AUTO, inodes, CTLFLAG_RD,
|
||||
SYSCTL_UINT(_vfs_devfs, OID_AUTO, topinode, CTLFLAG_RD,
|
||||
&devfs_topino, 0, "DEVFS highest inode#");
|
||||
|
||||
unsigned devfs_rule_depth = 1;
|
||||
SYSCTL_UINT(_vfs_devfs, OID_AUTO, rule_depth, CTLFLAG_RW,
|
||||
&devfs_rule_depth, 0, "Max depth of ruleset include");
|
||||
|
||||
/*
|
||||
* Helper sysctl for devname(3). We're given a struct cdev * and return
|
||||
* the name, if any, registered by the device driver.
|
||||
*/
|
||||
static int
|
||||
sysctl_devname(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
dev_t ud;
|
||||
struct cdev *dev, **dp;
|
||||
|
||||
error = SYSCTL_IN(req, &ud, sizeof (ud));
|
||||
if (error)
|
||||
return (error);
|
||||
if (ud == NODEV)
|
||||
return(EINVAL);
|
||||
dp = devfs_itod(ud);
|
||||
if (dp == NULL)
|
||||
return(ENOENT);
|
||||
dev = *dp;
|
||||
if (dev == NULL)
|
||||
return(ENOENT);
|
||||
return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1));
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
|
||||
NULL, 0, sysctl_devname, "", "devname(3) handler");
|
||||
|
||||
SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD,
|
||||
0, sizeof(struct cdev), "sizeof(struct cdev)");
|
||||
|
||||
static int *
|
||||
devfs_itor(int inode)
|
||||
{
|
||||
@ -164,7 +201,7 @@ devfs_newdirent(char *name, int namelen)
|
||||
|
||||
d.d_namlen = namelen;
|
||||
i = sizeof (*de) + GENERIC_DIRSIZ(&d);
|
||||
MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK | M_ZERO);
|
||||
de = malloc(i, M_DEVFS, M_WAITOK | M_ZERO);
|
||||
de->de_dirent = (struct dirent *)(de + 1);
|
||||
de->de_dirent->d_namlen = namelen;
|
||||
de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
|
||||
@ -217,7 +254,7 @@ devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
|
||||
{
|
||||
|
||||
if (de->de_symlink) {
|
||||
FREE(de->de_symlink, M_DEVFS);
|
||||
free(de->de_symlink, M_DEVFS);
|
||||
de->de_symlink = NULL;
|
||||
}
|
||||
if (de->de_vnode)
|
||||
@ -226,7 +263,7 @@ devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
|
||||
#ifdef MAC
|
||||
mac_destroy_devfsdirent(de);
|
||||
#endif
|
||||
FREE(de, M_DEVFS);
|
||||
free(de, M_DEVFS);
|
||||
}
|
||||
|
||||
void
|
||||
@ -244,7 +281,7 @@ devfs_purge(struct devfs_dirent *dd)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
void
|
||||
devfs_populate(struct devfs_mount *dm)
|
||||
{
|
||||
int i, j;
|
||||
@ -254,8 +291,7 @@ devfs_populate(struct devfs_mount *dm)
|
||||
char *q, *s;
|
||||
|
||||
if (dm->dm_generation == devfs_generation)
|
||||
return (0);
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, curthread);
|
||||
return;
|
||||
if (devfs_noverflow && dm->dm_overflow == NULL) {
|
||||
i = devfs_noverflow * sizeof (struct devfs_dirent *);
|
||||
MALLOC(dm->dm_overflow, struct devfs_dirent **, i,
|
||||
@ -284,7 +320,7 @@ devfs_populate(struct devfs_mount *dm)
|
||||
continue;
|
||||
if (!devfs_getref(i))
|
||||
continue;
|
||||
dd = dm->dm_basedir;
|
||||
dd = dm->dm_rootdir;
|
||||
s = dev->si_name;
|
||||
for (;;) {
|
||||
for (q = s; *q != '/' && *q != '\0'; q++)
|
||||
@ -333,8 +369,6 @@ devfs_populate(struct devfs_mount *dm)
|
||||
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
|
||||
}
|
||||
}
|
||||
lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, curthread);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -71,8 +71,8 @@
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/sx.h>
|
||||
|
||||
#include <fs/devfs/devfs.h>
|
||||
|
||||
@ -96,12 +96,10 @@ struct devfs_ruleset {
|
||||
int ds_refcount;
|
||||
int ds_flags;
|
||||
#define DS_IMMUTABLE 0x001
|
||||
int ds_running;
|
||||
};
|
||||
|
||||
static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
|
||||
|
||||
static void devfs_rule_applyde(struct devfs_krule *dk,struct devfs_dirent *de);
|
||||
static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
|
||||
struct devfs_dirent *de);
|
||||
static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
|
||||
@ -114,10 +112,10 @@ static int devfs_rule_insert(struct devfs_rule *dr);
|
||||
static int devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
|
||||
static int devfs_rule_matchpath(struct devfs_krule *dk,
|
||||
struct devfs_dirent *de);
|
||||
static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de);
|
||||
static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth);
|
||||
|
||||
static void devfs_ruleset_applyde(struct devfs_ruleset *ds,
|
||||
struct devfs_dirent *de);
|
||||
struct devfs_dirent *de, unsigned depth);
|
||||
static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
|
||||
struct devfs_mount *dm);
|
||||
static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
|
||||
@ -126,10 +124,11 @@ static void devfs_ruleset_destroy(struct devfs_ruleset **dsp);
|
||||
static void devfs_ruleset_reap(struct devfs_ruleset **dsp);
|
||||
static int devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
|
||||
|
||||
static struct sx sx_rules;
|
||||
static SLIST_HEAD(, devfs_ruleset) devfs_rulesets;
|
||||
|
||||
/*
|
||||
* Called to apply the proper rules for de before the latter can be
|
||||
* Called to apply the proper rules for 'de' before it can be
|
||||
* exposed to the userland. This should be called with an exclusive
|
||||
* lock on dm in case we need to run anything.
|
||||
*/
|
||||
@ -138,9 +137,11 @@ devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
|
||||
{
|
||||
struct devfs_ruleset *ds;
|
||||
|
||||
sx_slock(&sx_rules);
|
||||
ds = devfs_ruleset_bynum(dm->dm_ruleset);
|
||||
KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
|
||||
devfs_ruleset_applyde(ds, de);
|
||||
devfs_ruleset_applyde(ds, de, devfs_rule_depth);
|
||||
sx_sunlock(&sx_rules);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -151,6 +152,7 @@ devfs_rules_init(void *junk __unused)
|
||||
{
|
||||
struct devfs_ruleset *ds;
|
||||
|
||||
sx_init(&sx_rules, "devfsrules");
|
||||
SLIST_INIT(&devfs_rulesets);
|
||||
|
||||
ds = devfs_ruleset_create(0);
|
||||
@ -164,9 +166,8 @@ SYSINIT(devfs_rules, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_rules_init, NULL);
|
||||
* Rule subsystem ioctl hook.
|
||||
*/
|
||||
int
|
||||
devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
struct devfs_mount *dm = VFSTODEVFS(mp);
|
||||
struct devfs_ruleset *ds;
|
||||
struct devfs_krule *dk;
|
||||
struct devfs_rule *dr;
|
||||
@ -183,8 +184,7 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
lockmgr(&dm->dm_lock, LK_SHARED, 0, td);
|
||||
|
||||
sx_xlock(&sx_rules);
|
||||
switch (cmd) {
|
||||
case DEVFSIO_RADD:
|
||||
dr = (struct devfs_rule *)data;
|
||||
@ -196,7 +196,6 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
error = EEXIST;
|
||||
goto out;
|
||||
}
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
error = devfs_rule_insert(dr);
|
||||
break;
|
||||
case DEVFSIO_RAPPLY:
|
||||
@ -226,9 +225,7 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
}
|
||||
dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO);
|
||||
memcpy(&dk->dk_rule, dr, sizeof(*dr));
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
devfs_rule_applydm(dk, dm);
|
||||
lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, td);
|
||||
free(dk, M_TEMP);
|
||||
error = 0;
|
||||
break;
|
||||
@ -240,7 +237,6 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
error = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
devfs_rule_applydm(dk, dm);
|
||||
error = 0;
|
||||
break;
|
||||
@ -253,7 +249,6 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
goto out;
|
||||
}
|
||||
ds = dk->dk_ruleset;
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
error = devfs_rule_delete(&dk);
|
||||
devfs_ruleset_reap(&ds);
|
||||
break;
|
||||
@ -289,7 +284,6 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
break;
|
||||
case DEVFSIO_SUSE:
|
||||
rsnum = *(devfs_rsnum *)data;
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
error = devfs_ruleset_use(rsnum, dm);
|
||||
break;
|
||||
case DEVFSIO_SAPPLY:
|
||||
@ -300,7 +294,6 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
error = ESRCH;
|
||||
goto out;
|
||||
}
|
||||
lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
|
||||
devfs_ruleset_applydm(ds, dm);
|
||||
error = 0;
|
||||
break;
|
||||
@ -323,7 +316,7 @@ devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
|
||||
}
|
||||
|
||||
out:
|
||||
lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
|
||||
sx_xunlock(&sx_rules);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -335,18 +328,18 @@ devfs_rules_newmount(struct devfs_mount *dm, struct thread *td)
|
||||
{
|
||||
struct devfs_ruleset *ds;
|
||||
|
||||
lockmgr(&dm->dm_lock, LK_EXCLUSIVE, 0, td);
|
||||
/*
|
||||
* We can't use devfs_ruleset_use() since it will try to
|
||||
* decrement the refcount for the old ruleset, and there is no
|
||||
* old ruleset. Making some value of ds_ruleset "special" to
|
||||
* mean "don't decrement refcount" is uglier than this.
|
||||
*/
|
||||
sx_slock(&sx_rules);
|
||||
ds = devfs_ruleset_bynum(0);
|
||||
KASSERT(ds != NULL, ("no ruleset 0"));
|
||||
++ds->ds_refcount;
|
||||
dm->dm_ruleset = 0;
|
||||
lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
|
||||
sx_sunlock(&sx_rules);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -367,17 +360,6 @@ devfs_rid_input(devfs_rid rid, struct devfs_mount *dm)
|
||||
return (rid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply dk to de.
|
||||
*/
|
||||
static void
|
||||
devfs_rule_applyde(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
{
|
||||
|
||||
if (devfs_rule_match(dk, de))
|
||||
devfs_rule_run(dk, de);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply dk to de and everything under de.
|
||||
*
|
||||
@ -390,11 +372,9 @@ devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
{
|
||||
struct devfs_dirent *de2;
|
||||
|
||||
/* XXX: Should we apply to ourselves first or last? Does it matter? */
|
||||
TAILQ_FOREACH(de2, &de->de_dlist, de_list) {
|
||||
TAILQ_FOREACH(de2, &de->de_dlist, de_list)
|
||||
devfs_rule_applyde_recursive(dk, de2);
|
||||
}
|
||||
devfs_rule_applyde(dk, de);
|
||||
devfs_rule_run(dk, de, devfs_rule_depth);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -404,7 +384,7 @@ static void
|
||||
devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm)
|
||||
{
|
||||
|
||||
devfs_rule_applyde_recursive(dk, dm->dm_basedir);
|
||||
devfs_rule_applyde_recursive(dk, dm->dm_rootdir);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -610,15 +590,12 @@ devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
if (dr->dr_icond & DRC_DSWFLAGS)
|
||||
if (dev == NULL ||
|
||||
(dev->si_devsw->d_flags & dr->dr_dswflags) == 0)
|
||||
goto nomatch;
|
||||
return (0);
|
||||
if (dr->dr_icond & DRC_PATHPTRN)
|
||||
if (!devfs_rule_matchpath(dk, de))
|
||||
goto nomatch;
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
nomatch:
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -648,11 +625,13 @@ devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
* Run dk on de.
|
||||
*/
|
||||
static void
|
||||
devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth)
|
||||
{
|
||||
struct devfs_rule *dr = &dk->dk_rule;
|
||||
struct devfs_ruleset *ds;
|
||||
|
||||
if (!devfs_rule_match(dk, de))
|
||||
return;
|
||||
if (dr->dr_iacts & DRA_BACTS) {
|
||||
if (dr->dr_bacts & DRB_HIDE)
|
||||
de->de_flags |= DE_WHITEOUT;
|
||||
@ -666,13 +645,20 @@ devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
if (dr->dr_iacts & DRA_MODE)
|
||||
de->de_mode = dr->dr_mode;
|
||||
if (dr->dr_iacts & DRA_INCSET) {
|
||||
ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
|
||||
KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
|
||||
if (ds->ds_running)
|
||||
printf("Warning: avoiding loop through ruleset %d\n",
|
||||
ds->ds_number);
|
||||
else
|
||||
devfs_ruleset_applyde(ds, de);
|
||||
/*
|
||||
* XXX: we should tell the user if the depth is exceeded here
|
||||
* XXX: but it is not obvious how to. A return value will
|
||||
* XXX: not work as this is called when devices are created
|
||||
* XXX: long time after the rules were instantiated.
|
||||
* XXX: a printf() would probably give too much noise, or
|
||||
* XXX: DoS the machine. I guess a a rate-limited message
|
||||
* XXX: might work.
|
||||
*/
|
||||
if (depth > 0) {
|
||||
ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
|
||||
KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
|
||||
devfs_ruleset_applyde(ds, de, depth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -680,16 +666,12 @@ devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de)
|
||||
* Apply all the rules in ds to de.
|
||||
*/
|
||||
static void
|
||||
devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de)
|
||||
devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de, unsigned depth)
|
||||
{
|
||||
struct devfs_krule *dk;
|
||||
|
||||
KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
|
||||
ds->ds_running = 1;
|
||||
SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
|
||||
devfs_rule_applyde(dk, de);
|
||||
}
|
||||
ds->ds_running = 0;
|
||||
SLIST_FOREACH(dk, &ds->ds_rules, dk_list)
|
||||
devfs_rule_run(dk, de, depth);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -700,8 +682,6 @@ devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
|
||||
{
|
||||
struct devfs_krule *dk;
|
||||
|
||||
KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
|
||||
ds->ds_running = 1;
|
||||
/*
|
||||
* XXX: Does it matter whether we do
|
||||
*
|
||||
@ -721,7 +701,6 @@ devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
|
||||
SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
|
||||
devfs_rule_applydm(dk, dm);
|
||||
}
|
||||
ds->ds_running = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -829,4 +808,3 @@ devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm)
|
||||
devfs_ruleset_reap(&cds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,6 @@ devfs_mount(struct mount *mp, struct thread *td)
|
||||
#ifdef MAC
|
||||
mac_create_devfs_directory(mp, "", 0, fmp->dm_rootdir);
|
||||
#endif
|
||||
fmp->dm_basedir = fmp->dm_rootdir;
|
||||
devfs_rules_newmount(fmp, td);
|
||||
|
||||
error = devfs_root(mp, LK_EXCLUSIVE, &rvp, td);
|
||||
|
@ -61,133 +61,16 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ttycom.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
static struct vop_vector devfs_vnodeops;
|
||||
static struct vop_vector devfs_specops;
|
||||
static struct fileops devfs_ops_f;
|
||||
|
||||
#include <fs/devfs/devfs.h>
|
||||
|
||||
static fo_rdwr_t devfs_read_f;
|
||||
static fo_rdwr_t devfs_write_f;
|
||||
static fo_ioctl_t devfs_ioctl_f;
|
||||
static fo_poll_t devfs_poll_f;
|
||||
static fo_kqfilter_t devfs_kqfilter_f;
|
||||
static fo_stat_t devfs_stat_f;
|
||||
static fo_close_t devfs_close_f;
|
||||
|
||||
static struct fileops devfs_ops_f = {
|
||||
.fo_read = devfs_read_f,
|
||||
.fo_write = devfs_write_f,
|
||||
.fo_ioctl = devfs_ioctl_f,
|
||||
.fo_poll = devfs_poll_f,
|
||||
.fo_kqfilter = devfs_kqfilter_f,
|
||||
.fo_stat = devfs_stat_f,
|
||||
.fo_close = devfs_close_f,
|
||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
|
||||
};
|
||||
|
||||
static vop_access_t devfs_access;
|
||||
static vop_advlock_t devfs_advlock;
|
||||
static vop_close_t devfs_close;
|
||||
static vop_fsync_t devfs_fsync;
|
||||
static vop_getattr_t devfs_getattr;
|
||||
static vop_lookup_t devfs_lookup;
|
||||
static vop_lookup_t devfs_lookupx;
|
||||
static vop_mknod_t devfs_mknod;
|
||||
static vop_open_t devfs_open;
|
||||
static vop_pathconf_t devfs_pathconf;
|
||||
static vop_print_t devfs_print;
|
||||
static vop_readdir_t devfs_readdir;
|
||||
static vop_readlink_t devfs_readlink;
|
||||
static vop_reclaim_t devfs_reclaim;
|
||||
static vop_remove_t devfs_remove;
|
||||
static vop_revoke_t devfs_revoke;
|
||||
static vop_ioctl_t devfs_rioctl;
|
||||
static vop_read_t devfs_rread;
|
||||
static vop_setattr_t devfs_setattr;
|
||||
#ifdef MAC
|
||||
static vop_setlabel_t devfs_setlabel;
|
||||
#endif
|
||||
static vop_symlink_t devfs_symlink;
|
||||
|
||||
static struct vop_vector devfs_vnodeops = {
|
||||
.vop_default = &default_vnodeops,
|
||||
|
||||
.vop_access = devfs_access,
|
||||
.vop_getattr = devfs_getattr,
|
||||
.vop_ioctl = devfs_rioctl,
|
||||
.vop_lookup = devfs_lookup,
|
||||
.vop_mknod = devfs_mknod,
|
||||
.vop_pathconf = devfs_pathconf,
|
||||
.vop_read = devfs_rread,
|
||||
.vop_readdir = devfs_readdir,
|
||||
.vop_readlink = devfs_readlink,
|
||||
.vop_reclaim = devfs_reclaim,
|
||||
.vop_remove = devfs_remove,
|
||||
.vop_revoke = devfs_revoke,
|
||||
.vop_setattr = devfs_setattr,
|
||||
#ifdef MAC
|
||||
.vop_setlabel = devfs_setlabel,
|
||||
#endif
|
||||
.vop_symlink = devfs_symlink,
|
||||
};
|
||||
|
||||
static struct vop_vector devfs_specops = {
|
||||
.vop_default = &default_vnodeops,
|
||||
|
||||
.vop_access = devfs_access,
|
||||
.vop_advlock = devfs_advlock,
|
||||
.vop_bmap = VOP_PANIC,
|
||||
.vop_close = devfs_close,
|
||||
.vop_create = VOP_PANIC,
|
||||
.vop_fsync = devfs_fsync,
|
||||
.vop_getattr = devfs_getattr,
|
||||
.vop_lease = VOP_NULL,
|
||||
.vop_link = VOP_PANIC,
|
||||
.vop_mkdir = VOP_PANIC,
|
||||
.vop_mknod = VOP_PANIC,
|
||||
.vop_open = devfs_open,
|
||||
.vop_pathconf = devfs_pathconf,
|
||||
.vop_print = devfs_print,
|
||||
.vop_read = VOP_PANIC,
|
||||
.vop_readdir = VOP_PANIC,
|
||||
.vop_readlink = VOP_PANIC,
|
||||
.vop_reallocblks = VOP_PANIC,
|
||||
.vop_reclaim = devfs_reclaim,
|
||||
.vop_remove = devfs_remove,
|
||||
.vop_rename = VOP_PANIC,
|
||||
.vop_revoke = devfs_revoke,
|
||||
.vop_rmdir = VOP_PANIC,
|
||||
.vop_setattr = devfs_setattr,
|
||||
#ifdef MAC
|
||||
.vop_setlabel = devfs_setlabel,
|
||||
#endif
|
||||
.vop_strategy = VOP_PANIC,
|
||||
.vop_symlink = VOP_PANIC,
|
||||
.vop_write = VOP_PANIC,
|
||||
};
|
||||
|
||||
static u_int
|
||||
devfs_random(void)
|
||||
{
|
||||
static u_int devfs_seed;
|
||||
|
||||
while (devfs_seed == 0) {
|
||||
/*
|
||||
* Make sure people don't make stupid assumptions
|
||||
* about device major/minor numbers in userspace.
|
||||
* We do this late to get entropy and for the same
|
||||
* reason we force a reseed, but it may not be
|
||||
* late enough for entropy to be available.
|
||||
*/
|
||||
arc4rand(&devfs_seed, sizeof devfs_seed, 1);
|
||||
devfs_seed &= 0xf0f;
|
||||
}
|
||||
return (devfs_seed);
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp)
|
||||
{
|
||||
@ -222,7 +105,7 @@ devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp)
|
||||
return (NULL);
|
||||
bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen);
|
||||
de = dd;
|
||||
while (de != dmp->dm_basedir) {
|
||||
while (de != dmp->dm_rootdir) {
|
||||
i--;
|
||||
if (i < 0)
|
||||
return (NULL);
|
||||
@ -297,13 +180,7 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, stru
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_access(ap)
|
||||
struct vop_access_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_access(struct vop_access_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct devfs_dirent *de;
|
||||
@ -332,14 +209,7 @@ devfs_access(ap)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
devfs_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
caddr_t a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
devfs_advlock(struct vop_advlock_args *ap)
|
||||
{
|
||||
|
||||
return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
|
||||
@ -350,13 +220,7 @@ devfs_advlock(ap)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
devfs_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_close(struct vop_close_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp, *oldvp;
|
||||
struct thread *td = ap->a_td;
|
||||
@ -424,9 +288,7 @@ devfs_close(ap)
|
||||
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
|
||||
PICKUP_GIANT();
|
||||
} else {
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
dev_relthread(dev);
|
||||
return (error);
|
||||
@ -444,13 +306,7 @@ devfs_close_f(struct file *fp, struct thread *td)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
devfs_fsync(ap)
|
||||
struct vop_fsync_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct ucred *a_cred;
|
||||
int a_waitfor;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_fsync(struct vop_fsync_args *ap)
|
||||
{
|
||||
if (!vn_isdisk(ap->a_vp, NULL))
|
||||
return (0);
|
||||
@ -459,13 +315,7 @@ devfs_fsync(ap)
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_getattr(struct vop_getattr_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
@ -520,7 +370,7 @@ devfs_getattr(ap)
|
||||
fix(dev->si_ctime);
|
||||
vap->va_ctime = dev->si_ctime;
|
||||
|
||||
vap->va_rdev = dev->si_inode ^ devfs_random();
|
||||
vap->va_rdev = dev->si_inode;
|
||||
}
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
@ -564,11 +414,7 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc
|
||||
dev_relthread(dev);
|
||||
return (error);
|
||||
}
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_ioctl(dev, com, data, fp->f_flag, td);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_unlock(&Giant);
|
||||
dev_relthread(dev);
|
||||
if (error == ENOIOCTL)
|
||||
error = ENOTTY;
|
||||
@ -612,22 +458,13 @@ devfs_kqfilter_f(struct file *fp, struct knote *kn)
|
||||
error = devfs_fp_check(fp, &dev, &dsw);
|
||||
if (error)
|
||||
return (error);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_kqfilter(dev, kn);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_unlock(&Giant);
|
||||
dev_relthread(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_lookupx(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
devfs_lookupx(struct vop_lookup_args *ap)
|
||||
{
|
||||
struct componentname *cnp;
|
||||
struct vnode *dvp, **vpp;
|
||||
@ -683,7 +520,9 @@ devfs_lookupx(ap)
|
||||
return (error);
|
||||
}
|
||||
|
||||
lockmgr(&dmp->dm_lock, LK_UPGRADE, 0, curthread);
|
||||
devfs_populate(dmp);
|
||||
lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
|
||||
dd = dvp->v_data;
|
||||
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
|
||||
if (cnp->cn_namelen != de->de_dirent->d_namlen)
|
||||
@ -713,7 +552,9 @@ devfs_lookupx(ap)
|
||||
if (cdev == NULL)
|
||||
goto notfound;
|
||||
|
||||
lockmgr(&dmp->dm_lock, LK_UPGRADE, 0, curthread);
|
||||
devfs_populate(dmp);
|
||||
lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
|
||||
|
||||
dde = devfs_itode(dmp, cdev->si_inode);
|
||||
dev_rel(cdev);
|
||||
@ -772,14 +613,6 @@ devfs_lookup(struct vop_lookup_args *ap)
|
||||
|
||||
static int
|
||||
devfs_mknod(struct vop_mknod_args *ap)
|
||||
/*
|
||||
struct vop_mknod_args {
|
||||
struct vnodeop_desc *a_desc;
|
||||
struct vnode *a_dvp;
|
||||
struct vnode **a_vpp;
|
||||
struct componentname *a_cnp;
|
||||
struct vattr *a_vap;
|
||||
}; */
|
||||
{
|
||||
struct componentname *cnp;
|
||||
struct vnode *dvp, **vpp;
|
||||
@ -828,14 +661,7 @@ devfs_mknod(struct vop_mknod_args *ap)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
devfs_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
int a_fdidx;
|
||||
} */ *ap;
|
||||
devfs_open(struct vop_open_args *ap)
|
||||
{
|
||||
struct thread *td = ap->a_td;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
@ -884,12 +710,10 @@ devfs_open(ap)
|
||||
error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
|
||||
PICKUP_GIANT();
|
||||
} else {
|
||||
mtx_lock(&Giant);
|
||||
if (dsw->d_fdopen != NULL)
|
||||
error = dsw->d_fdopen(dev, ap->a_mode, td, ap->a_fdidx);
|
||||
else
|
||||
error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
@ -921,21 +745,10 @@ devfs_open(ap)
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_pathconf(ap)
|
||||
struct vop_pathconf_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_name;
|
||||
int *a_retval;
|
||||
} */ *ap;
|
||||
devfs_pathconf(struct vop_pathconf_args *ap)
|
||||
{
|
||||
|
||||
switch (ap->a_name) {
|
||||
case _PC_NAME_MAX:
|
||||
*ap->a_retval = NAME_MAX;
|
||||
return (0);
|
||||
case _PC_PATH_MAX:
|
||||
*ap->a_retval = PATH_MAX;
|
||||
return (0);
|
||||
case _PC_MAC_PRESENT:
|
||||
#ifdef MAC
|
||||
/*
|
||||
@ -964,11 +777,7 @@ devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
|
||||
error = devfs_fp_check(fp, &dev, &dsw);
|
||||
if (error)
|
||||
return (error);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_poll(dev, events, td);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_unlock(&Giant);
|
||||
dev_relthread(dev);
|
||||
return(error);
|
||||
}
|
||||
@ -977,10 +786,7 @@ devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
|
||||
* Print out the contents of a special device vnode.
|
||||
*/
|
||||
static int
|
||||
devfs_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
devfs_print(struct vop_print_args *ap)
|
||||
{
|
||||
|
||||
printf("\tdev %s\n", devtoname(ap->a_vp->v_rdev));
|
||||
@ -1009,11 +815,7 @@ devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, st
|
||||
if ((flags & FOF_OFFSET) == 0)
|
||||
uio->uio_offset = fp->f_offset;
|
||||
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_read(dev, uio, ioflag);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_unlock(&Giant);
|
||||
dev_relthread(dev);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0))
|
||||
vfs_timestamp(&dev->si_atime);
|
||||
@ -1025,15 +827,7 @@ devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, st
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
int *a_ncookies;
|
||||
u_long **a_cookies;
|
||||
} */ *ap;
|
||||
devfs_readdir(struct vop_readdir_args *ap)
|
||||
{
|
||||
int error;
|
||||
struct uio *uio;
|
||||
@ -1042,9 +836,6 @@ devfs_readdir(ap)
|
||||
struct devfs_dirent *de;
|
||||
struct devfs_mount *dmp;
|
||||
off_t off, oldoff;
|
||||
int ncookies = 0;
|
||||
u_long *cookiebuf, *cookiep;
|
||||
struct dirent *dps, *dpe;
|
||||
|
||||
if (ap->a_vp->v_type != VDIR)
|
||||
return (ENOTDIR);
|
||||
@ -1054,12 +845,17 @@ devfs_readdir(ap)
|
||||
return (EINVAL);
|
||||
|
||||
dmp = VFSTODEVFS(ap->a_vp->v_mount);
|
||||
lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
|
||||
lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
|
||||
devfs_populate(dmp);
|
||||
lockmgr(&dmp->dm_lock, LK_DOWNGRADE, 0, curthread);
|
||||
error = 0;
|
||||
de = ap->a_vp->v_data;
|
||||
off = 0;
|
||||
oldoff = uio->uio_offset;
|
||||
if (ap->a_ncookies != NULL) {
|
||||
*ap->a_ncookies = 0;
|
||||
*ap->a_cookies = NULL;
|
||||
}
|
||||
TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
|
||||
if (dd->de_flags & DE_WHITEOUT)
|
||||
continue;
|
||||
@ -1072,55 +868,28 @@ devfs_readdir(ap)
|
||||
break;
|
||||
dp->d_fileno = de->de_inode;
|
||||
if (off >= uio->uio_offset) {
|
||||
ncookies++;
|
||||
error = uiomove(dp, dp->d_reclen, uio);
|
||||
error = vfs_read_dirent(ap, dp, off);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
off += dp->d_reclen;
|
||||
}
|
||||
if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) {
|
||||
MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long),
|
||||
M_TEMP, M_WAITOK);
|
||||
cookiep = cookiebuf;
|
||||
dps = (struct dirent *)((char *)uio->uio_iov->iov_base -
|
||||
(uio->uio_offset - oldoff));
|
||||
dpe = (struct dirent *) uio->uio_iov->iov_base;
|
||||
for( dp = dps;
|
||||
dp < dpe;
|
||||
dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
|
||||
oldoff += dp->d_reclen;
|
||||
*cookiep++ = (u_long) oldoff;
|
||||
}
|
||||
*ap->a_ncookies = ncookies;
|
||||
*ap->a_cookies = cookiebuf;
|
||||
}
|
||||
lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
|
||||
uio->uio_offset = off;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_readlink(ap)
|
||||
struct vop_readlink_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cead;
|
||||
} */ *ap;
|
||||
devfs_readlink(struct vop_readlink_args *ap)
|
||||
{
|
||||
int error;
|
||||
struct devfs_dirent *de;
|
||||
|
||||
de = ap->a_vp->v_data;
|
||||
error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio);
|
||||
return (error);
|
||||
return (uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio));
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
devfs_reclaim(struct vop_reclaim_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct devfs_dirent *de;
|
||||
@ -1148,12 +917,7 @@ devfs_reclaim(ap)
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_remove(ap)
|
||||
struct vop_remove_args /* {
|
||||
struct vnode *a_dvp;
|
||||
struct vnode *a_vp;
|
||||
struct componentname *a_cnp;
|
||||
} */ *ap;
|
||||
devfs_remove(struct vop_remove_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct devfs_dirent *dd;
|
||||
@ -1170,7 +934,7 @@ devfs_remove(ap)
|
||||
#ifdef MAC
|
||||
mac_destroy_devfsdirent(de);
|
||||
#endif
|
||||
FREE(de, M_DEVFS);
|
||||
free(de, M_DEVFS);
|
||||
} else {
|
||||
de->de_flags |= DE_WHITEOUT;
|
||||
}
|
||||
@ -1184,11 +948,7 @@ devfs_remove(ap)
|
||||
* as well so that we create a new one next time around.
|
||||
*/
|
||||
static int
|
||||
devfs_revoke(ap)
|
||||
struct vop_revoke_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
devfs_revoke(struct vop_revoke_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct cdev *dev;
|
||||
@ -1209,36 +969,21 @@ devfs_revoke(ap)
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_rioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
u_long a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_rioctl(struct vop_ioctl_args *ap)
|
||||
{
|
||||
int error;
|
||||
struct devfs_mount *dmp;
|
||||
|
||||
dmp = VFSTODEVFS(ap->a_vp->v_mount);
|
||||
lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
|
||||
lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
|
||||
devfs_populate(dmp);
|
||||
error = devfs_rules_ioctl(dmp, ap->a_command, ap->a_data, ap->a_td);
|
||||
lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
|
||||
error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data,
|
||||
ap->a_td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_rread(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
devfs_rread(struct vop_read_args *ap)
|
||||
{
|
||||
|
||||
if (ap->a_vp->v_type != VDIR)
|
||||
@ -1247,13 +992,7 @@ devfs_rread(ap)
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
devfs_setattr(struct vop_setattr_args *ap)
|
||||
{
|
||||
struct devfs_dirent *de;
|
||||
struct vattr *vap;
|
||||
@ -1339,13 +1078,7 @@ devfs_setattr(ap)
|
||||
|
||||
#ifdef MAC
|
||||
static int
|
||||
devfs_setlabel(ap)
|
||||
struct vop_setlabel_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct mac *a_label;
|
||||
struct ucred *a_cred;
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
devfs_setlabel(struct vop_setlabel_args *ap)
|
||||
{
|
||||
struct vnode *vp;
|
||||
struct devfs_dirent *de;
|
||||
@ -1368,14 +1101,7 @@ devfs_stat_f(struct file *fp, struct stat *sb, struct ucred *cred, struct thread
|
||||
}
|
||||
|
||||
static int
|
||||
devfs_symlink(ap)
|
||||
struct vop_symlink_args /* {
|
||||
struct vnode *a_dvp;
|
||||
struct vnode **a_vpp;
|
||||
struct componentname *a_cnp;
|
||||
struct vattr *a_vap;
|
||||
char *a_target;
|
||||
} */ *ap;
|
||||
devfs_symlink(struct vop_symlink_args *ap)
|
||||
{
|
||||
int i, error;
|
||||
struct devfs_dirent *dd;
|
||||
@ -1397,7 +1123,7 @@ devfs_symlink(ap)
|
||||
de->de_inode = dmp->dm_inode++;
|
||||
de->de_dirent->d_type = DT_LNK;
|
||||
i = strlen(ap->a_target) + 1;
|
||||
MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
|
||||
de->de_symlink = malloc(i, M_DEVFS, M_WAITOK);
|
||||
bcopy(ap->a_target, de->de_symlink, i);
|
||||
lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, td);
|
||||
#ifdef MAC
|
||||
@ -1417,7 +1143,6 @@ static int
|
||||
devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
|
||||
{
|
||||
struct cdev *dev;
|
||||
struct vnode *vp;
|
||||
int error, ioflag, resid;
|
||||
struct cdevsw *dsw;
|
||||
|
||||
@ -1425,7 +1150,6 @@ devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, s
|
||||
if (error)
|
||||
return (error);
|
||||
KASSERT(uio->uio_td == td, ("uio_td %p is not td %p", uio->uio_td, td));
|
||||
vp = fp->f_vnode;
|
||||
ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT | O_FSYNC);
|
||||
if (ioflag & O_DIRECT)
|
||||
ioflag |= IO_DIRECT;
|
||||
@ -1434,11 +1158,7 @@ devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, s
|
||||
|
||||
resid = uio->uio_resid;
|
||||
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_lock(&Giant);
|
||||
error = dsw->d_write(dev, uio, ioflag);
|
||||
if (dsw->d_flags & D_NEEDGIANT)
|
||||
mtx_unlock(&Giant);
|
||||
dev_relthread(dev);
|
||||
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
|
||||
vfs_timestamp(&dev->si_ctime);
|
||||
@ -1456,37 +1176,76 @@ dev2udev(struct cdev *x)
|
||||
{
|
||||
if (x == NULL)
|
||||
return (NODEV);
|
||||
return (x->si_inode ^ devfs_random());
|
||||
return (x->si_inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper sysctl for devname(3). We're given a struct cdev * and return
|
||||
* the name, if any, registered by the device driver.
|
||||
*/
|
||||
static int
|
||||
sysctl_devname(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
dev_t ud;
|
||||
struct cdev *dev, **dp;
|
||||
static struct fileops devfs_ops_f = {
|
||||
.fo_read = devfs_read_f,
|
||||
.fo_write = devfs_write_f,
|
||||
.fo_ioctl = devfs_ioctl_f,
|
||||
.fo_poll = devfs_poll_f,
|
||||
.fo_kqfilter = devfs_kqfilter_f,
|
||||
.fo_stat = devfs_stat_f,
|
||||
.fo_close = devfs_close_f,
|
||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
|
||||
};
|
||||
|
||||
error = SYSCTL_IN(req, &ud, sizeof (ud));
|
||||
if (error)
|
||||
return (error);
|
||||
if (ud == NODEV)
|
||||
return(EINVAL);
|
||||
dp = devfs_itod(ud ^ devfs_random());
|
||||
if (dp == NULL)
|
||||
return(ENOENT);
|
||||
dev = *dp;
|
||||
if (dev == NULL)
|
||||
return(ENOENT);
|
||||
return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1));
|
||||
return (error);
|
||||
}
|
||||
static struct vop_vector devfs_vnodeops = {
|
||||
.vop_default = &default_vnodeops,
|
||||
|
||||
SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
|
||||
NULL, 0, sysctl_devname, "", "devname(3) handler");
|
||||
.vop_access = devfs_access,
|
||||
.vop_getattr = devfs_getattr,
|
||||
.vop_ioctl = devfs_rioctl,
|
||||
.vop_lookup = devfs_lookup,
|
||||
.vop_mknod = devfs_mknod,
|
||||
.vop_pathconf = devfs_pathconf,
|
||||
.vop_read = devfs_rread,
|
||||
.vop_readdir = devfs_readdir,
|
||||
.vop_readlink = devfs_readlink,
|
||||
.vop_reclaim = devfs_reclaim,
|
||||
.vop_remove = devfs_remove,
|
||||
.vop_revoke = devfs_revoke,
|
||||
.vop_setattr = devfs_setattr,
|
||||
#ifdef MAC
|
||||
.vop_setlabel = devfs_setlabel,
|
||||
#endif
|
||||
.vop_symlink = devfs_symlink,
|
||||
};
|
||||
|
||||
static struct vop_vector devfs_specops = {
|
||||
.vop_default = &default_vnodeops,
|
||||
|
||||
.vop_access = devfs_access,
|
||||
.vop_advlock = devfs_advlock,
|
||||
.vop_bmap = VOP_PANIC,
|
||||
.vop_close = devfs_close,
|
||||
.vop_create = VOP_PANIC,
|
||||
.vop_fsync = devfs_fsync,
|
||||
.vop_getattr = devfs_getattr,
|
||||
.vop_lease = VOP_NULL,
|
||||
.vop_link = VOP_PANIC,
|
||||
.vop_mkdir = VOP_PANIC,
|
||||
.vop_mknod = VOP_PANIC,
|
||||
.vop_open = devfs_open,
|
||||
.vop_pathconf = devfs_pathconf,
|
||||
.vop_print = devfs_print,
|
||||
.vop_read = VOP_PANIC,
|
||||
.vop_readdir = VOP_PANIC,
|
||||
.vop_readlink = VOP_PANIC,
|
||||
.vop_reallocblks = VOP_PANIC,
|
||||
.vop_reclaim = devfs_reclaim,
|
||||
.vop_remove = devfs_remove,
|
||||
.vop_rename = VOP_PANIC,
|
||||
.vop_revoke = devfs_revoke,
|
||||
.vop_rmdir = VOP_PANIC,
|
||||
.vop_setattr = devfs_setattr,
|
||||
#ifdef MAC
|
||||
.vop_setlabel = devfs_setlabel,
|
||||
#endif
|
||||
.vop_strategy = VOP_PANIC,
|
||||
.vop_symlink = VOP_PANIC,
|
||||
.vop_write = VOP_PANIC,
|
||||
};
|
||||
|
||||
/*
|
||||
* Our calling convention to the device drivers used to be that we passed
|
||||
|
@ -45,9 +45,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/ucred.h>
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
|
||||
#include <fs/devfs/devfs_int.h>
|
||||
|
||||
/* Built at compile time from sys/conf/majors */
|
||||
static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
|
||||
|
||||
static struct mtx devmtx;
|
||||
static void freedev(struct cdev *dev);
|
||||
@ -232,6 +232,125 @@ no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
|
||||
|
||||
#define no_dump (dumper_t *)enodev
|
||||
|
||||
static int
|
||||
giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_open(dev, oflags, devtype, td);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_fdopen(struct cdev *dev, int oflags, struct thread *td, int fdidx)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_fdopen(dev, oflags, td, fdidx);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_close(dev, fflag, devtype, td);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static void
|
||||
giant_strategy(struct bio *bp)
|
||||
{
|
||||
|
||||
mtx_lock(&Giant);
|
||||
bp->bio_dev->si_devsw->d_gianttrick->
|
||||
d_strategy(bp);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_ioctl(dev, cmd, data, fflag, td);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_read(dev, uio, ioflag);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_write(dev, uio, ioflag);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_poll(struct cdev *dev, int events, struct thread *td)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_poll(dev, events, td);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_kqfilter(struct cdev *dev, struct knote *kn)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_kqfilter(dev, kn);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
retval = dev->si_devsw->d_gianttrick->
|
||||
d_mmap(dev, offset, paddr, nprot);
|
||||
mtx_unlock(&Giant);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* struct cdev * and u_dev_t primitives
|
||||
*/
|
||||
@ -324,14 +443,26 @@ umajor(dev_t dev)
|
||||
static void
|
||||
fini_cdevsw(struct cdevsw *devsw)
|
||||
{
|
||||
struct cdevsw *gt;
|
||||
|
||||
if (devsw->d_gianttrick != NULL) {
|
||||
gt = devsw->d_gianttrick;
|
||||
memcpy(devsw, gt, sizeof *devsw);
|
||||
free(gt, M_DEVT);
|
||||
devsw->d_gianttrick = NULL;
|
||||
}
|
||||
devsw->d_flags &= ~D_INIT;
|
||||
}
|
||||
|
||||
static void
|
||||
prep_cdevsw(struct cdevsw *devsw)
|
||||
{
|
||||
struct cdevsw *dsw2;
|
||||
|
||||
if (devsw->d_flags & D_NEEDGIANT)
|
||||
dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK);
|
||||
else
|
||||
dsw2 = NULL;
|
||||
dev_lock();
|
||||
|
||||
if (devsw->d_version != D_VERSION_01) {
|
||||
@ -358,16 +489,35 @@ prep_cdevsw(struct cdevsw *devsw)
|
||||
if (devsw->d_poll == NULL) devsw->d_poll = ttypoll;
|
||||
}
|
||||
|
||||
if (devsw->d_open == NULL) devsw->d_open = null_open;
|
||||
if (devsw->d_close == NULL) devsw->d_close = null_close;
|
||||
if (devsw->d_read == NULL) devsw->d_read = no_read;
|
||||
if (devsw->d_write == NULL) devsw->d_write = no_write;
|
||||
if (devsw->d_ioctl == NULL) devsw->d_ioctl = no_ioctl;
|
||||
if (devsw->d_poll == NULL) devsw->d_poll = no_poll;
|
||||
if (devsw->d_mmap == NULL) devsw->d_mmap = no_mmap;
|
||||
if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy;
|
||||
if (devsw->d_flags & D_NEEDGIANT) {
|
||||
if (devsw->d_gianttrick == NULL) {
|
||||
memcpy(dsw2, devsw, sizeof *dsw2);
|
||||
devsw->d_gianttrick = dsw2;
|
||||
} else
|
||||
free(dsw2, M_DEVT);
|
||||
}
|
||||
|
||||
#define FIXUP(member, noop, giant) \
|
||||
do { \
|
||||
if (devsw->member == NULL) { \
|
||||
devsw->member = noop; \
|
||||
} else if (devsw->d_flags & D_NEEDGIANT) \
|
||||
devsw->member = giant; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
FIXUP(d_open, null_open, giant_open);
|
||||
FIXUP(d_fdopen, NULL, giant_fdopen);
|
||||
FIXUP(d_close, null_close, giant_close);
|
||||
FIXUP(d_read, no_read, giant_read);
|
||||
FIXUP(d_write, no_write, giant_write);
|
||||
FIXUP(d_ioctl, no_ioctl, giant_ioctl);
|
||||
FIXUP(d_poll, no_poll, giant_poll);
|
||||
FIXUP(d_mmap, no_mmap, giant_mmap);
|
||||
FIXUP(d_strategy, no_strategy, giant_strategy);
|
||||
FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter);
|
||||
|
||||
if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
|
||||
if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter;
|
||||
|
||||
LIST_INIT(&devsw->d_devs);
|
||||
|
||||
@ -454,19 +604,6 @@ make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
|
||||
return (dev);
|
||||
}
|
||||
|
||||
int
|
||||
dev_named(struct cdev *pdev, const char *name)
|
||||
{
|
||||
struct cdev *cdev;
|
||||
|
||||
if (strcmp(devtoname(pdev), name) == 0)
|
||||
return (1);
|
||||
LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
|
||||
if (strcmp(devtoname(cdev), name) == 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dev_depends(struct cdev *pdev, struct cdev *cdev)
|
||||
{
|
||||
|
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/extattr.h>
|
||||
@ -3851,3 +3852,29 @@ filt_vfsvnode(struct knote *kn, long hint)
|
||||
}
|
||||
return (kn->kn_fflags != 0);
|
||||
}
|
||||
|
||||
int
|
||||
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (dp->d_reclen > ap->a_uio->uio_resid)
|
||||
return (ENAMETOOLONG);
|
||||
error = uiomove(dp, dp->d_reclen, ap->a_uio);
|
||||
if (error) {
|
||||
if (ap->a_ncookies != NULL) {
|
||||
if (ap->a_cookies != NULL)
|
||||
free(ap->a_cookies, M_TEMP);
|
||||
ap->a_cookies = NULL;
|
||||
*ap->a_ncookies = 0;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
if (ap->a_ncookies == NULL)
|
||||
return (0);
|
||||
*ap->a_cookies = realloc(*ap->a_cookies,
|
||||
(*ap->a_ncookies + 1) * sizeof(u_long), M_TEMP, M_WAITOK | M_ZERO);
|
||||
(*ap->a_cookies)[*ap->a_ncookies] = off;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -213,6 +213,7 @@ struct cdevsw {
|
||||
LIST_ENTRY(cdevsw) d_list;
|
||||
LIST_HEAD(, cdev) d_devs;
|
||||
int d_spare3;
|
||||
struct cdevsw *d_gianttrick;
|
||||
};
|
||||
|
||||
#define NUMCDEVSW 256
|
||||
@ -246,7 +247,6 @@ int count_dev(struct cdev *_dev);
|
||||
void destroy_dev(struct cdev *_dev);
|
||||
struct cdevsw *dev_refthread(struct cdev *_dev);
|
||||
void dev_relthread(struct cdev *_dev);
|
||||
int dev_named(struct cdev *_pdev, const char *_name);
|
||||
void dev_depends(struct cdev *_pdev, struct cdev *_cdev);
|
||||
void dev_ref(struct cdev *dev);
|
||||
void dev_refl(struct cdev *dev);
|
||||
@ -265,9 +265,6 @@ int unit2minor(int _unit);
|
||||
u_int minor2unit(u_int _minor);
|
||||
void setconf(void);
|
||||
|
||||
void devfs_create(struct cdev *dev);
|
||||
void devfs_destroy(struct cdev *dev);
|
||||
|
||||
#define UID_ROOT 0
|
||||
#define UID_BIN 3
|
||||
#define UID_UUCP 66
|
||||
|
@ -736,6 +736,8 @@ void vfs_hash_rehash(struct vnode *vp, u_int hash);
|
||||
void vfs_hash_remove(struct vnode *vp);
|
||||
|
||||
int vfs_kqfilter(struct vop_kqfilter_args *);
|
||||
struct dirent;
|
||||
int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user