if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
                        /* Duplicate. Free one */
                        if (new->version < (*prev)->version) {
-                               dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n",
+                               dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n",
                                        (*prev)->name, (*prev)->ino);
                                jffs2_mark_node_obsolete(c, new->raw);
                                jffs2_free_full_dirent(new);
                        } else {
-                               dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n",
+                               dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n",
                                        (*prev)->name, (*prev)->ino);
                                new->next = (*prev)->next;
-                               jffs2_mark_node_obsolete(c, ((*prev)->raw));
+                               /* It may have been a 'placeholder' deletion dirent, 
+                                  if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */
+                               if ((*prev)->raw)
+                                       jffs2_mark_node_obsolete(c, ((*prev)->raw));
                                jffs2_free_full_dirent(*prev);
                                *prev = new;
                        }
 
                jffs2_add_fd_to_list(c, fd, &dir_f->dents);
                up(&dir_f->sem);
        } else {
-               struct jffs2_full_dirent **prev = &dir_f->dents;
+               struct jffs2_full_dirent *fd = dir_f->dents;
                uint32_t nhash = full_name_hash(name, namelen);
 
                /* We don't actually want to reserve any space, but we do
                down(&c->alloc_sem);
                down(&dir_f->sem);
 
-               while ((*prev) && (*prev)->nhash <= nhash) {
-                       if ((*prev)->nhash == nhash &&
-                           !memcmp((*prev)->name, name, namelen) &&
-                           !(*prev)->name[namelen]) {
-                               struct jffs2_full_dirent *this = *prev;
+               for (fd = dir_f->dents; fd; fd = fd->next) {
+                       if (fd->nhash == nhash &&
+                           !memcmp(fd->name, name, namelen) &&
+                           !fd->name[namelen]) {
 
                                D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
-                                         this->ino, ref_offset(this->raw)));
-
-                               *prev = this->next;
-                               jffs2_mark_node_obsolete(c, (this->raw));
-                               jffs2_free_full_dirent(this);
+                                         fd->ino, ref_offset(fd->raw)));
+                               jffs2_mark_node_obsolete(c, fd->raw);
+                               /* We don't want to remove it from the list immediately,
+                                  because that screws up getdents()/seek() semantics even
+                                  more than they're screwed already. Turn it into a
+                                  node-less deletion dirent instead -- a placeholder */
+                               fd->raw = NULL;
+                               fd->ino = 0;
                                break;
                        }
                        prev = &((*prev)->next);
                                        D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
                                                fd->name, dead_f->inocache->ino));
                                }
-                               jffs2_mark_node_obsolete(c, fd->raw);
+                               if (fd->raw)
+                                       jffs2_mark_node_obsolete(c, fd->raw);
                                jffs2_free_full_dirent(fd);
                        }
                }