Hello,

        I've made some fixes in the fs layer of new devfs. First version
of this patch was passed via Poul and new version includes parts of his
suggestions.

        Here is a brief decription of the patch:

Rename de_dir to de_parent with appropritate code changes.
Implement proper logic and locking in the devfs_lookup().
Fix behaviour for '.' and '..' directories with corresponding changes
in the devfs_readdir().
Implement devfs_read() operation for directories.
Return proper mount owner in the devfs_statfs().
Fix panic related to the incorrect handling of root vnode.
Few cosmetic changes as well.

        Code is still not SMP safe.

--
Boris Popov
http://www.butya.kz/~bp/
Index: devfs.h
===================================================================
RCS file: /home/ncvs/src/sys/fs/devfs/devfs.h,v
retrieving revision 1.2
diff -u -r1.2 devfs.h
--- devfs.h     2000/08/24 15:36:47     1.2
+++ devfs.h     2000/08/26 12:28:52
@@ -48,10 +48,12 @@
 #define        DE_ORPHAN       0x1
 #define        DE_DOT          0x2
 #define        DE_DOTDOT       0x4
-       struct dirent *de_dirent;
+       int     de_type;
+       char *  de_name;
+       int     de_namelen;
        TAILQ_ENTRY(devfs_dirent) de_list;
        TAILQ_HEAD(, devfs_dirent) de_dlist;
-       struct devfs_dirent *de_dir;
+       struct devfs_dirent *de_parent;
        int     de_links;
        mode_t  de_mode;
        uid_t   de_uid;
@@ -68,7 +70,6 @@
 };
 
 struct devfs_mount {
-       struct vnode    *dm_root;       /* Root node */
        struct devfs_dirent *dm_rootdir;
        struct devfs_dirent *dm_basedir;
        unsigned        dm_generation;
@@ -84,6 +85,7 @@
 
 
 #define VFSTODEVFS(mp) ((struct devfs_mount *)((mp)->mnt_data))
+#define VNTODEVFS(vp)  ((struct devfs_dirent *)(vp)->v_data)
 
 extern vop_t **devfs_vnodeop_p;
 extern vop_t **devfs_specop_p;
@@ -93,6 +95,9 @@
 void devfs_purge __P((struct devfs_dirent *dd));
 struct devfs_dirent * devfs_vmkdir __P((char *name, int namelen,
     struct devfs_dirent *dotdot));
+int devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp,
+       struct proc *proc);
+
 #endif /* DEVFS_INTERN */
 
 typedef void (*devfs_clone_fn) __P((void *arg, char *name, int namelen, dev_t 
*result));
Index: devfs_devs.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/devfs/devfs_devs.c,v
retrieving revision 1.3
diff -u -r1.3 devfs_devs.c
--- devfs_devs.c        2000/08/24 15:36:47     1.3
+++ devfs_devs.c        2000/08/26 11:49:49
@@ -46,16 +46,13 @@
 {
        int i;
        struct devfs_dirent *de;
-       struct dirent d;
 
-       d.d_namlen = namelen;
-       i = sizeof (*de) + GENERIC_DIRSIZ(&d);
+       i = sizeof (*de) + namelen + 1;
        MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK);
        bzero(de, i);
-       de->de_dirent = (struct dirent *)(de + 1);
-       de->de_dirent->d_namlen = namelen;
-       de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
-       bcopy(name, de->de_dirent->d_name, namelen + 1);
+       de->de_name = (char *)(de + 1);
+       de->de_namelen = namelen;
+       bcopy(name, de->de_name, namelen);
        nanotime(&de->de_ctime);
        de->de_mtime = de->de_atime = de->de_ctime;
        de->de_links = 1;
@@ -63,36 +60,23 @@
 }
 
 struct devfs_dirent *
-devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot)
+devfs_vmkdir(char *name, int namelen, struct devfs_dirent *parent)
 {
-       struct devfs_dirent *dd;
        struct devfs_dirent *de;
 
-       dd = devfs_newdirent(name, namelen);
+       de = devfs_newdirent(name, namelen);
 
-       TAILQ_INIT(&dd->de_dlist);
+       TAILQ_INIT(&de->de_dlist);
 
-       dd->de_dirent->d_type = DT_DIR;
-       dd->de_mode = 0755;
-       dd->de_links = 2;
-       dd->de_dir = dd;
-
-       de = devfs_newdirent(".", 1);
-       de->de_dirent->d_type = DT_DIR;
-       de->de_dir = dd;
-       de->de_flags |= DE_DOT;
-       TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
-
-       de = devfs_newdirent("..", 2);
-       de->de_dirent->d_type = DT_DIR;
-       if (dotdot == NULL)
-               de->de_dir = dd;
-       else
-               de->de_dir = dotdot;
-       de->de_flags |= DE_DOTDOT;
-       TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
+       de->de_type = DT_DIR;
+       de->de_mode = 0755;
+       de->de_links = 2;
 
-       return (dd);
+       if (parent) {
+               de->de_parent = parent;
+               TAILQ_INSERT_TAIL(&parent->de_dlist, de, de_list);
+       }
+       return (de);
 }
 
 static void
@@ -125,7 +109,6 @@
        FREE(dd, M_DEVFS);
 }
 
-
 int
 devfs_populate(struct devfs_mount *dm)
 {
@@ -145,7 +128,7 @@
                                continue;
                        }
                        if (dev == NULL && de != NULL) {
-                               dd = de->de_dir;
+                               dd = de->de_parent;
                                dm->dm_dirent[i] = NULL;
                                TAILQ_REMOVE(&dd->de_dlist, de, de_list);
                                if (de->de_vnode) {
@@ -166,9 +149,9 @@
                                continue;
                        if (*q == '/') {
                                TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
-                                       if (de->de_dirent->d_namlen != q - s)
+                                       if (de->de_namelen != q - s)
                                                continue;
-                                       if (bcmp(de->de_dirent->d_name, s, q - s))
+                                       if (bcmp(de->de_name, s, q - s))
                                                continue;
                                        goto fdir;
                                }
@@ -187,7 +170,7 @@
                                de->de_uid = 0;
                                de->de_gid = 0;
                                de->de_mode = 0666;
-                               de->de_dirent->d_type = DT_LNK;
+                               de->de_type = DT_LNK;
                                pdev = dev->si_drv1;
                                j = strlen(pdev->si_name) + 1;
                                MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
@@ -197,7 +180,7 @@
                                de->de_uid = dev->si_uid;
                                de->de_gid = dev->si_gid;
                                de->de_mode = dev->si_mode;
-                               de->de_dirent->d_type = DT_CHR;
+                               de->de_type = DT_CHR;
                        }
                        dm->dm_dirent[i] = de;
                        TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
Index: devfs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/devfs/devfs_vfsops.c,v
retrieving revision 1.3
diff -u -r1.3 devfs_vfsops.c
--- devfs_vfsops.c      2000/08/24 15:36:47     1.3
+++ devfs_vfsops.c      2000/08/26 11:49:49
@@ -79,30 +79,23 @@
                return (EOPNOTSUPP);
 
        MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), M_DEVFS, 
M_WAITOK);
-
        bzero(fmp, sizeof(*fmp));
 
-       error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &rvp);
-       if (error) {
-               FREE(fmp, M_DEVFS);
-               return (error);
-       }
-
-       vhold(rvp);
-       rvp->v_type = VDIR;
-       rvp->v_flag |= VROOT;
        mp->mnt_flag |= MNT_LOCAL;
        mp->mnt_data = (qaddr_t) fmp;
        vfs_getnewfsid(mp);
 
        fmp->dm_inode = NDEVINO;
-       fmp->dm_root = rvp;
 
        fmp->dm_rootdir = devfs_vmkdir("(root)", 6, NULL);
        fmp->dm_rootdir->de_inode = 2;
-       rvp->v_data = fmp->dm_rootdir;
-
        fmp->dm_basedir = fmp->dm_rootdir;
+       error = devfs_root(mp, &rvp);
+       if (error) {
+               FREE(fmp, M_DEVFS);
+               return error;
+       }
+       VOP_UNLOCK(rvp, 0, p);
 
        if (path != NULL) {
                (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
@@ -127,13 +120,15 @@
 {
        int error;
        int flags = 0;
-       struct vnode *rootvp = VFSTODEVFS(mp)->dm_root;
-       struct devfs_mount *fmp;
+       struct devfs_mount *fmp = VFSTODEVFS(mp);
+       struct vnode *rootvp;
 
-       fmp = (struct devfs_mount*) mp->mnt_data;
        if (mntflags & MNT_FORCE)
                flags |= FORCECLOSE;
 
+       error = VFS_ROOT(mp, &rootvp);
+       if (error)
+               return (error);
        /*
         * Clear out buffer cache.  I don't think we
         * ever get anything cached at this level at the
@@ -146,6 +141,7 @@
        if (error)
                return (error);
 
+       vput(rootvp);
        /*
         * Release reference on underlying root vnode
         */
@@ -157,8 +153,8 @@
        /*
         * Finally, throw away the devfs_mount structure
         */
-       free(mp->mnt_data, M_DEVFS);
-       mp->mnt_data = 0;
+       mp->mnt_data = (qaddr_t)0;
+       free(fmp, M_DEVFS);
        return 0;
 }
 
@@ -167,15 +163,18 @@
        struct mount *mp;
        struct vnode **vpp;
 {
+       struct devfs_mount *dmp = VFSTODEVFS(mp);
        struct proc *p = curproc;       /* XXX */
        struct vnode *vp;
+       int error;
 
        /*
         * Return locked reference to root.
         */
-       vp = VFSTODEVFS(mp)->dm_root;
-       VREF(vp);
-       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+       error = devfs_allocv(dmp->dm_rootdir, mp, &vp, p);
+       if (error)
+               return error;
+       vp->v_flag |= VROOT;
        *vpp = vp;
        return (0);
 }
@@ -197,6 +196,7 @@
        sbp->f_ffree = 0;
        if (sbp != &mp->mnt_stat) {
                sbp->f_type = mp->mnt_vfc->vfc_typenum;
+               sbp->f_owner = mp->mnt_stat.f_owner;    /* user that mounted the 
+filesystem */
                bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
                bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
                bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
Index: devfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/devfs/devfs_vnops.c,v
retrieving revision 1.3
diff -u -r1.3 devfs_vnops.c
--- devfs_vnops.c       2000/08/24 15:36:47     1.3
+++ devfs_vnops.c       2000/08/26 12:29:22
@@ -53,7 +53,7 @@
 #include <fs/devfs/devfs.h>
 
 #define KSTRING        256             /* Largest I/O available via this filesystem 
*/
-#define        UIO_MX 32
+#define        DE_SIZE (sizeof(struct dirent))
 
 static int     devfs_access __P((struct vop_access_args *ap));
 static int     devfs_badop __P((void));
@@ -69,16 +69,18 @@
 static int     devfs_symlink __P((struct vop_symlink_args *ap));
 
 
-static int
-devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct 
proc *p)
+int
+devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp,
+       struct proc *proc)
 {
-       int error;
+       struct proc *p = proc ? proc : curproc; /* XXX */
        struct vnode *vp;
+       int error;
 
 loop:
        vp = de->de_vnode;
        if (vp != NULL) {
-               if (vget(vp, 0, p ? p : curproc))
+               if (vget(vp, LK_EXCLUSIVE, p))
                        goto loop;
                *vpp = vp;
                return (0);
@@ -89,13 +91,13 @@
                return (error);
        }
 
-       if (de->de_dirent->d_type == DT_CHR) {
+       if (de->de_type == DT_CHR) {
                vp->v_type = VCHR;
                vp = addaliasu(vp, devfs_inot[de->de_inode]->si_udev);
                vp->v_op = devfs_specop_p;
-       } else if (de->de_dirent->d_type == DT_DIR) {
+       } else if (de->de_type == DT_DIR) {
                vp->v_type = VDIR;
-       } else if (de->de_dirent->d_type == DT_LNK) {
+       } else if (de->de_type == DT_LNK) {
                vp->v_type = VLNK;
        } else {
                vp->v_type = VBAD;
@@ -103,9 +105,29 @@
        vp->v_data = de;
        de->de_vnode = vp;
        vhold(vp);
+       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
        *vpp = vp;
        return (0);
 }
+
+static int
+devfs_de_lookup(struct vnode *dvp, const char *name, int namelen,
+       struct devfs_dirent **depp)
+{
+       struct devfs_dirent *dd, *de;
+
+       devfs_populate(VFSTODEVFS(dvp->v_mount));
+       dd = VNTODEVFS(dvp);
+       TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
+               if (namelen != de->de_namelen ||
+                   bcmp(name, de->de_name, namelen) != 0)
+                       continue;
+               *depp = de;
+               return 0;
+       }
+       return ENOENT;
+}
+
 /*
  * vp is the current namei directory
  * ndp is the name to locate in that directory...
@@ -121,47 +143,67 @@
        struct componentname *cnp = ap->a_cnp;
        struct vnode **vpp = ap->a_vpp;
        struct vnode *dvp = ap->a_dvp;
-       char *pname = cnp->cn_nameptr;
+       char *name = cnp->cn_nameptr;
        struct proc *p = cnp->cn_proc;
        struct devfs_dirent *dd;
        struct devfs_dirent *de;
        struct devfs_mount *dmp;
        dev_t cdev;
-       int error, cloned, i;
        char specname[SPECNAMELEN + 1];
+       int flags = cnp->cn_flags;
+       int isdotdot = flags & ISDOTDOT;
+       int namelen = cnp->cn_namelen;
+       int nameiop = cnp->cn_nameiop;
+       int lockparent, wantparent, error, islastcn, i;
 
        *vpp = NULLVP;
 
-#if 0
-       error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
+       if (dvp->v_type != VDIR)
+               return ENOTDIR;
+
+       if (isdotdot && (dvp->v_flag & VROOT))
+               return EIO;
+
+       error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
        if (error)
                return (error);
-#endif
+
+       if (nameiop == RENAME)
+               return EOPNOTSUPP;
 
-       VOP_UNLOCK(dvp, 0, p);
-       if (cnp->cn_namelen == 1 && *pname == '.') {
+       if (namelen == 1 && name[0] == '.') {
+               if (nameiop != LOOKUP)
+                       return EINVAL;
                *vpp = dvp;
                VREF(dvp);
-               vn_lock(dvp, LK_SHARED | LK_RETRY, p);
                return (0);
        }
-
-       cloned = 0;
-
-       dmp = VFSTODEVFS(dvp->v_mount);
-again:
-
-       devfs_populate(dmp);
-       dd = dvp->v_data;
-       TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
-               if (cnp->cn_namelen != de->de_dirent->d_namlen)
-                       continue;
-               if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 
de->de_dirent->d_namlen) != 0)
-                       continue;
-               goto found;
+       dd = VNTODEVFS(dvp);
+       islastcn = flags & ISLASTCN;
+       lockparent = flags & LOCKPARENT;
+       wantparent = flags & (LOCKPARENT | WANTPARENT);
+
+       if (isdotdot) {
+               if (nameiop != LOOKUP)
+                       return EINVAL;
+               VOP_UNLOCK(dvp, 0, p);
+               de = dd->de_parent;
+               error = devfs_allocv(de, dvp->v_mount, vpp, p);
+               if (error) {
+                       vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+                       return error;
+               }
+               if (lockparent && islastcn &&
+                   (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
+                       vput(*vpp);
+                       return error;
+               }
+               return 0;
        }
 
-       if (!cloned) {
+       dmp = VFSTODEVFS(dvp->v_mount);
+       error = devfs_de_lookup(dvp, name, namelen, &de);
+       if (error) {
                /*
                 * OK, we didn't have an entry for the name we were asked for
                 * so we try to see if anybody can create it on demand.
@@ -171,24 +213,21 @@
                 */
                i = SPECNAMELEN;
                specname[i] = '\0';
-               i -= cnp->cn_namelen;
+               i -= namelen;
                if (i < 0)
                         goto noclone;
-               bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen);
+               bcopy(name, specname + i, namelen);
                de = dd;
-               while (de != dmp->dm_basedir) {
+               while (de->de_parent) {
                        i--;
                        if (i < 0)
                                 goto noclone;
                        specname[i] = '/';
-                       i -= de->de_dirent->d_namlen;
+                       i -= de->de_namelen;
                        if (i < 0)
                                 goto noclone;
-                       bcopy(de->de_dirent->d_name, specname + i,
-                           de->de_dirent->d_namlen);
-                       de = TAILQ_FIRST(&de->de_dlist);        /* "." */
-                       de = TAILQ_NEXT(de, de_list);           /* ".." */
-                       de = de->de_dir;
+                       bcopy(de->de_name, specname + i, de->de_namelen);
+                       de = de->de_parent;
                }
 
 #if 0
@@ -201,47 +240,44 @@
                printf("cloned %s -> %p %s\n", specname + i, cdev,
                    cdev == NODEV ? "NODEV" : cdev->si_name);
 #endif
-               if (cdev != NODEV) {
-                       cloned = 1;
-                       goto again;
-               }
+               if (cdev != NODEV)
+                       error = devfs_de_lookup(dvp, name, namelen, &de);
        }
-
 noclone:
-       /* No luck, too bad. */
-
-       if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
-           (cnp->cn_flags & ISLASTCN)) {
-               cnp->cn_flags |= SAVENAME;
-               if (!(cnp->cn_flags & LOCKPARENT))
-                       VOP_UNLOCK(dvp, 0, p);
-               return (EJUSTRETURN);
-       } else {
-               vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+       if (error) {
+               /*
+                * No valid entry was found
+                */
+               if ((nameiop == CREATE || nameiop == RENAME) &&
+                   wantparent && islastcn) {
+                       cnp->cn_flags |= SAVENAME;
+                       if (!lockparent)
+                               VOP_UNLOCK(dvp, 0, p);
+                       return (EJUSTRETURN);
+               }
                return (ENOENT);
        }
-
 
-found:
-
-       error = devfs_allocv(de, dvp->v_mount, vpp, p);
-       if (error != 0) {
-               vn_lock(dvp, LK_SHARED | LK_RETRY, p);
-               return (error);
-       }
-       if ((cnp->cn_nameiop == DELETE) && (cnp->cn_flags & ISLASTCN)) {
+       if (nameiop == DELETE && islastcn) {
+               error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
+               if (error)
+                       return (error);
                if (*vpp == dvp) {
                        VREF(dvp);
                        *vpp = dvp;
                        return (0);
                }
-               VREF(*vpp);
-               if (!(cnp->cn_flags & LOCKPARENT))
+               error = devfs_allocv(de, dvp->v_mount, vpp, p);
+               if (error)
+                       return (error);
+               if (!lockparent)
                        VOP_UNLOCK(dvp, 0, p);
                return (0);
        }
-       vn_lock(*vpp, LK_SHARED | LK_RETRY, p);
-       if (!(cnp->cn_flags & LOCKPARENT))
+       error = devfs_allocv(de, dvp->v_mount, vpp, p);
+       if (error)
+               return error;
+       if (!lockparent || !islastcn)
                VOP_UNLOCK(dvp, 0, p);
        return (0);
 }
@@ -256,11 +292,7 @@
        } */ *ap;
 {
        struct vnode *vp = ap->a_vp;
-       struct devfs_dirent *de;
-
-       de = vp->v_data;
-       if (vp->v_type == VDIR)
-               de = de->de_dir;
+       struct devfs_dirent *de = VNTODEVFS(vp);
 
        return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
            ap->a_mode, ap->a_cred));
@@ -277,13 +309,10 @@
 {
        struct vnode *vp = ap->a_vp;
        struct vattr *vap = ap->a_vap;
+       struct devfs_dirent *de = VNTODEVFS(vp);
        int error = 0;
-       struct devfs_dirent *de;
        dev_t dev;
 
-       de = vp->v_data;
-       if (vp->v_type == VDIR) 
-               de = de->de_dir;
        bzero((caddr_t) vap, sizeof(*vap));
        vattr_null(vap);
        vap->va_uid = de->de_uid;
@@ -308,11 +337,12 @@
        vap->va_nlink = de->de_links;
        vap->va_fileid = de->de_inode;
 
-       if (de->de_dirent->d_type == DT_DIR) {
+       if (de->de_type == DT_DIR) {
                vap->va_type = VDIR;
-       } else if (de->de_dirent->d_type == DT_LNK) {
+               vap->va_size = 512;             /* any non-zero value */
+       } else if (de->de_type == DT_LNK) {
                vap->va_type = VLNK;
-       } else if (de->de_dirent->d_type == DT_CHR) {
+       } else if (de->de_type == DT_CHR) {
                vap->va_type = VCHR;
                vap->va_rdev = devfs_inot[de->de_inode]->si_udev;
        }
@@ -334,31 +364,30 @@
        } */ *ap;
 {
        struct devfs_dirent *de;
+       struct vattr *vap = ap->a_vap;
        int c;
 
-       de = ap->a_vp->v_data;
-       if (ap->a_vp->v_type == VDIR) 
-               de = de->de_dir;
+       de = VNTODEVFS(ap->a_vp);
 
        c = 0;
-       if (ap->a_vap->va_flags != VNOVAL)
+       if (vap->va_flags != VNOVAL)
                return (EOPNOTSUPP);
-       if (ap->a_vap->va_uid != (uid_t)VNOVAL) {
-               de->de_uid = ap->a_vap->va_uid;
+       if (vap->va_uid != (uid_t)VNOVAL) {
+               de->de_uid = vap->va_uid;
                c = 1;
        }
-       if (ap->a_vap->va_gid != (gid_t)VNOVAL) {
-               de->de_gid = ap->a_vap->va_gid;
+       if (vap->va_gid != (gid_t)VNOVAL) {
+               de->de_gid = vap->va_gid;
                c = 1;
        }
-       if (ap->a_vap->va_mode != (mode_t)VNOVAL) {
-               de->de_mode = ap->a_vap->va_mode;
+       if (vap->va_mode != (mode_t)VNOVAL) {
+               de->de_mode = vap->va_mode;
                c = 1;
        }
-       if (ap->a_vap->va_atime.tv_sec != VNOVAL)
-               de->de_atime = ap->a_vap->va_atime;
-       if (ap->a_vap->va_mtime.tv_sec != VNOVAL)
-               de->de_mtime = ap->a_vap->va_mtime;
+       if (vap->va_atime.tv_sec != VNOVAL)
+               de->de_atime = vap->va_atime;
+       if (vap->va_mtime.tv_sec != VNOVAL)
+               de->de_mtime = vap->va_mtime;
 
        if (c)
                getnanotime(&de->de_ctime);
@@ -366,6 +395,22 @@
 }
 
 static int
+devfs_read(struct vop_read_args *ap)
+        /*struct vop_read_args {
+                struct vnode *a_vp;
+                struct uio *a_uio;
+                int  a_ioflag;
+                struct ucred *a_cred;
+        } */
+{
+       struct vnode *vp = ap->a_vp;
+
+       if (vp->v_type != VDIR)
+               return (EINVAL);
+       return (VOP_READDIR(vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
+}
+
+static int
 devfs_readdir(ap)
        struct vop_readdir_args /* {
                struct vnode *a_vp;
@@ -376,40 +421,64 @@
                u_long **a_cookies;
        } */ *ap;
 {
-       int error, i;
+       struct vnode *vp = ap->a_vp;
        struct uio *uio = ap->a_uio;
-       struct dirent *dp;
-       struct devfs_dirent *dd;
-       struct devfs_dirent *de;
+       struct dirent *dp, dirent;
+       struct devfs_dirent *dd, *de;
        struct devfs_mount *dmp;
        off_t off;
+       int error, entryid, i;
 
        if (ap->a_vp->v_type != VDIR)
                return (ENOTDIR);
+
+       if (ap->a_ncookies) {
+               printf("devfs_readdir: cookies not supported\n");
+               return EOPNOTSUPP;
+       }
 
-       dmp = VFSTODEVFS(ap->a_vp->v_mount);
+       if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
+               return EINVAL;
+
+       dmp = VFSTODEVFS(vp->v_mount);
        devfs_populate(dmp);
-       i = (u_int)off / UIO_MX;
+
+       off = uio->uio_offset;
+       entryid = off / DE_SIZE;
        error = 0;
-       de = ap->a_vp->v_data;
-       dd = TAILQ_FIRST(&de->de_dlist);
-       off = 0;
-       while (uio->uio_resid >= UIO_MX && dd != NULL) {
-               if (dd->de_dirent->d_type == DT_DIR) 
-                       de = dd->de_dir;
-               else
-                       de = dd;
-               dp = dd->de_dirent;
-               dp->d_fileno = de->de_inode;
-               if (off >= uio->uio_offset)
-                       if ((error = uiomove((caddr_t)dp, dp->d_reclen, uio)) != 0)
-                               break;
+       dd = VNTODEVFS(vp);
+
+       de = TAILQ_FIRST(&dd->de_dlist);
+       for (i = entryid - 2; de && i > 0; i--)
+               de = TAILQ_NEXT(de, de_list);
+
+       dp = &dirent;
+       while (uio->uio_resid >= DE_SIZE && de != NULL) {
+               bzero(dp, DE_SIZE);
+               dp->d_reclen = DE_SIZE;
+               switch (entryid) {
+                   case 0:
+                   case 1:
+                       dp->d_name[0] = dp->d_name[1] = '.';
+                       dp->d_fileno = (entryid == 0) ? dd->de_inode :
+                           (dd->de_parent ? dd->de_parent->de_inode : 1);
+                       dp->d_namlen = entryid + 1;
+                       dp->d_name[entryid + 1] = '\0';
+                       dp->d_type = DT_DIR;
+                       break;
+                   default:
+                       dp->d_fileno = de->de_inode;
+                       dp->d_namlen = de->de_namelen;
+                       dp->d_type = de->de_type;
+                       bcopy(de->de_name, dp->d_name, de->de_namelen + 1);
+                       de = TAILQ_NEXT(de, de_list);
+               }
+               if ((error = uiomove((caddr_t)dp, dp->d_reclen, uio)) != 0)
+                       break;
                off += dp->d_reclen;
-               dd = TAILQ_NEXT(dd, de_list);
+               entryid++;
        }
-
        uio->uio_offset = off;
-
        return (error);
 }
 
@@ -424,7 +493,7 @@
        int error;
        struct devfs_dirent *de;
 
-       de = ap->a_vp->v_data;
+       de = VNTODEVFS(ap->a_vp);
        error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio);
        return (error);
 }
@@ -504,26 +573,24 @@
                char *a_target;
        } */ *ap;
 {
-       int i;
-       struct devfs_dirent *dd;
+       struct vnode *dvp = ap->a_dvp;
+       struct devfs_mount *dmp = VFSTODEVFS(dvp->v_mount);
+       struct devfs_dirent *dd = VNTODEVFS(dvp);
        struct devfs_dirent *de;
-       struct devfs_mount *dmp;
+       char *target = ap->a_target;
+       int i;
 
-       dmp = (struct devfs_mount *)ap->a_dvp->v_mount->mnt_data;
-       dd = ap->a_dvp->v_data;
        de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
        de->de_uid = 0;
        de->de_gid = 0;
        de->de_mode = 0642;
        de->de_inode = dmp->dm_inode++;
-       de->de_dirent->d_type = DT_LNK;
-       i = strlen(ap->a_target) + 1;
+       de->de_type = DT_LNK;
+       i = strlen(target) + 1;
        MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
-       bcopy(ap->a_target, de->de_symlink, i);
+       bcopy(target, de->de_symlink, i);
        TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
-       devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
-       VREF(*(ap->a_vpp));
-       return (0);
+       return devfs_allocv(de, dvp->v_mount, ap->a_vpp, 0);
 }
 
 /*
@@ -542,7 +609,7 @@
 }
 
 /*
- * Kernfs "should never get here" operation
+ * devfs "should never get here" operation
  */
 static int
 devfs_badop()
@@ -559,6 +626,7 @@
        { &vop_lookup_desc,             (vop_t *) devfs_lookup },
        { &vop_pathconf_desc,           (vop_t *) vop_stdpathconf },
        { &vop_print_desc,              (vop_t *) devfs_print },
+       { &vop_read_desc,               (vop_t *) devfs_read },
        { &vop_readdir_desc,            (vop_t *) devfs_readdir },
        { &vop_readlink_desc,           (vop_t *) devfs_readlink },
        { &vop_reclaim_desc,            (vop_t *) devfs_reclaim },

Reply via email to