Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=15953580e79b58caefb107e77f218e009b9992e6
Commit:     15953580e79b58caefb107e77f218e009b9992e6
Parent:     d10a39d1a580db005d206fb6527a60fd9800c9fd
Author:     David Woodhouse <[EMAIL PROTECTED]>
AuthorDate: Thu Nov 1 16:25:56 2007 -0400
Committer:  David Woodhouse <[EMAIL PROTECTED]>
CommitDate: Thu Nov 1 16:25:56 2007 -0400

    [JFFS2] Improve getdents vs. f_pos handling on NOR flash.
    
    Commit a491486a2087ac3dfc00efb4f838c8d684afaf54 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 <[EMAIL PROTECTED]>
---
 fs/jffs2/nodelist.c |    9 ++++++---
 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 4bf8608..87c6f55 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
                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;
                        }
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 147e2cb..611012f 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,
                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
@@ -590,18 +590,20 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct 
jffs2_inode_info *dir_f,
                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);
@@ -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);
                        }
                }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to