Skip to content

Commit

Permalink
[JFFS2] Improve getdents vs. f_pos handling on NOR flash.
Browse files Browse the repository at this point in the history
Commit a491486 started obliterating
dirents directly on the medium, when jffs2_can_mark_obsolete(). Removing
them immediately from the f->dents list, however, screws up handling of
f_pos within a directory -- because the offset is equivalent to the
number of entries through the list we are, and the existence of
deletion dirents served to provide 'placeholders' for unlinked
entries. Now, 'rm -r' doesn't even manage to unlink everything in the
directory.

Revert to keeping 'deletion' dirents in the list, at least in memory
even though we no longer write anything to the medium.

Spotted, debugged and mostly fixed by Joakim Tjernlund

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
David Woodhouse committed Nov 1, 2007
1 parent d10a39d commit 1595358
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 15 deletions.
9 changes: 6 additions & 3 deletions fs/jffs2/nodelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
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;
}
Expand Down
27 changes: 15 additions & 12 deletions fs/jffs2/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,26 +582,28 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
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
want to be holding the alloc_sem when we write to flash */
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);
Expand Down Expand Up @@ -630,7 +632,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
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);
}
}
Expand Down

0 comments on commit 1595358

Please sign in to comment.