From 80a3cef87da5cdfc2416704a39bc2c419114cce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Sat, 29 Sep 2001 00:49:29 +0000 Subject: [PATCH] Pseudofs take 2: - Remove hardcoded uid, gid, mode from struct pfs_node; make pfs_getattr() smart enough to get it right most of the time, and allow for callbacks to handle the remaining cases. Rework the definition macros to match. - Add lots of (conditional) debugging output. - Fix a long-standing bug inherited from procfs: don't pretend to be a read-only file system. Instead, return EOPNOTSUPP for operations we truly can't support and allow others to fail silently. In particular, pfs_lookup() now treats CREATE as LOOKUP. This may need more work. - In pfs_lookup(), if the parent node is process-dependent, check that the process in question still exists. - Implement pfs_open() - its only current function is to check that the process opening the file can see the process it belongs to. - Finish adding support for writeable nodes. - Bump module version number. - Introduce lots of new bugs. --- sys/fs/pseudofs/pseudofs.c | 2 +- sys/fs/pseudofs/pseudofs.h | 56 +++++++---- sys/fs/pseudofs/pseudofs_vnops.c | 168 +++++++++++++++++++++++++------ 3 files changed, 171 insertions(+), 55 deletions(-) diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c index 45117ac44ea5..97a269e8234b 100644 --- a/sys/fs/pseudofs/pseudofs.c +++ b/sys/fs/pseudofs/pseudofs.c @@ -170,4 +170,4 @@ static moduledata_t pseudofs_data = { NULL }; DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST); -MODULE_VERSION(pseudofs, 1); +MODULE_VERSION(pseudofs, 2); diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h index a3e92863d7e4..4b2ec2a29829 100644 --- a/sys/fs/pseudofs/pseudofs.h +++ b/sys/fs/pseudofs/pseudofs.h @@ -64,6 +64,9 @@ struct pfs_info; struct pfs_node; struct pfs_bitmap; +/* + * Filler callback + */ #define PFS_FILL_ARGS \ struct thread *td, struct proc *p, struct pfs_node *pn, \ struct sbuf *sb, struct uio *uio @@ -71,6 +74,17 @@ struct pfs_bitmap; int name(PFS_FILL_ARGS); typedef int (*pfs_fill_t)(PFS_FILL_ARGS); +/* + * Attribute callback + */ +struct vattr; +#define PFS_ATTR_ARGS \ + struct thread *td, struct proc *p, struct pfs_node *pn, \ + struct vattr *vap +#define PFS_ATTR_PROTO(name) \ + int name(PFS_ATTR_ARGS); +typedef int (*pfs_attr_t)(PFS_ATTR_ARGS); + struct pfs_bitmap; /* opaque */ /* @@ -91,41 +105,39 @@ struct pfs_info { struct pfs_node { char pn_name[PFS_NAMELEN]; pfs_type_t pn_type; - int pn_flags; - uid_t pn_uid; - gid_t pn_gid; - mode_t pn_mode; union { - void *_pn_data; + void *_pn_dummy; pfs_fill_t _pn_func; struct pfs_node *_pn_nodes; } u1; -#define pn_data u1._pn_data #define pn_func u1._pn_func #define pn_nodes u1._pn_nodes + pfs_attr_t pn_attr; + void *pn_data; + int pn_flags; /* members below this line aren't initialized */ struct pfs_node *pn_parent; u_int32_t pn_fileno; }; -#define PFS_NODE(name, type, flags, uid, gid, mode, data) \ - { (name), (type), (flags), (uid), (gid), (mode), { (data) } } -#define PFS_DIR(name, flags, uid, gid, mode, nodes) \ - PFS_NODE(name, pfstype_dir, flags, uid, gid, mode, nodes) +#define PFS_NODE(name, type, fill, attr, data, flags) \ + { (name), (type), { (fill) }, (attr), (data), (flags) } +#define PFS_DIR(name, nodes, attr, data, flags) \ + PFS_NODE(name, pfstype_dir, nodes, attr, data, flags) #define PFS_ROOT(nodes) \ - PFS_NODE("/", pfstype_root, 0, 0, 0, 0555, nodes) + PFS_NODE("/", pfstype_root, nodes, NULL, NULL, 0) #define PFS_THIS \ - PFS_NODE(".", pfstype_this, 0, 0, 0, 0, NULL) + PFS_NODE(".", pfstype_this, NULL, NULL, NULL, 0) #define PFS_PARENT \ - PFS_NODE("..", pfstype_parent, 0, 0, 0, 0, NULL) -#define PFS_FILE(name, flags, uid, gid, mode, func) \ - PFS_NODE(name, pfstype_file, flags, uid, gid, mode, func) -#define PFS_SYMLINK(name, flags, uid, gid, mode, func) \ - PFS_NODE(name, pfstype_symlink, flags, uid, gid, mode, func) -#define PFS_PROCDIR(flags, uid, gid, mode, nodes) \ - PFS_NODE("", pfstype_procdir, flags, uid, gid, mode, nodes) + PFS_NODE("..", pfstype_parent, NULL, NULL, NULL, 0) +#define PFS_FILE(name, func, attr, data, flags) \ + PFS_NODE(name, pfstype_file, func, attr, data, flags) +#define PFS_SYMLINK(name, func, attr, data, flags) \ + PFS_NODE(name, pfstype_symlink, func, attr, data, flags) +#define PFS_PROCDIR(nodes, attr, data, flags) \ + PFS_NODE("", pfstype_procdir, nodes, attr, data, flags) #define PFS_LASTNODE \ - PFS_NODE("", pfstype_none, 0, 0, 0, 0, NULL) + PFS_NODE("", pfstype_none, NULL, NULL, NULL, 0) /* * VFS interface @@ -154,7 +166,7 @@ static struct pfs_info name##_info = { \ static int \ _##name##_mount(struct mount *mp, char *path, caddr_t data, \ struct nameidata *ndp, struct thread *td) { \ - return pfs_mount(&name##_info, mp, path, data, ndp, td); \ + return pfs_mount(&name##_info, mp, path, data, ndp, td); \ } \ \ static int \ @@ -185,6 +197,6 @@ static struct vfsops name##_vfsops = { \ }; \ VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC); \ MODULE_VERSION(name, version); \ -MODULE_DEPEND(name, pseudofs, 1, 1, 1); +MODULE_DEPEND(name, pseudofs, 2, 2, 2); #endif diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index e349c67c994e..6d2b8baee0e1 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -46,6 +46,25 @@ #include #include +#if 0 +#define PFS_TRACE(foo) \ + do { \ + printf("pseudofs: %s(): ", __FUNCTION__); \ + printf foo ; \ + printf("\n"); \ + } while (0) +#define PFS_RETURN(err) \ + do { \ + printf("pseudofs: %s(): returning %d\n", __FUNCTION__, err); \ + return (err); \ + } while (0) +#else +#define PFS_TRACE(foo) \ + do { /* nothing */ } while (0) +#define PFS_RETURN(err) \ + return (err) +#endif + /* * Verify permissions */ @@ -53,9 +72,13 @@ static int pfs_access(struct vop_access_args *va) { struct vnode *vn = va->a_vp; + struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; + struct pfs_node *pn = pvd->pvd_pn; struct vattr vattr; int error; + PFS_TRACE((pn->pn_name)); + error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td); if (error) return (error); @@ -83,10 +106,13 @@ pfs_getattr(struct vop_getattr_args *va) struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; struct pfs_node *pn = pvd->pvd_pn; struct vattr *vap = va->a_vap; + struct proc *proc; + int error = 0; + PFS_TRACE((pn->pn_name)); + VATTR_NULL(vap); vap->va_type = vn->v_type; - vap->va_mode = pn->pn_mode; vap->va_fileid = pn->pn_fileno; vap->va_flags = 0; vap->va_blocksize = PAGE_SIZE; @@ -95,10 +121,40 @@ pfs_getattr(struct vop_getattr_args *va) vap->va_nlink = 1; nanotime(&vap->va_ctime); vap->va_atime = vap->va_mtime = vap->va_ctime; - vap->va_uid = pn->pn_uid; - vap->va_gid = pn->pn_gid; - return (0); + switch (pn->pn_type) { + case pfstype_procdir: + /* XXX needs p_cansee */ + case pfstype_root: + case pfstype_dir: + vap->va_mode = 0555; + break; + case pfstype_file: + vap->va_mode = 0444; + break; + case pfstype_symlink: + vap->va_mode = 0777; + break; + default: + printf("shouldn't be here!\n"); + vap->va_mode = 0; + break; + } + + if (pvd->pvd_pid != NO_PID) { + if ((proc = pfind(pvd->pvd_pid)) == NULL) + PFS_RETURN (ENOENT); + vap->va_uid = proc->p_ucred->cr_ruid; + vap->va_gid = proc->p_ucred->cr_rgid; + if (pn->pn_attr != NULL) + error = (pn->pn_attr)(curthread, proc, pn, vap); + PROC_UNLOCK(proc); + } else { + vap->va_uid = 0; + vap->va_gid = 0; + } + + PFS_RETURN (error); } /* @@ -113,20 +169,34 @@ pfs_lookup(struct vop_lookup_args *va) struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; struct pfs_node *pd = pvd->pvd_pn; struct pfs_node *pn, *pdn = NULL; + struct proc *proc; pid_t pid = pvd->pvd_pid; char *pname; int error, i, namelen; - if (vn->v_type != VDIR) - return (ENOTDIR); + PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); - /* don't support CREATE, RENAME or DELETE */ - if (cnp->cn_nameiop != LOOKUP) - return (EROFS); + if (vn->v_type != VDIR) + PFS_RETURN (ENOTDIR); + + /* + * Don't support DELETE or RENAME. CREATE is supported so + * that O_CREAT will work, but the lookup will still fail if + * the file does not exist. + */ + if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) + return (EOPNOTSUPP); - /* shortcut */ + /* shortcut: check if the name is too long */ if (cnp->cn_namelen >= PFS_NAMELEN) - return (ENOENT); + PFS_RETURN (ENOENT); + + /* check that owner process exists */ + if (pvd->pvd_pid != NO_PID) { + if ((proc = pfind(pvd->pvd_pid)) == NULL) + PFS_RETURN (ENOENT); + PROC_UNLOCK(proc); + } /* self */ namelen = cnp->cn_namelen; @@ -141,7 +211,7 @@ pfs_lookup(struct vop_lookup_args *va) /* parent */ if (cnp->cn_flags & ISDOTDOT) { if (pd->pn_type == pfstype_root) - return (EIO); + PFS_RETURN (EIO); KASSERT(pd->pn_parent, ("non-root directory has no parent")); /* * This one is tricky. Descendents of procdir nodes @@ -154,7 +224,10 @@ pfs_lookup(struct vop_lookup_args *va) */ if (pd->pn_type == pfstype_procdir) pid = NO_PID; - return pfs_vncache_alloc(vn->v_mount, vpp, pd->pn_parent, pid); + error = pfs_vncache_alloc(vn->v_mount, vpp, pd->pn_parent, pid); + if (error) + PFS_RETURN (error); + goto got_vnode; } /* named node */ @@ -181,11 +254,11 @@ pfs_lookup(struct vop_lookup_args *va) pn->pn_parent = pd; error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid); if (error) - return error; + PFS_RETURN (error); got_vnode: if (cnp->cn_flags & MAKEENTRY) cache_enter(vn, *vpp, cnp); - return (0); + PFS_RETURN (0); } /* @@ -194,8 +267,24 @@ pfs_lookup(struct vop_lookup_args *va) static int pfs_open(struct vop_open_args *va) { - /* XXX */ - return (0); + struct vnode *vn = va->a_vp; + struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; + struct pfs_node *pn = pvd->pvd_pn; + struct proc *proc; + int error; + + PFS_TRACE((pn->pn_name)); + + error = 0; + if (pvd->pvd_pid != NO_PID) { + if ((proc = pfind(pvd->pvd_pid)) == NULL) + return (ENOENT); + if (p_cansee(va->a_td->td_proc, proc) != 0) + error = ENOENT; + PROC_UNLOCK(proc); + } + + return (error); } /* @@ -213,6 +302,8 @@ pfs_read(struct vop_read_args *va) char *ps; int error, xlen; + PFS_TRACE((pn->pn_name)); + if (vn->v_type != VREG) return (EINVAL); @@ -305,6 +396,8 @@ pfs_readdir(struct vop_readdir_args *va) off_t offset; int error, i, resid; + PFS_TRACE((pd->pn_name)); + if (vn->v_type != VDIR) return (ENOTDIR); uio = va->a_uio; @@ -389,6 +482,8 @@ pfs_readlink(struct vop_readlink_args *va) struct sbuf sb; int error, xlen; + PFS_TRACE((pn->pn_name)); + if (vn->v_type != VLNK) return (EINVAL); @@ -454,8 +549,11 @@ pfs_write(struct vop_read_args *va) struct pfs_node *pn = pvd->pvd_pn; struct uio *uio = va->a_uio; struct proc *proc = NULL; + struct sbuf sb; int error; + PFS_TRACE((pn->pn_name)); + if (vn->v_type != VREG) return (EINVAL); @@ -475,19 +573,25 @@ pfs_write(struct vop_read_args *va) PRELE(proc); return (error); } + + sbuf_uionew(&sb, uio, &error); + if (error) + return (error); - /* - * We currently don't support non-raw writers. It's not very - * hard to do, but it probably requires further changes to the - * sbuf API. - */ - return (EIO); + error = (pn->pn_func)(curthread, proc, pn, &sb, uio); + + if (proc != NULL) + PRELE(proc); + + sbuf_delete(&sb); + return (error); } /* * Dummy operations */ -static int pfs_erofs(void *va) { return (EROFS); } +static int pfs_badop(void *va) { return (EOPNOTSUPP); } #if 0 +static int pfs_erofs(void *va) { return (EROFS); } static int pfs_null(void *va) { return (0); } #endif @@ -499,21 +603,22 @@ static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vop_defaultop }, { &vop_access_desc, (vop_t *)pfs_access }, { &vop_close_desc, (vop_t *)pfs_close }, - { &vop_create_desc, (vop_t *)pfs_erofs }, + { &vop_create_desc, (vop_t *)pfs_badop }, { &vop_getattr_desc, (vop_t *)pfs_getattr }, - { &vop_link_desc, (vop_t *)pfs_erofs }, + { &vop_link_desc, (vop_t *)pfs_badop }, { &vop_lookup_desc, (vop_t *)pfs_lookup }, - { &vop_mkdir_desc, (vop_t *)pfs_erofs }, + { &vop_mkdir_desc, (vop_t *)pfs_badop }, + { &vop_mknod_desc, (vop_t *)pfs_badop }, { &vop_open_desc, (vop_t *)pfs_open }, { &vop_read_desc, (vop_t *)pfs_read }, { &vop_readdir_desc, (vop_t *)pfs_readdir }, { &vop_readlink_desc, (vop_t *)pfs_readlink }, { &vop_reclaim_desc, (vop_t *)pfs_reclaim }, - { &vop_remove_desc, (vop_t *)pfs_erofs }, - { &vop_rename_desc, (vop_t *)pfs_erofs }, - { &vop_rmdir_desc, (vop_t *)pfs_erofs }, + { &vop_remove_desc, (vop_t *)pfs_badop }, + { &vop_rename_desc, (vop_t *)pfs_badop }, + { &vop_rmdir_desc, (vop_t *)pfs_badop }, { &vop_setattr_desc, (vop_t *)pfs_setattr }, - { &vop_symlink_desc, (vop_t *)pfs_erofs }, + { &vop_symlink_desc, (vop_t *)pfs_badop }, { &vop_write_desc, (vop_t *)pfs_write }, /* XXX I've probably forgotten a few that need pfs_erofs */ { NULL, (vop_t *)NULL } @@ -523,4 +628,3 @@ static struct vnodeopv_desc pfs_vnodeop_opv_desc = { &pfs_vnodeop_p, pfs_vnodeop_entries }; VNODEOP_SET(pfs_vnodeop_opv_desc); -