Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/fs/tmpfs tmpfs: replace the broken tmpfs_dircookie() log...



details:   https://anonhg.NetBSD.org/src/rev/4ba0b2db68f0
branches:  trunk
changeset: 791206:4ba0b2db68f0
user:      rmind <rmind%NetBSD.org@localhost>
date:      Fri Nov 08 15:44:23 2013 +0000

description:
tmpfs: replace the broken tmpfs_dircookie() logic which uses the node
address truncated to 31 bits (required for 32-bit readdir compatibility,
e.g. linux32).  Instead, assign 2^31 range using the following logic:
- The first half of the 2^31 is assigned incrementally (the fast path).
- When exceeded, use the second half of 2^31, but manage with vmem(9).

It will require 2 billion files per-directory to trigger vmem(9) usage.
Also, while here, add some fixes for tmpfs_unmount().

Should fix PR/47739, PR/47480, PR/46088 and PR/41068.
Thanks to wiz@ for stress testing.

diffstat:

 sys/fs/tmpfs/tmpfs.h        |   88 +++-----
 sys/fs/tmpfs/tmpfs_rename.c |   18 +-
 sys/fs/tmpfs/tmpfs_subr.c   |  409 ++++++++++++++++++++++++-------------------
 sys/fs/tmpfs/tmpfs_vfsops.c |   45 ++--
 sys/fs/tmpfs/tmpfs_vnops.c  |   79 +++-----
 5 files changed, 335 insertions(+), 304 deletions(-)

diffs (truncated from 1071 to 300 lines):

diff -r fdee5335d79e -r 4ba0b2db68f0 sys/fs/tmpfs/tmpfs.h
--- a/sys/fs/tmpfs/tmpfs.h      Fri Nov 08 13:17:45 2013 +0000
+++ b/sys/fs/tmpfs/tmpfs.h      Fri Nov 08 15:44:23 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tmpfs.h,v 1.45 2011/09/27 01:10:43 christos Exp $      */
+/*     $NetBSD: tmpfs.h,v 1.46 2013/11/08 15:44:23 rmind Exp $ */
 
 /*
  * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -54,6 +54,9 @@
        /* Pointer to the inode this entry refers to. */
        struct tmpfs_node *             td_node;
 
+       /* Sequence number, see tmpfs_dir_getseq(). */
+       uint32_t                        td_seq;
+
        /* Name and its length. */
        char *                          td_name;
        uint16_t                        td_namelen;
@@ -61,47 +64,10 @@
 
 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
 
-#if defined(_KERNEL)
-
-#define TMPFS_MAXNAMLEN        255
-/* Validate maximum td_namelen length. */
-CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX);
-
-#define        TMPFS_DIRCOOKIE_DOT     0
-#define        TMPFS_DIRCOOKIE_DOTDOT  1
-#define        TMPFS_DIRCOOKIE_EOF     2
-
-/*
- * Each entry in a directory has a cookie that identifies it.  Cookies
- * supersede offsets within directories, as tmpfs has no offsets as such.
- *
- * The '.', '..' and the end of directory markers have fixed cookies,
- * which cannot collide with the cookies generated by other entries.
- *
- * The cookies for the other entries are generated based on the memory
- * address of their representative meta-data structure.
- *
- * XXX: Truncating directory cookies to 31 bits now - workaround for
- * problem with Linux compat, see PR/32034.
- */
-static inline off_t
-tmpfs_dircookie(tmpfs_dirent_t *de)
-{
-       off_t cookie;
-
-       cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF;
-       KASSERT(cookie != TMPFS_DIRCOOKIE_DOT);
-       KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT);
-       KASSERT(cookie != TMPFS_DIRCOOKIE_EOF);
-
-       return cookie;
-}
-#endif
-
 /*
  * Internal representation of a tmpfs file system node -- inode.
  *
- * This structure is splitted in two parts: one holds attributes common
+ * This structure is split in two parts: one holds attributes common
  * to all file types and the other holds data that is only applicable to
  * a particular type.
  *
@@ -169,11 +135,14 @@
                        /* List of directory entries. */
                        struct tmpfs_dir        tn_dir;
 
+                       /* Last given sequence number and their arena. */
+                       uint32_t                tn_next_seq;
+                       void *                  tn_seq_arena;
+
                        /*
-                        * Number and pointer of the last directory entry
-                        * returned by the readdir(3) operation.
+                        * Pointer of the last directory entry returned
+                        * by the readdir(3) operation.
                         */
-                       off_t                   tn_readdir_lastn;
                        struct tmpfs_dirent *   tn_readdir_lastp;
                } tn_dir;
 
@@ -196,6 +165,24 @@
 
 LIST_HEAD(tmpfs_node_list, tmpfs_node);
 
+#define        TMPFS_MAXNAMLEN         255
+/* Validate maximum td_namelen length. */
+CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX);
+
+/*
+ * Reserved values for the virtual entries (the first must be 0) and EOF.
+ * The start/end of the incremental range, see tmpfs_dir_getseq().
+ */
+#define        TMPFS_DIRSEQ_DOT        0
+#define        TMPFS_DIRSEQ_DOTDOT     1
+#define        TMPFS_DIRSEQ_EOF        2
+
+#define        TMPFS_DIRSEQ_START      3               /* inclusive */
+#define        TMPFS_DIRSEQ_END        (1U << 30)      /* exclusive */
+
+/* Mark to indicate that the number is not set. */
+#define        TMPFS_DIRSEQ_NONE       (1U << 31)
+
 /* Status flags. */
 #define        TMPFS_NODE_ACCESSED     0x01
 #define        TMPFS_NODE_MODIFIED     0x02
@@ -270,15 +257,14 @@
 int            tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t,
                    tmpfs_dirent_t **);
 void           tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *);
-void           tmpfs_dir_attach(vnode_t *, tmpfs_dirent_t *, tmpfs_node_t *);
-void           tmpfs_dir_detach(vnode_t *, tmpfs_dirent_t *);
+void           tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *, tmpfs_node_t *);
+void           tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *);
 
 tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *);
 tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *);
 
-int            tmpfs_dir_getdotdent(tmpfs_node_t *, struct uio *);
-int            tmpfs_dir_getdotdotdent(tmpfs_node_t *, struct uio *);
-tmpfs_dirent_t *tmpfs_dir_lookupbycookie(tmpfs_node_t *, off_t);
+uint32_t       tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *);
+tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t);
 int            tmpfs_dir_getdents(tmpfs_node_t *, struct uio *, off_t *);
 
 int            tmpfs_reg_resize(vnode_t *, off_t);
@@ -321,12 +307,10 @@
  * Ensures that the node pointed by 'node' is a directory and that its
  * contents are consistent with respect to directories.
  */
-#define TMPFS_VALIDATE_DIR(node) \
+#define        TMPFS_VALIDATE_DIR(node) \
+    KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \
     KASSERT((node)->tn_type == VDIR); \
-    KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); \
-    KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \
-        tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \
-        (node)->tn_spec.tn_dir.tn_readdir_lastn);
+    KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0);
 
 /*
  * Memory management stuff.
diff -r fdee5335d79e -r 4ba0b2db68f0 sys/fs/tmpfs/tmpfs_rename.c
--- a/sys/fs/tmpfs/tmpfs_rename.c       Fri Nov 08 13:17:45 2013 +0000
+++ b/sys/fs/tmpfs/tmpfs_rename.c       Fri Nov 08 15:44:23 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tmpfs_rename.c,v 1.4 2012/09/27 17:40:51 riastradh Exp $       */
+/*     $NetBSD: tmpfs_rename.c,v 1.5 2013/11/08 15:44:23 rmind Exp $   */
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_rename.c,v 1.4 2012/09/27 17:40:51 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_rename.c,v 1.5 2013/11/08 15:44:23 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -313,8 +313,11 @@
         * source entry and reattach it to the target directory.
         */
        if (fdvp != tdvp) {
-               tmpfs_dir_detach(fdvp, *fdep);
-               tmpfs_dir_attach(tdvp, *fdep, VP_TO_TMPFS_NODE(fvp));
+               tmpfs_node_t *fdnode = VP_TO_TMPFS_DIR(fdvp);
+               tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
+
+               tmpfs_dir_detach(fdnode, *fdep);
+               tmpfs_dir_attach(tdnode, *fdep, VP_TO_TMPFS_NODE(fvp));
        } else if (tvp == NULL) {
                /*
                 * We are changing the directory.  tmpfs_dir_attach and
@@ -331,6 +334,8 @@
         * XXX What if the target is a directory with whiteout entries?
         */
        if (tvp != NULL) {
+               tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp);
+
                KASSERT((*tdep) != NULL);
                KASSERT((*tdep)->td_node == VP_TO_TMPFS_NODE(tvp));
                KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
@@ -349,7 +354,7 @@
                         */
                        VP_TO_TMPFS_NODE(tvp)->tn_links--;
                }
-               tmpfs_dir_detach(tdvp, *tdep);
+               tmpfs_dir_detach(tdnode, *tdep);
                tmpfs_free_dirent(VFS_TO_TMPFS(mp), *tdep);
        }
 
@@ -388,6 +393,7 @@
 tmpfs_gro_remove(struct mount *mp, kauth_cred_t cred,
     struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
 {
+       tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);
        struct tmpfs_dirent **dep = de;
 
        (void)vp;
@@ -404,7 +410,7 @@
        KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
 
-       tmpfs_dir_detach(dvp, *dep);
+       tmpfs_dir_detach(dnode, *dep);
        tmpfs_free_dirent(VFS_TO_TMPFS(mp), *dep);
 
        return 0;
diff -r fdee5335d79e -r 4ba0b2db68f0 sys/fs/tmpfs/tmpfs_subr.c
--- a/sys/fs/tmpfs/tmpfs_subr.c Fri Nov 08 13:17:45 2013 +0000
+++ b/sys/fs/tmpfs/tmpfs_subr.c Fri Nov 08 15:44:23 2013 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: tmpfs_subr.c,v 1.82 2013/11/01 15:38:45 rmind Exp $    */
+/*     $NetBSD: tmpfs_subr.c,v 1.83 2013/11/08 15:44:23 rmind Exp $    */
 
 /*
- * Copyright (c) 2005-2011 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005-2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -74,7 +74,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.82 2013/11/01 15:38:45 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.83 2013/11/08 15:44:23 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -98,6 +98,8 @@
 #include <fs/tmpfs/tmpfs_specops.h>
 #include <fs/tmpfs/tmpfs_vnops.h>
 
+static void    tmpfs_dir_putseq(tmpfs_node_t *, tmpfs_dirent_t *);
+
 /*
  * tmpfs_alloc_node: allocate a new inode of a specified type and
  * insert it into the list of specified mount point.
@@ -155,7 +157,8 @@
                /* Directory. */
                TAILQ_INIT(&nnode->tn_spec.tn_dir.tn_dir);
                nnode->tn_spec.tn_dir.tn_parent = NULL;
-               nnode->tn_spec.tn_dir.tn_readdir_lastn = 0;
+               nnode->tn_spec.tn_dir.tn_seq_arena = NULL;
+               nnode->tn_spec.tn_dir.tn_next_seq = TMPFS_DIRSEQ_START;
                nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
 
                /* Extra link count for the virtual '.' entry. */
@@ -240,11 +243,10 @@
                }
                break;
        case VDIR:
-               /*
-                * KASSERT(TAILQ_EMPTY(&node->tn_spec.tn_dir.tn_dir));
-                * KASSERT(node->tn_spec.tn_dir.tn_parent == NULL ||
-                *     node == tmp->tm_root);
-                */
+               KASSERT(node->tn_spec.tn_dir.tn_seq_arena == NULL);
+               KASSERT(TAILQ_EMPTY(&node->tn_spec.tn_dir.tn_dir));
+               KASSERT(node->tn_spec.tn_dir.tn_parent == NULL ||
+                   node == tmp->tm_root);
                break;
        default:
                break;
@@ -390,12 +392,12 @@
        if (cnp->cn_flags & ISWHITEOUT) {
                wde = tmpfs_dir_lookup(dnode, cnp);
                KASSERT(wde != NULL && wde->td_node == TMPFS_NODE_WHITEOUT);
-               tmpfs_dir_detach(dvp, wde);
+               tmpfs_dir_detach(dnode, wde);
                tmpfs_free_dirent(tmp, wde);
        }
 
        /* Associate inode and attach the entry into the directory. */
-       tmpfs_dir_attach(dvp, de, node);
+       tmpfs_dir_attach(dnode, de, node);
 
        /* Make node opaque if requested. */
        if (cnp->cn_flags & ISWHITEOUT)
@@ -426,6 +428,7 @@
        }
        nde->td_namelen = len;
        memcpy(nde->td_name, name, len);
+       nde->td_seq = TMPFS_DIRSEQ_NONE;
 
        *de = nde;
        return 0;
@@ -437,8 +440,8 @@
 void
 tmpfs_free_dirent(tmpfs_mount_t *tmp, tmpfs_dirent_t *de)
 {
-
-       /* KASSERT(de->td_node == NULL); */



Home | Main Index | Thread Index | Old Index