unsigned blkoff)
 {
        union afs_xdr_dirent *dire;
-       unsigned offset, next, curr;
+       unsigned offset, next, curr, nr_slots;
        size_t nlen;
        int tmp;
 
             offset < AFS_DIR_SLOTS_PER_BLOCK;
             offset = next
             ) {
-               next = offset + 1;
-
                /* skip entries marked unused in the bitmap */
                if (!(block->hdr.bitmap[offset / 8] &
                      (1 << (offset % 8)))) {
                        _debug("ENT[%zu.%u]: unused",
                               blkoff / sizeof(union afs_xdr_dir_block), offset);
+                       next = offset + 1;
                        if (offset >= curr)
                                ctx->pos = blkoff +
                                        next * sizeof(union afs_xdr_dirent);
                nlen = strnlen(dire->u.name,
                               sizeof(*block) -
                               offset * sizeof(union afs_xdr_dirent));
+               if (nlen > AFSNAMEMAX - 1) {
+                       _debug("ENT[%zu]: name too long (len %u/%zu)",
+                              blkoff / sizeof(union afs_xdr_dir_block),
+                              offset, nlen);
+                       return afs_bad(dvnode, afs_file_error_dir_name_too_long);
+               }
 
                _debug("ENT[%zu.%u]: %s %zu \"%s\"",
                       blkoff / sizeof(union afs_xdr_dir_block), offset,
                       (offset < curr ? "skip" : "fill"),
                       nlen, dire->u.name);
 
-               /* work out where the next possible entry is */
-               for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_xdr_dirent)) {
-                       if (next >= AFS_DIR_SLOTS_PER_BLOCK) {
-                               _debug("ENT[%zu.%u]:"
-                                      " %u travelled beyond end dir block"
-                                      " (len %u/%zu)",
-                                      blkoff / sizeof(union afs_xdr_dir_block),
-                                      offset, next, tmp, nlen);
-                               return afs_bad(dvnode, afs_file_error_dir_over_end);
-                       }
-                       if (!(block->hdr.bitmap[next / 8] &
-                             (1 << (next % 8)))) {
-                               _debug("ENT[%zu.%u]:"
-                                      " %u unmarked extension (len %u/%zu)",
+               nr_slots = afs_dir_calc_slots(nlen);
+               next = offset + nr_slots;
+               if (next > AFS_DIR_SLOTS_PER_BLOCK) {
+                       _debug("ENT[%zu.%u]:"
+                              " %u extends beyond end dir block"
+                              " (len %zu)",
+                              blkoff / sizeof(union afs_xdr_dir_block),
+                              offset, next, nlen);
+                       return afs_bad(dvnode, afs_file_error_dir_over_end);
+               }
+
+               /* Check that the name-extension dirents are all allocated */
+               for (tmp = 1; tmp < nr_slots; tmp++) {
+                       unsigned int ix = offset + tmp;
+                       if (!(block->hdr.bitmap[ix / 8] & (1 << (ix % 8)))) {
+                               _debug("ENT[%zu.u]:"
+                                      " %u unmarked extension (%u/%u)",
                                       blkoff / sizeof(union afs_xdr_dir_block),
-                                      offset, next, tmp, nlen);
+                                      offset, tmp, nr_slots);
                                return afs_bad(dvnode, afs_file_error_dir_unmarked_ext);
                        }
-
-                       _debug("ENT[%zu.%u]: ext %u/%zu",
-                              blkoff / sizeof(union afs_xdr_dir_block),
-                              next, tmp, nlen);
-                       next++;
                }
 
                /* skip if starts before the current position */
 
        }
 
        /* Work out how many slots we're going to need. */
-       need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE);
-       need_slots /= AFS_DIR_DIRENT_SIZE;
+       need_slots = afs_dir_calc_slots(name->len);
 
        meta_page = kmap(page0);
        meta = &meta_page->blocks[0];
        }
 
        /* Work out how many slots we're going to discard. */
-       need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE);
-       need_slots /= AFS_DIR_DIRENT_SIZE;
+       need_slots = afs_dir_calc_slots(name->len);
 
        meta_page = kmap(page0);
        meta = &meta_page->blocks[0];
 
                /* When determining the number of dirent slots needed to
                 * represent a directory entry, name should be assumed to be 16
                 * bytes, due to a now-standardised (mis)calculation, but it is
-                * in fact 20 bytes in size.
+                * in fact 20 bytes in size.  afs_dir_calc_slots() should be
+                * used for this.
                 *
                 * For names longer than (16 or) 20 bytes, extra slots should
                 * be annexed to this one using the extended_name format.
        union afs_xdr_dir_block blocks[AFS_DIR_BLOCKS_PER_PAGE];
 };
 
+/*
+ * Calculate the number of dirent slots required for any given name length.
+ * The calculation is made assuming the part of the name in the first slot is
+ * 16 bytes, rather than 20, but this miscalculation is now standardised.
+ */
+static inline unsigned int afs_dir_calc_slots(size_t name_len)
+{
+       name_len++; /* NUL-terminated */
+       return 1 + ((name_len + 15) / AFS_DIR_DIRENT_SIZE);
+}
+
 #endif /* XDR_FS_H */
 
        afs_file_error_dir_bad_magic,
        afs_file_error_dir_big,
        afs_file_error_dir_missing_page,
+       afs_file_error_dir_name_too_long,
        afs_file_error_dir_over_end,
        afs_file_error_dir_small,
        afs_file_error_dir_unmarked_ext,
        EM(afs_file_error_dir_bad_magic,        "DIR_BAD_MAGIC")        \
        EM(afs_file_error_dir_big,              "DIR_BIG")              \
        EM(afs_file_error_dir_missing_page,     "DIR_MISSING_PAGE")     \
+       EM(afs_file_error_dir_name_too_long,    "DIR_NAME_TOO_LONG")    \
        EM(afs_file_error_dir_over_end,         "DIR_ENT_OVER_END")     \
        EM(afs_file_error_dir_small,            "DIR_SMALL")            \
        EM(afs_file_error_dir_unmarked_ext,     "DIR_UNMARKED_EXT")     \