diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/nodelist.c | 9 | ||||
-rw-r--r-- | fs/jffs2/write.c | 27 |
2 files changed, 21 insertions, 15 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4bf86088b3ae..87c6f555e1a0 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -32,15 +32,18 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
32 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { | 32 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { |
33 | /* Duplicate. Free one */ | 33 | /* Duplicate. Free one */ |
34 | if (new->version < (*prev)->version) { | 34 | if (new->version < (*prev)->version) { |
35 | dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n", | 35 | dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n", |
36 | (*prev)->name, (*prev)->ino); | 36 | (*prev)->name, (*prev)->ino); |
37 | jffs2_mark_node_obsolete(c, new->raw); | 37 | jffs2_mark_node_obsolete(c, new->raw); |
38 | jffs2_free_full_dirent(new); | 38 | jffs2_free_full_dirent(new); |
39 | } else { | 39 | } else { |
40 | dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n", | 40 | dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n", |
41 | (*prev)->name, (*prev)->ino); | 41 | (*prev)->name, (*prev)->ino); |
42 | new->next = (*prev)->next; | 42 | new->next = (*prev)->next; |
43 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); | 43 | /* It may have been a 'placeholder' deletion dirent, |
44 | if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */ | ||
45 | if ((*prev)->raw) | ||
46 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); | ||
44 | jffs2_free_full_dirent(*prev); | 47 | jffs2_free_full_dirent(*prev); |
45 | *prev = new; | 48 | *prev = new; |
46 | } | 49 | } |
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 147e2cbee9e4..611012f7c8ae 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -582,7 +582,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
583 | up(&dir_f->sem); | 583 | up(&dir_f->sem); |
584 | } else { | 584 | } else { |
585 | struct jffs2_full_dirent **prev = &dir_f->dents; | 585 | struct jffs2_full_dirent *fd = dir_f->dents; |
586 | uint32_t nhash = full_name_hash(name, namelen); | 586 | uint32_t nhash = full_name_hash(name, namelen); |
587 | 587 | ||
588 | /* We don't actually want to reserve any space, but we do | 588 | /* We don't actually want to reserve any space, but we do |
@@ -590,18 +590,20 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
590 | down(&c->alloc_sem); | 590 | down(&c->alloc_sem); |
591 | down(&dir_f->sem); | 591 | down(&dir_f->sem); |
592 | 592 | ||
593 | while ((*prev) && (*prev)->nhash <= nhash) { | 593 | for (fd = dir_f->dents; fd; fd = fd->next) { |
594 | if ((*prev)->nhash == nhash && | 594 | if (fd->nhash == nhash && |
595 | !memcmp((*prev)->name, name, namelen) && | 595 | !memcmp(fd->name, name, namelen) && |
596 | !(*prev)->name[namelen]) { | 596 | !fd->name[namelen]) { |
597 | struct jffs2_full_dirent *this = *prev; | ||
598 | 597 | ||
599 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n", | 598 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n", |
600 | this->ino, ref_offset(this->raw))); | 599 | fd->ino, ref_offset(fd->raw))); |
601 | 600 | jffs2_mark_node_obsolete(c, fd->raw); | |
602 | *prev = this->next; | 601 | /* We don't want to remove it from the list immediately, |
603 | jffs2_mark_node_obsolete(c, (this->raw)); | 602 | because that screws up getdents()/seek() semantics even |
604 | jffs2_free_full_dirent(this); | 603 | more than they're screwed already. Turn it into a |
604 | node-less deletion dirent instead -- a placeholder */ | ||
605 | fd->raw = NULL; | ||
606 | fd->ino = 0; | ||
605 | break; | 607 | break; |
606 | } | 608 | } |
607 | prev = &((*prev)->next); | 609 | prev = &((*prev)->next); |
@@ -630,7 +632,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
630 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", | 632 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", |
631 | fd->name, dead_f->inocache->ino)); | 633 | fd->name, dead_f->inocache->ino)); |
632 | } | 634 | } |
633 | jffs2_mark_node_obsolete(c, fd->raw); | 635 | if (fd->raw) |
636 | jffs2_mark_node_obsolete(c, fd->raw); | ||
634 | jffs2_free_full_dirent(fd); | 637 | jffs2_free_full_dirent(fd); |
635 | } | 638 | } |
636 | } | 639 | } |