[PATCH] jffs2: safely remove obsolete dirent from the f->dents list

yuyufen yuyufen at huawei.com
Fri May 4 02:27:22 PDT 2018


Hi, David.
On 2018/5/4 16:18, David Woodhouse wrote:
>
> On Fri, 2018-05-04 at 16:06 +0800, yuyufen wrote:
>>> You've made JFFS2_INVALID_LIMIT 64, which is reasonable enough
>>> (although it's a bit of a weird name and possibly wants to be more
>>> specific — invalid *what*?).
>> Thansk a lot for your suggestions.
>>
>> Yes, it is really a bad name. How about JFFS2_OBS_DIRENT_LIMIT?  I am
>> not sure.
> That'll do; at least it's a hint in the right direction :)
>
>>> So the maximum interesting value of ->obsolete_count is 64. Which means
>>> it might as well be a uint8_t and sit in the padding after the
>>> 'usercompr' field.
>>>
>>> It might be useful to look at putting the mutually exclusive fields in
>>> struct jffs2_inode_info into a union, and then we don't need the
>>> additional space of the atomic_t either; we'll never need that *and*
>>> the fragtree at the same time... will we?
>> You are right, thanks. But, obsolete_count may be large. So, I apply to
>> use uint16_t and it also sits in the padding after the 'usercompr'
>> field.
> You can always just cap it. Once it reaches 64 it never changes again,
> until you actually harvest them. Without that, a uint16_t could
> overflow too.

I think 'JFFS2_OBS_DIRENT_LIMIT' may cause misunderstanding. Sorry for that.
In my patch, it just means a threshold value. when ->nr_dir_opening is 
'0' and
  ->obsolete_count is bigger than the value, it can trigger removing 
operations.

If ->nr_dir_opening is not '0', obsolete_count may continuously increase 
and can
exceed 64.

+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
+{
+#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) && (dir_f->obsolete_count--)) {
+                       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);
+               }
+       }
+       mutex_unlock(&dir_f->sem);
+#endif
+
+       return 0;
+}

Thanks,
Yufen






More information about the linux-mtd mailing list