1 /*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright © 2001-2007 Red Hat, Inc.
5 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
6 *
7 * Created by David Woodhouse <dwmw2@infradead.org>
8 *
9 * For licensing information, see the file 'LICENCE' in this directory.
10 *
11 */
12
13 #include <linux/kernel.h>
14 #include <stdio.h>
15 #include "nodelist.h"
16 #include "vfs_jffs2.h"
17 #include "mtd_partition.h"
18
19 #define GC_THREAD_FLAG_TRIG 1
20 #define GC_THREAD_FLAG_STOP 2
21 #define GC_THREAD_FLAG_HAS_EXIT 4
22
23 extern struct MtdNorDev *jffs2_dev_list;
24 static void jffs2_garbage_collect_thread(unsigned long data);
25
jffs2_garbage_collect_trigger(struct jffs2_sb_info * c)26 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
27 {
28 struct super_block *sb = OFNI_BS_2SFFJ(c);
29 /* Wake up the thread */
30 jffs2_dbg(1, "jffs2_garbage_collect_trigger\n");
31 LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_TRIG);
32 }
33
34 /* This must only ever be called when no GC thread is currently running */
jffs2_start_garbage_collect_thread(struct jffs2_sb_info * c)35 void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
36 {
37 struct super_block *sb = OFNI_BS_2SFFJ(c);
38 TSK_INIT_PARAM_S stGcTask;
39
40 if (c == NULL)
41 return;
42
43 if (sb->s_root == NULL)
44 return;
45
46 LOS_EventInit(&sb->s_gc_thread_flags);
47
48 /* Start the thread. Doesn't matter if it fails -- it's only an
49 * optimisation anyway */
50 (void)memset_s(&stGcTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
51
52 stGcTask.pfnTaskEntry = (TSK_ENTRY_FUNC)jffs2_garbage_collect_thread;
53 stGcTask.auwArgs[0] = (UINTPTR)c;
54 stGcTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
55 stGcTask.pcName = "jffs2_gc_thread";
56 #ifdef LOSCFG_KERNEL_SMP
57 unsigned int i;
58 for (i = 0; i < CONFIG_MTD_PATTITION_NUM; i++) {
59 if (sb->s_dev == &jffs2_dev_list[i])
60 break;
61 }
62 stGcTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(i % LOSCFG_KERNEL_CORE_NUM);
63 #endif
64 stGcTask.usTaskPrio = JFFS2_GC_THREAD_PRIORITY;
65
66 if (LOS_TaskCreate(&sb->s_gc_thread, &stGcTask))
67 JFFS2_ERROR("Create gc task failed!!!\n");
68 }
69
jffs2_stop_garbage_collect_thread(struct jffs2_sb_info * c)70 void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
71 {
72 struct super_block *sb = OFNI_BS_2SFFJ(c);
73
74 JFFS2_DEBUG("jffs2_stop_garbage_collect_thread\n");
75 /* Stop the thread and wait for it if necessary */
76
77 LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_STOP);
78
79 JFFS2_DEBUG("jffs2_stop_garbage_collect_thread wait\n");
80
81 (void)LOS_EventRead(&sb->s_gc_thread_flags,
82 GC_THREAD_FLAG_HAS_EXIT,
83 LOS_WAITMODE_OR | LOS_WAITMODE_CLR,
84 LOS_WAIT_FOREVER);
85
86 // Kill and free the resources ... this is safe due to the flag
87 // from the thread.
88 (void)LOS_TaskDelete(sb->s_gc_thread);
89 (void)LOS_EventWrite(&sb->s_gc_thread_flags, 0xFFFFFFFF);
90 }
91
jffs2_garbage_collect_thread(unsigned long data)92 static void jffs2_garbage_collect_thread(unsigned long data)
93 {
94 struct jffs2_sb_info *c = (struct jffs2_sb_info *)data;
95 struct super_block *sb = OFNI_BS_2SFFJ(c);
96 unsigned int flag = 0;
97
98 jffs2_dbg(1, "jffs2_garbage_collect_thread START\n");
99 while(1) {
100 flag = LOS_EventRead(&sb->s_gc_thread_flags,
101 GC_THREAD_FLAG_TRIG | GC_THREAD_FLAG_STOP,
102 LOS_WAITMODE_OR | LOS_WAITMODE_CLR,
103 LOS_WAIT_FOREVER
104 );
105 if (flag & GC_THREAD_FLAG_STOP)
106 break;
107
108 jffs2_dbg(1, "jffs2: GC THREAD GC BEGIN\n");
109
110 if (sb->s_root == NULL)
111 return;
112
113 if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
114 PRINTK("No space for garbage collection. "
115 "Aborting JFFS2 GC thread\n");
116 break;
117 }
118 jffs2_dbg(1, "jffs2: GC THREAD GC END\n");
119 }
120 JFFS2_DEBUG("jffs2_garbage_collect_thread EXIT\n");
121 LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_HAS_EXIT);
122 }
123