kernel - TMPFS - Bug fixing pass - vinitvmio(), umount, readdir
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 13 Feb 2010 07:57:53 +0000 (23:57 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 13 Feb 2010 07:57:53 +0000 (23:57 -0800)
* Call vinitvmio() with a properly bufcache-aligned number of pages

* Do not call vinitvmio() for symlinks or directories (we don't use
  the buffer cache for those vnode types).

* Adjust tmpfs_dir_attach() and tmpfs_dir_detach() so the detach
  code can be called from umount, and call it from umount to fix
  a panic.

* tmpfs_dir_getdotdotdent() needed to be adjusted to handle the
  root vnode's NULL parent pointer.  Fixed empty root directories
  for the mount.

* Acquire TMPFS_NODE_LOCK() around opreations on dnode->tn_dir.tn_dirhead.

sys/vfs/tmpfs/tmpfs.h
sys/vfs/tmpfs/tmpfs_subr.c
sys/vfs/tmpfs/tmpfs_vfsops.c
sys/vfs/tmpfs/tmpfs_vnops.c

index 647c0dd..4c1b03d 100644 (file)
@@ -431,13 +431,14 @@ int       tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, int,
 void   tmpfs_free_vp(struct vnode *);
 int    tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
            struct namecache *, struct ucred *, char *);
-void   tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
-void   tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
+void   tmpfs_dir_attach(struct tmpfs_node *, struct tmpfs_dirent *);
+void   tmpfs_dir_detach(struct tmpfs_node *, struct tmpfs_dirent *);
 struct tmpfs_dirent *  tmpfs_dir_lookup(struct tmpfs_node *node,
                            struct tmpfs_node *f,
                            struct namecache *ncp);
 int    tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
-int    tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
+int    tmpfs_dir_getdotdotdent(struct tmpfs_mount *,
+                           struct tmpfs_node *, struct uio *);
 struct tmpfs_dirent *  tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
 int    tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
 int    tmpfs_reg_resize(struct vnode *, off_t, int);
index 8e7005b..e575d99 100644 (file)
@@ -444,17 +444,14 @@ loop:
        case VSOCK:
                break;
        case VREG:
-               vinitvmio(vp, node->tn_size);
+               vinitvmio(vp, (node->tn_size + BMASK) & ~(off_t)BMASK);
                break;
        case VLNK:
-               if (node->tn_size >= vp->v_mount->mnt_maxsymlinklen)
-                       vinitvmio(vp, node->tn_size);
                break;
        case VFIFO:
                vp->v_ops = &mp->mnt_vn_fifo_ops;
                break;
        case VDIR:
-               vinitvmio(vp, node->tn_size);
                break;
 
        default:
@@ -580,7 +577,7 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
        /* Now that all required items are allocated, we can proceed to
         * insert the new node into the directory, an operation that
         * cannot fail. */
-       tmpfs_dir_attach(dvp, de);
+       tmpfs_dir_attach(dnode, de);
        TMPFS_NODE_UNLOCK(node);
 
        return error;
@@ -594,19 +591,15 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
  * the directory entry, as this is done by tmpfs_alloc_dirent.
  */
 void
-tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
+tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
 {
-       struct tmpfs_node *dnode;
-
-       dnode = VP_TO_TMPFS_DIR(vp);
-
+       TMPFS_NODE_LOCK(dnode);
        TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries);
 
-       TMPFS_NODE_LOCK(dnode);
        TMPFS_ASSERT_ELOCKED(dnode);
        dnode->tn_size += sizeof(struct tmpfs_dirent);
-       dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
-           TMPFS_NODE_MODIFIED;
+       dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
+                           TMPFS_NODE_MODIFIED;
        TMPFS_NODE_UNLOCK(dnode);
 }
 
@@ -618,24 +611,19 @@ tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
  * the directory entry, as this is done by tmpfs_free_dirent.
  */
 void
-tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de)
+tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
 {
-       struct tmpfs_node *dnode;
-
-       dnode = VP_TO_TMPFS_DIR(vp);
-
-
+       TMPFS_NODE_LOCK(dnode);
        if (dnode->tn_dir.tn_readdir_lastp == de) {
                dnode->tn_dir.tn_readdir_lastn = 0;
                dnode->tn_dir.tn_readdir_lastp = NULL;
        }
        TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries);
 
-       TMPFS_NODE_LOCK(dnode);
        TMPFS_ASSERT_ELOCKED(dnode);
        dnode->tn_size -= sizeof(struct tmpfs_dirent);
-       dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
-           TMPFS_NODE_MODIFIED;
+       dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
+                           TMPFS_NODE_MODIFIED;
        TMPFS_NODE_UNLOCK(dnode);
 }
 
@@ -723,7 +711,8 @@ tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio)
  * error happens.
  */
 int
-tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio)
+tmpfs_dir_getdotdotdent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
+                       struct uio *uio)
 {
        int error;
        struct dirent dent;
@@ -732,17 +721,14 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio)
        TMPFS_VALIDATE_DIR(node);
        KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT);
 
-       /*
-        * Return ENOENT if the current node is already removed.
-        */
-       if (node->tn_dir.tn_parent == NULL) {
-               return (ENOENT);
+       if (node->tn_dir.tn_parent) {
+               TMPFS_NODE_LOCK(node->tn_dir.tn_parent);
+               dent.d_ino = node->tn_dir.tn_parent->tn_id;
+               TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent);
+       } else {
+               dent.d_ino = tmp->tm_root->tn_id;
        }
 
-       TMPFS_NODE_LOCK(node->tn_dir.tn_parent);
-       dent.d_ino = node->tn_dir.tn_parent->tn_id;
-       TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent);
-
        dent.d_type = DT_DIR;
        dent.d_namlen = 2;
        dent.d_name[0] = '.';
@@ -961,19 +947,24 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize, int trivial)
         * When adjusting the vnode filesize and its VM object we must
         * also adjust our backing VM object (aobj).  The blocksize
         * used must match the block sized we use for the buffer cache.
+        *
+        * The backing VM object contains no VM pages, only swap
+        * assignments.
         */
        if (newsize < oldsize) {
                vm_pindex_t osize;
+               vm_pindex_t nsize;
                vm_object_t aobj;
 
                error = nvtruncbuf(vp, newsize, BSIZE, -1);
                aobj = node->tn_reg.tn_aobj;
                if (aobj) {
                        osize = aobj->size;
-                       if (osize > vp->v_object->size) {
+                       nsize = vp->v_object->size;
+                       if (nsize < osize) {
                                aobj->size = osize;
-                               vm_object_page_remove(aobj, vp->v_object->size,
-                                                     osize, FALSE);
+                               swap_pager_freespace(aobj, nsize,
+                                                    osize - nsize);
                        }
                }
        } else {
index ce0165d..338ede6 100644 (file)
@@ -337,6 +337,7 @@ tmpfs_unmount(struct mount *mp, int mntflags)
 
                        while (!TAILQ_EMPTY(&node->tn_dir.tn_dirhead)) {
                                de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
+                               tmpfs_dir_detach(node, de);
                                tmpfs_free_dirent(tmp, de);
                                node->tn_size -= sizeof(struct tmpfs_dirent);
                        }
index f3f92c7..10663d4 100644 (file)
@@ -786,7 +786,7 @@ tmpfs_nremove(struct vop_nremove_args *v)
 
        /* Remove the entry from the directory; as it is a file, we do not
         * have to change the number of hard links of the directory. */
-       tmpfs_dir_detach(dvp, de);
+       tmpfs_dir_detach(dnode, de);
 
        /* Free the directory entry we just deleted.  Note that the node
         * referred by it will not be removed until the vnode is really
@@ -819,14 +819,15 @@ tmpfs_nlink(struct vop_nlink_args *v)
        struct vnode *dvp = v->a_dvp;
        struct vnode *vp = v->a_vp;
        struct namecache *ncp = v->a_nch->ncp;
-
-       int error;
        struct tmpfs_dirent *de;
        struct tmpfs_node *node;
+       struct tmpfs_node *dnode;
+       int error;
 
        KKASSERT(dvp != vp); /* XXX When can this be false? */
 
        node = VP_TO_TMPFS_NODE(vp);
+       dnode = VP_TO_TMPFS_NODE(dvp);
 
        /* XXX: Why aren't the following two tests done by the caller? */
 
@@ -863,7 +864,7 @@ tmpfs_nlink(struct vop_nlink_args *v)
                goto out;
 
        /* Insert the new directory entry into the appropriate directory. */
-       tmpfs_dir_attach(dvp, de);
+       tmpfs_dir_attach(dnode, de);
 
        /* vp link count has changed, so update node times. */
 
@@ -891,15 +892,14 @@ tmpfs_nrename(struct vop_nrename_args *v)
        struct vnode *tdvp = v->a_tdvp;
        struct namecache *tncp = v->a_tnch->ncp;
        struct vnode *tvp = tncp->nc_vp;
-
-       char *newname;
-       int error;
        struct tmpfs_dirent *de;
        struct tmpfs_mount *tmp;
        struct tmpfs_node *fdnode;
        struct tmpfs_node *fnode;
        struct tmpfs_node *tnode;
        struct tmpfs_node *tdnode;
+       char *newname;
+       int error;
 
        tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
 
@@ -1049,8 +1049,8 @@ tmpfs_nrename(struct vop_nrename_args *v)
 
                /* Do the move: just remove the entry from the source directory
                 * and insert it into the target one. */
-               tmpfs_dir_detach(fdvp, de);
-               tmpfs_dir_attach(tdvp, de);
+               tmpfs_dir_detach(fdnode, de);
+               tmpfs_dir_attach(tdnode, de);
        }
 
        /* If the name has changed, we need to make it effective by changing
@@ -1078,7 +1078,7 @@ tmpfs_nrename(struct vop_nrename_args *v)
        if (tvp != NULL) {
                /* Remove the old entry from the target directory. */
                de = tmpfs_dir_lookup(tdnode, tnode, tncp);
-               tmpfs_dir_detach(tdvp, de);
+               tmpfs_dir_detach(tdnode, de);
 
                /* Free the directory entry we just deleted.  Note that the
                 * node referred by it will not be removed until the vnode is
@@ -1187,7 +1187,7 @@ tmpfs_nrmdir(struct vop_nrmdir_args *v)
 
 
        /* Detach the directory entry from the directory (dnode). */
-       tmpfs_dir_detach(dvp, de);
+       tmpfs_dir_detach(dnode, de);
 
        /* No vnode should be allocated for this entry from this point */
        TMPFS_NODE_LOCK(node);
@@ -1272,7 +1272,7 @@ tmpfs_readdir(struct vop_readdir_args *v)
        int *eofflag = v->a_eofflag;
        off_t **cookies = v->a_cookies;
        int *ncookies = v->a_ncookies;
-
+       struct tmpfs_mount *tmp;
        int error;
        off_t startoff;
        off_t cnt = 0;
@@ -1282,6 +1282,7 @@ tmpfs_readdir(struct vop_readdir_args *v)
        if (vp->v_type != VDIR)
                return ENOTDIR;
 
+       tmp = VFS_TO_TMPFS(vp->v_mount);
        node = VP_TO_TMPFS_DIR(vp);
        startoff = uio->uio_offset;
 
@@ -1293,7 +1294,7 @@ tmpfs_readdir(struct vop_readdir_args *v)
        }
 
        if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
-               error = tmpfs_dir_getdotdotdent(node, uio);
+               error = tmpfs_dir_getdotdotdent(tmp, node, uio);
                if (error != 0)
                        goto outok;
                cnt++;