Am Samstag, 16. Februar 2019, 09:53:35 CET schrieb yuyufen: > ping? Sorry for the delay. I didn't forget (completely) about this one. The thing is, I don't really maintain jffs2 but I will collect and test patches for the upcoming merge window and carry them via my ubifs tree. David, I hope I have by end of the week a list with potential patches ready such that you can have a final look and veto what you don't like. :-) Thanks, //richard > > On 2019/1/23 15:22, Yufen Yu wrote: > > We may delete a bunch of directory entries, operating such as: > > getdents(), unlink(), getdents()..., until the end of the directory. > > jffs2 handles f_pos on the directory merely as the position on the > > f->dents list. So, the next getdents() may skip some entries > > before f_pos, if we remove some entries from the list between two > > getdents(), resulting in some entries of the directory cannot be deleted. > > > > Commit 15953580e79b is introduced to resolve this bug by not > > removing delete entries from the list immediately. > > > > However, when CONFIG_JFFS2_SUMMARY is not set, it can cause the > > following issues: > > > > * 'deletion' dirents is always in the f->dents list, wasting memory > > resource. For example: > > There is a file named 'file1'. Then we rename it: > > mv file1 file2; > > mv file2 file3; > > ... > > mv file99999 file1000000 > > > > All of file1~file1000000 dirents always in the f->dents list. > > > > * Though, the list we're traversing is already ordered by CRC, > > it could waste much CPU time when the list is very long. > > > > To fix, we define two variables in struct jffs2_inode_info: nr_dir_opening, > > obsolete_count, and two new functions: jffs2_dir_open(), jffs2_dir_release(). > > > > When open a directory, jffs2_dir_open() will increase nr_dir_opening, > > which will be decreased by jffs2_dir_release(). if the value is 0, > > it means nobody open the dir and nobody in getdents()/seek() semantics. > > Thus, we can remove all obsolete dirent from the list. > > > > When delete a file, jffs2_do_unlink() can remove the dirent directly if > > nobody open the directory(i.e. nr_dir_opending == 0). Otherwise, it just > > increase obsolete_count, denoting obsolete dirent count of the list. > > > > Fixes: 15953580e79b ("[JFFS2] Improve getdents vs. f_pos handling on NOR flash.") > > Signed-off-by: Yufen Yu <yuyufen@xxxxxxxxxx> > > --- > > fs/jffs2/dir.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ > > fs/jffs2/jffs2_fs_i.h | 7 +++++++ > > fs/jffs2/super.c | 4 ++++ > > fs/jffs2/write.c | 30 +++++++++++++++++++--------- > > include/uapi/linux/jffs2.h | 4 ++++ > > 5 files changed, 85 insertions(+), 9 deletions(-) > > > > diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c > > index f20cff1194bb..aed872dcd0ca 100644 > > --- a/fs/jffs2/dir.c > > +++ b/fs/jffs2/dir.c > > @@ -37,6 +37,8 @@ static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); > > static int jffs2_rename (struct inode *, struct dentry *, > > struct inode *, struct dentry *, > > unsigned int); > > +static int jffs2_dir_release (struct inode *, struct file *); > > +static int jffs2_dir_open (struct inode *, struct file *); > > > > const struct file_operations jffs2_dir_operations = > > { > > @@ -45,6 +47,8 @@ const struct file_operations jffs2_dir_operations = > > .unlocked_ioctl=jffs2_ioctl, > > .fsync = jffs2_fsync, > > .llseek = generic_file_llseek, > > + .open = jffs2_dir_open, > > + .release = jffs2_dir_release, > > }; > > > > > > @@ -865,3 +869,48 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, > > return 0; > > } > > > > +static int jffs2_dir_open(struct inode *dir_i, struct file *filp) > > +{ > > +#ifndef CONFIG_JFFS2_SUMMARY > > + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); > > + atomic_inc(&dir_f->nr_dir_opening); > > +#endif > > + > > + return 0; > > +} > > + > > +static int jffs2_dir_release(struct inode *dir_i, struct file *filp) > > +{ > > +#ifndef CONFIG_JFFS2_SUMMARY > > + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); > > + > > + BUG_ON(atomic_read(&dir_f->nr_dir_opening) <= 0); > > + > > + mutex_lock(&dir_f->sem); > > + /* jffs2_dir_open may increase nr_dir_opening after > > + * atomic_dec_and_test() returning true. > > + * However, it cannot traverse the list until hold > > + * mutex dir_f->sem lock, so that we can go on > > + * removing.*/ > > + if (atomic_dec_and_test(&dir_f->nr_dir_opening) && > > + dir_f->obsolete_count > JFFS2_OBS_DIRENT_LIMIT) { > > + struct jffs2_full_dirent **prev = &dir_f->dents; > > + > > + /* remove all obsolete dirent from the list, which > > + * can save memory space and reduce CPU time for > > + * traverse the list */ > > + while(*prev) { > > + if ((*prev)->raw == NULL && (*prev)->ino == 0) { > > + struct jffs2_full_dirent *this = *prev; > > + *prev = this->next; > > + jffs2_free_full_dirent(this); > > + } else > > + prev = &((*prev)->next); > > + } > > + dir_f->obsolete_count = 0; > > + } > > + mutex_unlock(&dir_f->sem); > > +#endif > > + > > + return 0; > > +} > > diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h > > index 2e4a86763c07..a4da25d16cb4 100644 > > --- a/fs/jffs2/jffs2_fs_i.h > > +++ b/fs/jffs2/jffs2_fs_i.h > > @@ -50,6 +50,13 @@ struct jffs2_inode_info { > > > > uint16_t flags; > > uint8_t usercompr; > > + > > + /* obsolete dirent count in the list of 'dents' */ > > + uint8_t obsolete_count; > > + > > + /* Directory open refcount */ > > + atomic_t nr_dir_opening; > > + > > struct inode vfs_inode; > > }; > > > > diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c > > index 87bdf0f4cba1..bf181b0ade9c 100644 > > --- a/fs/jffs2/super.c > > +++ b/fs/jffs2/super.c > > @@ -41,6 +41,10 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) > > f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); > > if (!f) > > return NULL; > > + > > + atomic_set(&f->nr_dir_opening, 0); > > + f->obsolete_count = 0; > > + > > return &f->vfs_inode; > > } > > > > diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c > > index cda9a361368e..780b4fd9af51 100644 > > --- a/fs/jffs2/write.c > > +++ b/fs/jffs2/write.c > > @@ -600,29 +600,41 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, > > } else { > > uint32_t nhash = full_name_hash(NULL, name, namelen); > > > > - fd = dir_f->dents; > > + struct jffs2_full_dirent **prev = &dir_f->dents; > > + > > /* We don't actually want to reserve any space, but we do > > want to be holding the alloc_sem when we write to flash */ > > mutex_lock(&c->alloc_sem); > > mutex_lock(&dir_f->sem); > > > > - for (fd = dir_f->dents; fd; fd = fd->next) { > > - if (fd->nhash == nhash && > > - !memcmp(fd->name, name, namelen) && > > - !fd->name[namelen]) { > > + while((*prev) && (*prev)->nhash <= nhash) { > > + if ((*prev)->nhash == nhash && > > + !memcmp((*prev)->name, name, namelen) && > > + !(*prev)->name[namelen]) { > > > > + fd = *prev; > > jffs2_dbg(1, "Marking old dirent node (ino #%u) @%08x obsolete\n", > > 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; > > + > > + /* if nr_dir_openning is 0, we think nobody open the dir, and > > + * nobody being in getdents()/seek() semantics. Thus, we can > > + * safely remove this obsolete dirent from the list. Otherwise, > > + * we just increase obsolete_count, and finally delete it in > > + * jffs2_dir_release() */ > > + if (atomic_read(&dir_f->nr_dir_opening) == 0) { > > + *prev = fd->next; > > + jffs2_free_full_dirent(fd); > > + } else > > + dir_f->obsolete_count++; > > + > > break; > > } > > + prev = &((*prev)->next); > > } > > + > > mutex_unlock(&dir_f->sem); > > } > > > > diff --git a/include/uapi/linux/jffs2.h b/include/uapi/linux/jffs2.h > > index a18b719f49d4..dff3ac2d6b0c 100644 > > --- a/include/uapi/linux/jffs2.h > > +++ b/include/uapi/linux/jffs2.h > > @@ -35,6 +35,10 @@ > > */ > > #define JFFS2_MAX_NAME_LEN 254 > > > > +/* The obsolete dirent of dents list limit. When the number over > > + * this limit, we can remove the obsoleted dents. */ > > +#define JFFS2_OBS_DIRENT_LIMIT 64 > > + > > /* How small can we sensibly write nodes? */ > > #define JFFS2_MIN_DATA_LEN 128 > > > > > -- sigma star gmbh - Eduard-Bodem-Gasse 6 - 6020 Innsbruck - Austria ATU66964118 - FN 374287y ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/