From 051ea6d1a82f7323f6d47d8bfda129ef428e3929 Mon Sep 17 00:00:00 2001 From: phk Date: Sun, 18 Sep 2005 07:10:57 +0000 Subject: [PATCH] MFC: Various fixes for DEVFS, in particular "devfs ruleset already running". Approved by: re@ (scottl) --- sys/fs/devfs/devfs.h | 7 +- sys/fs/devfs/devfs_devs.c | 52 ++++- sys/fs/devfs/devfs_rule.c | 100 ++++---- sys/fs/devfs/devfs_vfsops.c | 1 - sys/fs/devfs/devfs_vnops.c | 455 +++++++++--------------------------- sys/kern/kern_conf.c | 185 +++++++++++++-- sys/kern/vfs_subr.c | 27 +++ sys/sys/conf.h | 5 +- sys/sys/vnode.h | 2 + 9 files changed, 384 insertions(+), 450 deletions(-) diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h index c8f107419ed..07912a9a0dc 100644 --- a/sys/fs/devfs/devfs.h +++ b/sys/fs/devfs/devfs.h @@ -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); diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 172a63c8902..77a514083e3 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -46,6 +46,7 @@ #include #include +#include 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); } /* diff --git a/sys/fs/devfs/devfs_rule.c b/sys/fs/devfs/devfs_rule.c index 5168efe6cc3..5e25f4eaead 100644 --- a/sys/fs/devfs/devfs_rule.c +++ b/sys/fs/devfs/devfs_rule.c @@ -71,8 +71,8 @@ #include #include #include -#include #include +#include #include @@ -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); } - diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c index b93f123f39a..307b4a28cea 100644 --- a/sys/fs/devfs/devfs_vfsops.c +++ b/sys/fs/devfs/devfs_vfsops.c @@ -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); diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index aafcd2616fc..6cf2f49b888 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -61,133 +61,16 @@ #include #include #include -#include #include #include #include #include -#include - -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 struct vop_vector devfs_vnodeops; +static struct vop_vector devfs_specops; +static struct fileops devfs_ops_f; +#include 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 diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 3c4ab29274f..a6fcf83ab14 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -45,9 +45,9 @@ __FBSDID("$FreeBSD$"); #include #include -static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); +#include -/* 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) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 7140aec6e50..a3538910459 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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); +} + diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 2dfa9561dee..1ceadc0eb20 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -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 diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 598062f05a8..3c84baf5442 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -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 */ -- 2.45.2