diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/Makefile | 1 | ||||
-rw-r--r-- | fs/jffs2/background.c | 12 | ||||
-rw-r--r-- | fs/jffs2/compr.c | 422 | ||||
-rw-r--r-- | fs/jffs2/compr.h | 54 | ||||
-rw-r--r-- | fs/jffs2/compr_lzo.c | 108 | ||||
-rw-r--r-- | fs/jffs2/compr_rtime.c | 2 | ||||
-rw-r--r-- | fs/jffs2/compr_rubin.c | 4 | ||||
-rw-r--r-- | fs/jffs2/compr_zlib.c | 6 | ||||
-rw-r--r-- | fs/jffs2/dir.c | 4 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 55 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 4 | ||||
-rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 3 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 7 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 9 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 10 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 5 | ||||
-rw-r--r-- | fs/jffs2/security.c | 6 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 8 | ||||
-rw-r--r-- | fs/jffs2/summary.h | 6 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 77 | ||||
-rw-r--r-- | fs/jffs2/write.c | 15 | ||||
-rw-r--r-- | fs/jffs2/xattr.h | 2 | ||||
-rw-r--r-- | fs/jffs2/xattr_user.c | 4 |
23 files changed, 554 insertions, 270 deletions
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index c32b241e3d91..60e5d49ca03e 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile | |||
@@ -17,4 +17,5 @@ jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o | |||
17 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o | 17 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o |
18 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o | 18 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o |
19 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o | 19 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o |
20 | jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o | ||
20 | jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o | 21 | jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 143c5530caf3..d568ae846741 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -23,8 +23,8 @@ static int jffs2_garbage_collect_thread(void *); | |||
23 | void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) | 23 | void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) |
24 | { | 24 | { |
25 | spin_lock(&c->erase_completion_lock); | 25 | spin_lock(&c->erase_completion_lock); |
26 | if (c->gc_task && jffs2_thread_should_wake(c)) | 26 | if (c->gc_task && jffs2_thread_should_wake(c)) |
27 | send_sig(SIGHUP, c->gc_task, 1); | 27 | send_sig(SIGHUP, c->gc_task, 1); |
28 | spin_unlock(&c->erase_completion_lock); | 28 | spin_unlock(&c->erase_completion_lock); |
29 | } | 29 | } |
30 | 30 | ||
@@ -84,7 +84,7 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
84 | set_freezable(); | 84 | set_freezable(); |
85 | for (;;) { | 85 | for (;;) { |
86 | allow_signal(SIGHUP); | 86 | allow_signal(SIGHUP); |
87 | 87 | again: | |
88 | if (!jffs2_thread_should_wake(c)) { | 88 | if (!jffs2_thread_should_wake(c)) { |
89 | set_current_state (TASK_INTERRUPTIBLE); | 89 | set_current_state (TASK_INTERRUPTIBLE); |
90 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); | 90 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); |
@@ -95,9 +95,6 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
95 | schedule(); | 95 | schedule(); |
96 | } | 96 | } |
97 | 97 | ||
98 | if (try_to_freeze()) | ||
99 | continue; | ||
100 | |||
101 | /* This thread is purely an optimisation. But if it runs when | 98 | /* This thread is purely an optimisation. But if it runs when |
102 | other things could be running, it actually makes things a | 99 | other things could be running, it actually makes things a |
103 | lot worse. Use yield() and put it at the back of the runqueue | 100 | lot worse. Use yield() and put it at the back of the runqueue |
@@ -112,6 +109,9 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
112 | siginfo_t info; | 109 | siginfo_t info; |
113 | unsigned long signr; | 110 | unsigned long signr; |
114 | 111 | ||
112 | if (try_to_freeze()) | ||
113 | goto again; | ||
114 | |||
115 | signr = dequeue_signal_lock(current, ¤t->blocked, &info); | 115 | signr = dequeue_signal_lock(current, ¤t->blocked, &info); |
116 | 116 | ||
117 | switch(signr) { | 117 | switch(signr) { |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 485d065de41f..86739ee53b37 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Created by Arjan van de Ven <arjanv@redhat.com> | 5 | * Created by Arjan van de Ven <arjanv@redhat.com> |
6 | * | 6 | * |
7 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 7 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
8 | * University of Szeged, Hungary | 8 | * University of Szeged, Hungary |
9 | * | 9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * | 11 | * |
@@ -24,6 +24,34 @@ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; | |||
24 | /* Statistics for blocks stored without compression */ | 24 | /* Statistics for blocks stored without compression */ |
25 | static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; | 25 | static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; |
26 | 26 | ||
27 | |||
28 | /* | ||
29 | * Return 1 to use this compression | ||
30 | */ | ||
31 | static int jffs2_is_best_compression(struct jffs2_compressor *this, | ||
32 | struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) | ||
33 | { | ||
34 | switch (jffs2_compression_mode) { | ||
35 | case JFFS2_COMPR_MODE_SIZE: | ||
36 | if (bestsize > size) | ||
37 | return 1; | ||
38 | return 0; | ||
39 | case JFFS2_COMPR_MODE_FAVOURLZO: | ||
40 | if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size)) | ||
41 | return 1; | ||
42 | if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) | ||
43 | return 1; | ||
44 | if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) | ||
45 | return 1; | ||
46 | if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) | ||
47 | return 1; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | /* Shouldn't happen */ | ||
52 | return 0; | ||
53 | } | ||
54 | |||
27 | /* jffs2_compress: | 55 | /* jffs2_compress: |
28 | * @data: Pointer to uncompressed data | 56 | * @data: Pointer to uncompressed data |
29 | * @cdata: Pointer to returned pointer to buffer for compressed data | 57 | * @cdata: Pointer to returned pointer to buffer for compressed data |
@@ -43,121 +71,124 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co | |||
43 | * *datalen accordingly to show the amount of data which were compressed. | 71 | * *datalen accordingly to show the amount of data which were compressed. |
44 | */ | 72 | */ |
45 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 73 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
46 | unsigned char *data_in, unsigned char **cpage_out, | 74 | unsigned char *data_in, unsigned char **cpage_out, |
47 | uint32_t *datalen, uint32_t *cdatalen) | 75 | uint32_t *datalen, uint32_t *cdatalen) |
48 | { | 76 | { |
49 | int ret = JFFS2_COMPR_NONE; | 77 | int ret = JFFS2_COMPR_NONE; |
50 | int compr_ret; | 78 | int compr_ret; |
51 | struct jffs2_compressor *this, *best=NULL; | 79 | struct jffs2_compressor *this, *best=NULL; |
52 | unsigned char *output_buf = NULL, *tmp_buf; | 80 | unsigned char *output_buf = NULL, *tmp_buf; |
53 | uint32_t orig_slen, orig_dlen; | 81 | uint32_t orig_slen, orig_dlen; |
54 | uint32_t best_slen=0, best_dlen=0; | 82 | uint32_t best_slen=0, best_dlen=0; |
55 | 83 | ||
56 | switch (jffs2_compression_mode) { | 84 | switch (jffs2_compression_mode) { |
57 | case JFFS2_COMPR_MODE_NONE: | 85 | case JFFS2_COMPR_MODE_NONE: |
58 | break; | 86 | break; |
59 | case JFFS2_COMPR_MODE_PRIORITY: | 87 | case JFFS2_COMPR_MODE_PRIORITY: |
60 | output_buf = kmalloc(*cdatalen,GFP_KERNEL); | 88 | output_buf = kmalloc(*cdatalen,GFP_KERNEL); |
61 | if (!output_buf) { | 89 | if (!output_buf) { |
62 | printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); | 90 | printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); |
63 | goto out; | 91 | goto out; |
64 | } | 92 | } |
65 | orig_slen = *datalen; | 93 | orig_slen = *datalen; |
66 | orig_dlen = *cdatalen; | 94 | orig_dlen = *cdatalen; |
67 | spin_lock(&jffs2_compressor_list_lock); | 95 | spin_lock(&jffs2_compressor_list_lock); |
68 | list_for_each_entry(this, &jffs2_compressor_list, list) { | 96 | list_for_each_entry(this, &jffs2_compressor_list, list) { |
69 | /* Skip decompress-only backwards-compatibility and disabled modules */ | 97 | /* Skip decompress-only backwards-compatibility and disabled modules */ |
70 | if ((!this->compress)||(this->disabled)) | 98 | if ((!this->compress)||(this->disabled)) |
71 | continue; | 99 | continue; |
72 | 100 | ||
73 | this->usecount++; | 101 | this->usecount++; |
74 | spin_unlock(&jffs2_compressor_list_lock); | 102 | spin_unlock(&jffs2_compressor_list_lock); |
75 | *datalen = orig_slen; | 103 | *datalen = orig_slen; |
76 | *cdatalen = orig_dlen; | 104 | *cdatalen = orig_dlen; |
77 | compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); | 105 | compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); |
78 | spin_lock(&jffs2_compressor_list_lock); | 106 | spin_lock(&jffs2_compressor_list_lock); |
79 | this->usecount--; | 107 | this->usecount--; |
80 | if (!compr_ret) { | 108 | if (!compr_ret) { |
81 | ret = this->compr; | 109 | ret = this->compr; |
82 | this->stat_compr_blocks++; | 110 | this->stat_compr_blocks++; |
83 | this->stat_compr_orig_size += *datalen; | 111 | this->stat_compr_orig_size += *datalen; |
84 | this->stat_compr_new_size += *cdatalen; | 112 | this->stat_compr_new_size += *cdatalen; |
85 | break; | 113 | break; |
86 | } | 114 | } |
87 | } | 115 | } |
88 | spin_unlock(&jffs2_compressor_list_lock); | 116 | spin_unlock(&jffs2_compressor_list_lock); |
89 | if (ret == JFFS2_COMPR_NONE) kfree(output_buf); | 117 | if (ret == JFFS2_COMPR_NONE) |
90 | break; | 118 | kfree(output_buf); |
91 | case JFFS2_COMPR_MODE_SIZE: | 119 | break; |
92 | orig_slen = *datalen; | 120 | case JFFS2_COMPR_MODE_SIZE: |
93 | orig_dlen = *cdatalen; | 121 | case JFFS2_COMPR_MODE_FAVOURLZO: |
94 | spin_lock(&jffs2_compressor_list_lock); | 122 | orig_slen = *datalen; |
95 | list_for_each_entry(this, &jffs2_compressor_list, list) { | 123 | orig_dlen = *cdatalen; |
96 | /* Skip decompress-only backwards-compatibility and disabled modules */ | 124 | spin_lock(&jffs2_compressor_list_lock); |
97 | if ((!this->compress)||(this->disabled)) | 125 | list_for_each_entry(this, &jffs2_compressor_list, list) { |
98 | continue; | 126 | /* Skip decompress-only backwards-compatibility and disabled modules */ |
99 | /* Allocating memory for output buffer if necessary */ | 127 | if ((!this->compress)||(this->disabled)) |
100 | if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) { | 128 | continue; |
101 | spin_unlock(&jffs2_compressor_list_lock); | 129 | /* Allocating memory for output buffer if necessary */ |
102 | kfree(this->compr_buf); | 130 | if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) { |
103 | spin_lock(&jffs2_compressor_list_lock); | 131 | spin_unlock(&jffs2_compressor_list_lock); |
104 | this->compr_buf_size=0; | 132 | kfree(this->compr_buf); |
105 | this->compr_buf=NULL; | 133 | spin_lock(&jffs2_compressor_list_lock); |
106 | } | 134 | this->compr_buf_size=0; |
107 | if (!this->compr_buf) { | 135 | this->compr_buf=NULL; |
108 | spin_unlock(&jffs2_compressor_list_lock); | 136 | } |
109 | tmp_buf = kmalloc(orig_dlen,GFP_KERNEL); | 137 | if (!this->compr_buf) { |
110 | spin_lock(&jffs2_compressor_list_lock); | 138 | spin_unlock(&jffs2_compressor_list_lock); |
111 | if (!tmp_buf) { | 139 | tmp_buf = kmalloc(orig_slen, GFP_KERNEL); |
112 | printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); | 140 | spin_lock(&jffs2_compressor_list_lock); |
113 | continue; | 141 | if (!tmp_buf) { |
114 | } | 142 | printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen); |
115 | else { | 143 | continue; |
116 | this->compr_buf = tmp_buf; | 144 | } |
117 | this->compr_buf_size = orig_dlen; | 145 | else { |
118 | } | 146 | this->compr_buf = tmp_buf; |
119 | } | 147 | this->compr_buf_size = orig_slen; |
120 | this->usecount++; | 148 | } |
121 | spin_unlock(&jffs2_compressor_list_lock); | 149 | } |
122 | *datalen = orig_slen; | 150 | this->usecount++; |
123 | *cdatalen = orig_dlen; | 151 | spin_unlock(&jffs2_compressor_list_lock); |
124 | compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); | 152 | *datalen = orig_slen; |
125 | spin_lock(&jffs2_compressor_list_lock); | 153 | *cdatalen = orig_dlen; |
126 | this->usecount--; | 154 | compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); |
127 | if (!compr_ret) { | 155 | spin_lock(&jffs2_compressor_list_lock); |
128 | if ((!best_dlen)||(best_dlen>*cdatalen)) { | 156 | this->usecount--; |
129 | best_dlen = *cdatalen; | 157 | if (!compr_ret) { |
130 | best_slen = *datalen; | 158 | if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) |
131 | best = this; | 159 | && (*cdatalen < *datalen)) { |
132 | } | 160 | best_dlen = *cdatalen; |
133 | } | 161 | best_slen = *datalen; |
134 | } | 162 | best = this; |
135 | if (best_dlen) { | 163 | } |
136 | *cdatalen = best_dlen; | 164 | } |
137 | *datalen = best_slen; | 165 | } |
138 | output_buf = best->compr_buf; | 166 | if (best_dlen) { |
139 | best->compr_buf = NULL; | 167 | *cdatalen = best_dlen; |
140 | best->compr_buf_size = 0; | 168 | *datalen = best_slen; |
141 | best->stat_compr_blocks++; | 169 | output_buf = best->compr_buf; |
142 | best->stat_compr_orig_size += best_slen; | 170 | best->compr_buf = NULL; |
143 | best->stat_compr_new_size += best_dlen; | 171 | best->compr_buf_size = 0; |
144 | ret = best->compr; | 172 | best->stat_compr_blocks++; |
145 | } | 173 | best->stat_compr_orig_size += best_slen; |
146 | spin_unlock(&jffs2_compressor_list_lock); | 174 | best->stat_compr_new_size += best_dlen; |
147 | break; | 175 | ret = best->compr; |
148 | default: | 176 | } |
149 | printk(KERN_ERR "JFFS2: unknow compression mode.\n"); | 177 | spin_unlock(&jffs2_compressor_list_lock); |
150 | } | 178 | break; |
179 | default: | ||
180 | printk(KERN_ERR "JFFS2: unknow compression mode.\n"); | ||
181 | } | ||
151 | out: | 182 | out: |
152 | if (ret == JFFS2_COMPR_NONE) { | 183 | if (ret == JFFS2_COMPR_NONE) { |
153 | *cpage_out = data_in; | 184 | *cpage_out = data_in; |
154 | *datalen = *cdatalen; | 185 | *datalen = *cdatalen; |
155 | none_stat_compr_blocks++; | 186 | none_stat_compr_blocks++; |
156 | none_stat_compr_size += *datalen; | 187 | none_stat_compr_size += *datalen; |
157 | } | 188 | } |
158 | else { | 189 | else { |
159 | *cpage_out = output_buf; | 190 | *cpage_out = output_buf; |
160 | } | 191 | } |
161 | return ret; | 192 | return ret; |
162 | } | 193 | } |
163 | 194 | ||
@@ -165,8 +196,8 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
165 | uint16_t comprtype, unsigned char *cdata_in, | 196 | uint16_t comprtype, unsigned char *cdata_in, |
166 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) | 197 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) |
167 | { | 198 | { |
168 | struct jffs2_compressor *this; | 199 | struct jffs2_compressor *this; |
169 | int ret; | 200 | int ret; |
170 | 201 | ||
171 | /* Older code had a bug where it would write non-zero 'usercompr' | 202 | /* Older code had a bug where it would write non-zero 'usercompr' |
172 | fields. Deal with it. */ | 203 | fields. Deal with it. */ |
@@ -177,32 +208,32 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
177 | case JFFS2_COMPR_NONE: | 208 | case JFFS2_COMPR_NONE: |
178 | /* This should be special-cased elsewhere, but we might as well deal with it */ | 209 | /* This should be special-cased elsewhere, but we might as well deal with it */ |
179 | memcpy(data_out, cdata_in, datalen); | 210 | memcpy(data_out, cdata_in, datalen); |
180 | none_stat_decompr_blocks++; | 211 | none_stat_decompr_blocks++; |
181 | break; | 212 | break; |
182 | case JFFS2_COMPR_ZERO: | 213 | case JFFS2_COMPR_ZERO: |
183 | memset(data_out, 0, datalen); | 214 | memset(data_out, 0, datalen); |
184 | break; | 215 | break; |
185 | default: | 216 | default: |
186 | spin_lock(&jffs2_compressor_list_lock); | 217 | spin_lock(&jffs2_compressor_list_lock); |
187 | list_for_each_entry(this, &jffs2_compressor_list, list) { | 218 | list_for_each_entry(this, &jffs2_compressor_list, list) { |
188 | if (comprtype == this->compr) { | 219 | if (comprtype == this->compr) { |
189 | this->usecount++; | 220 | this->usecount++; |
190 | spin_unlock(&jffs2_compressor_list_lock); | 221 | spin_unlock(&jffs2_compressor_list_lock); |
191 | ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); | 222 | ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); |
192 | spin_lock(&jffs2_compressor_list_lock); | 223 | spin_lock(&jffs2_compressor_list_lock); |
193 | if (ret) { | 224 | if (ret) { |
194 | printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); | 225 | printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); |
195 | } | 226 | } |
196 | else { | 227 | else { |
197 | this->stat_decompr_blocks++; | 228 | this->stat_decompr_blocks++; |
198 | } | 229 | } |
199 | this->usecount--; | 230 | this->usecount--; |
200 | spin_unlock(&jffs2_compressor_list_lock); | 231 | spin_unlock(&jffs2_compressor_list_lock); |
201 | return ret; | 232 | return ret; |
202 | } | 233 | } |
203 | } | 234 | } |
204 | printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); | 235 | printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); |
205 | spin_unlock(&jffs2_compressor_list_lock); | 236 | spin_unlock(&jffs2_compressor_list_lock); |
206 | return -EIO; | 237 | return -EIO; |
207 | } | 238 | } |
208 | return 0; | 239 | return 0; |
@@ -210,108 +241,119 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
210 | 241 | ||
211 | int jffs2_register_compressor(struct jffs2_compressor *comp) | 242 | int jffs2_register_compressor(struct jffs2_compressor *comp) |
212 | { | 243 | { |
213 | struct jffs2_compressor *this; | 244 | struct jffs2_compressor *this; |
214 | 245 | ||
215 | if (!comp->name) { | 246 | if (!comp->name) { |
216 | printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); | 247 | printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); |
217 | return -1; | 248 | return -1; |
218 | } | 249 | } |
219 | comp->compr_buf_size=0; | 250 | comp->compr_buf_size=0; |
220 | comp->compr_buf=NULL; | 251 | comp->compr_buf=NULL; |
221 | comp->usecount=0; | 252 | comp->usecount=0; |
222 | comp->stat_compr_orig_size=0; | 253 | comp->stat_compr_orig_size=0; |
223 | comp->stat_compr_new_size=0; | 254 | comp->stat_compr_new_size=0; |
224 | comp->stat_compr_blocks=0; | 255 | comp->stat_compr_blocks=0; |
225 | comp->stat_decompr_blocks=0; | 256 | comp->stat_decompr_blocks=0; |
226 | D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); | 257 | D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); |
227 | 258 | ||
228 | spin_lock(&jffs2_compressor_list_lock); | 259 | spin_lock(&jffs2_compressor_list_lock); |
229 | 260 | ||
230 | list_for_each_entry(this, &jffs2_compressor_list, list) { | 261 | list_for_each_entry(this, &jffs2_compressor_list, list) { |
231 | if (this->priority < comp->priority) { | 262 | if (this->priority < comp->priority) { |
232 | list_add(&comp->list, this->list.prev); | 263 | list_add(&comp->list, this->list.prev); |
233 | goto out; | 264 | goto out; |
234 | } | 265 | } |
235 | } | 266 | } |
236 | list_add_tail(&comp->list, &jffs2_compressor_list); | 267 | list_add_tail(&comp->list, &jffs2_compressor_list); |
237 | out: | 268 | out: |
238 | D2(list_for_each_entry(this, &jffs2_compressor_list, list) { | 269 | D2(list_for_each_entry(this, &jffs2_compressor_list, list) { |
239 | printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); | 270 | printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); |
240 | }) | 271 | }) |
241 | 272 | ||
242 | spin_unlock(&jffs2_compressor_list_lock); | 273 | spin_unlock(&jffs2_compressor_list_lock); |
243 | 274 | ||
244 | return 0; | 275 | return 0; |
245 | } | 276 | } |
246 | 277 | ||
247 | int jffs2_unregister_compressor(struct jffs2_compressor *comp) | 278 | int jffs2_unregister_compressor(struct jffs2_compressor *comp) |
248 | { | 279 | { |
249 | D2(struct jffs2_compressor *this;) | 280 | D2(struct jffs2_compressor *this;) |
250 | 281 | ||
251 | D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); | 282 | D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); |
252 | 283 | ||
253 | spin_lock(&jffs2_compressor_list_lock); | 284 | spin_lock(&jffs2_compressor_list_lock); |
254 | 285 | ||
255 | if (comp->usecount) { | 286 | if (comp->usecount) { |
256 | spin_unlock(&jffs2_compressor_list_lock); | 287 | spin_unlock(&jffs2_compressor_list_lock); |
257 | printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); | 288 | printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); |
258 | return -1; | 289 | return -1; |
259 | } | 290 | } |
260 | list_del(&comp->list); | 291 | list_del(&comp->list); |
261 | 292 | ||
262 | D2(list_for_each_entry(this, &jffs2_compressor_list, list) { | 293 | D2(list_for_each_entry(this, &jffs2_compressor_list, list) { |
263 | printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); | 294 | printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); |
264 | }) | 295 | }) |
265 | spin_unlock(&jffs2_compressor_list_lock); | 296 | spin_unlock(&jffs2_compressor_list_lock); |
266 | return 0; | 297 | return 0; |
267 | } | 298 | } |
268 | 299 | ||
269 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) | 300 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) |
270 | { | 301 | { |
271 | if (orig != comprbuf) | 302 | if (orig != comprbuf) |
272 | kfree(comprbuf); | 303 | kfree(comprbuf); |
273 | } | 304 | } |
274 | 305 | ||
275 | int __init jffs2_compressors_init(void) | 306 | int __init jffs2_compressors_init(void) |
276 | { | 307 | { |
277 | /* Registering compressors */ | 308 | /* Registering compressors */ |
278 | #ifdef CONFIG_JFFS2_ZLIB | 309 | #ifdef CONFIG_JFFS2_ZLIB |
279 | jffs2_zlib_init(); | 310 | jffs2_zlib_init(); |
280 | #endif | 311 | #endif |
281 | #ifdef CONFIG_JFFS2_RTIME | 312 | #ifdef CONFIG_JFFS2_RTIME |
282 | jffs2_rtime_init(); | 313 | jffs2_rtime_init(); |
283 | #endif | 314 | #endif |
284 | #ifdef CONFIG_JFFS2_RUBIN | 315 | #ifdef CONFIG_JFFS2_RUBIN |
285 | jffs2_rubinmips_init(); | 316 | jffs2_rubinmips_init(); |
286 | jffs2_dynrubin_init(); | 317 | jffs2_dynrubin_init(); |
318 | #endif | ||
319 | #ifdef CONFIG_JFFS2_LZO | ||
320 | jffs2_lzo_init(); | ||
287 | #endif | 321 | #endif |
288 | /* Setting default compression mode */ | 322 | /* Setting default compression mode */ |
289 | #ifdef CONFIG_JFFS2_CMODE_NONE | 323 | #ifdef CONFIG_JFFS2_CMODE_NONE |
290 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; | 324 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; |
291 | D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) | 325 | D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) |
292 | #else | 326 | #else |
293 | #ifdef CONFIG_JFFS2_CMODE_SIZE | 327 | #ifdef CONFIG_JFFS2_CMODE_SIZE |
294 | jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; | 328 | jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; |
295 | D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) | 329 | D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) |
330 | #else | ||
331 | #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO | ||
332 | jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; | ||
333 | D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");) | ||
296 | #else | 334 | #else |
297 | D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) | 335 | D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) |
336 | #endif | ||
298 | #endif | 337 | #endif |
299 | #endif | 338 | #endif |
300 | return 0; | 339 | return 0; |
301 | } | 340 | } |
302 | 341 | ||
303 | int jffs2_compressors_exit(void) | 342 | int jffs2_compressors_exit(void) |
304 | { | 343 | { |
305 | /* Unregistering compressors */ | 344 | /* Unregistering compressors */ |
345 | #ifdef CONFIG_JFFS2_LZO | ||
346 | jffs2_lzo_exit(); | ||
347 | #endif | ||
306 | #ifdef CONFIG_JFFS2_RUBIN | 348 | #ifdef CONFIG_JFFS2_RUBIN |
307 | jffs2_dynrubin_exit(); | 349 | jffs2_dynrubin_exit(); |
308 | jffs2_rubinmips_exit(); | 350 | jffs2_rubinmips_exit(); |
309 | #endif | 351 | #endif |
310 | #ifdef CONFIG_JFFS2_RTIME | 352 | #ifdef CONFIG_JFFS2_RTIME |
311 | jffs2_rtime_exit(); | 353 | jffs2_rtime_exit(); |
312 | #endif | 354 | #endif |
313 | #ifdef CONFIG_JFFS2_ZLIB | 355 | #ifdef CONFIG_JFFS2_ZLIB |
314 | jffs2_zlib_exit(); | 356 | jffs2_zlib_exit(); |
315 | #endif | 357 | #endif |
316 | return 0; | 358 | return 0; |
317 | } | 359 | } |
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 68cc7010dbdf..7d1d72faa774 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
3 | * | 3 | * |
4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
5 | * University of Szeged, Hungary | 5 | * University of Szeged, Hungary |
6 | * | 6 | * |
7 | * For licensing information, see the file 'LICENCE' in this directory. | 7 | * For licensing information, see the file 'LICENCE' in this directory. |
8 | * | 8 | * |
@@ -27,34 +27,38 @@ | |||
27 | #define JFFS2_RUBINMIPS_PRIORITY 10 | 27 | #define JFFS2_RUBINMIPS_PRIORITY 10 |
28 | #define JFFS2_DYNRUBIN_PRIORITY 20 | 28 | #define JFFS2_DYNRUBIN_PRIORITY 20 |
29 | #define JFFS2_LZARI_PRIORITY 30 | 29 | #define JFFS2_LZARI_PRIORITY 30 |
30 | #define JFFS2_LZO_PRIORITY 40 | ||
31 | #define JFFS2_RTIME_PRIORITY 50 | 30 | #define JFFS2_RTIME_PRIORITY 50 |
32 | #define JFFS2_ZLIB_PRIORITY 60 | 31 | #define JFFS2_ZLIB_PRIORITY 60 |
32 | #define JFFS2_LZO_PRIORITY 80 | ||
33 | |||
33 | 34 | ||
34 | #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ | 35 | #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ |
35 | #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ | 36 | #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ |
36 | 37 | ||
37 | #define JFFS2_COMPR_MODE_NONE 0 | 38 | #define JFFS2_COMPR_MODE_NONE 0 |
38 | #define JFFS2_COMPR_MODE_PRIORITY 1 | 39 | #define JFFS2_COMPR_MODE_PRIORITY 1 |
39 | #define JFFS2_COMPR_MODE_SIZE 2 | 40 | #define JFFS2_COMPR_MODE_SIZE 2 |
41 | #define JFFS2_COMPR_MODE_FAVOURLZO 3 | ||
42 | |||
43 | #define FAVOUR_LZO_PERCENT 80 | ||
40 | 44 | ||
41 | struct jffs2_compressor { | 45 | struct jffs2_compressor { |
42 | struct list_head list; | 46 | struct list_head list; |
43 | int priority; /* used by prirority comr. mode */ | 47 | int priority; /* used by prirority comr. mode */ |
44 | char *name; | 48 | char *name; |
45 | char compr; /* JFFS2_COMPR_XXX */ | 49 | char compr; /* JFFS2_COMPR_XXX */ |
46 | int (*compress)(unsigned char *data_in, unsigned char *cpage_out, | 50 | int (*compress)(unsigned char *data_in, unsigned char *cpage_out, |
47 | uint32_t *srclen, uint32_t *destlen, void *model); | 51 | uint32_t *srclen, uint32_t *destlen, void *model); |
48 | int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, | 52 | int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, |
49 | uint32_t cdatalen, uint32_t datalen, void *model); | 53 | uint32_t cdatalen, uint32_t datalen, void *model); |
50 | int usecount; | 54 | int usecount; |
51 | int disabled; /* if seted the compressor won't compress */ | 55 | int disabled; /* if set the compressor won't compress */ |
52 | unsigned char *compr_buf; /* used by size compr. mode */ | 56 | unsigned char *compr_buf; /* used by size compr. mode */ |
53 | uint32_t compr_buf_size; /* used by size compr. mode */ | 57 | uint32_t compr_buf_size; /* used by size compr. mode */ |
54 | uint32_t stat_compr_orig_size; | 58 | uint32_t stat_compr_orig_size; |
55 | uint32_t stat_compr_new_size; | 59 | uint32_t stat_compr_new_size; |
56 | uint32_t stat_compr_blocks; | 60 | uint32_t stat_compr_blocks; |
57 | uint32_t stat_decompr_blocks; | 61 | uint32_t stat_decompr_blocks; |
58 | }; | 62 | }; |
59 | 63 | ||
60 | int jffs2_register_compressor(struct jffs2_compressor *comp); | 64 | int jffs2_register_compressor(struct jffs2_compressor *comp); |
@@ -64,12 +68,12 @@ int jffs2_compressors_init(void); | |||
64 | int jffs2_compressors_exit(void); | 68 | int jffs2_compressors_exit(void); |
65 | 69 | ||
66 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 70 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
67 | unsigned char *data_in, unsigned char **cpage_out, | 71 | unsigned char *data_in, unsigned char **cpage_out, |
68 | uint32_t *datalen, uint32_t *cdatalen); | 72 | uint32_t *datalen, uint32_t *cdatalen); |
69 | 73 | ||
70 | int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 74 | int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
71 | uint16_t comprtype, unsigned char *cdata_in, | 75 | uint16_t comprtype, unsigned char *cdata_in, |
72 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); | 76 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); |
73 | 77 | ||
74 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); | 78 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); |
75 | 79 | ||
@@ -90,5 +94,9 @@ void jffs2_rtime_exit(void); | |||
90 | int jffs2_zlib_init(void); | 94 | int jffs2_zlib_init(void); |
91 | void jffs2_zlib_exit(void); | 95 | void jffs2_zlib_exit(void); |
92 | #endif | 96 | #endif |
97 | #ifdef CONFIG_JFFS2_LZO | ||
98 | int jffs2_lzo_init(void); | ||
99 | void jffs2_lzo_exit(void); | ||
100 | #endif | ||
93 | 101 | ||
94 | #endif /* __JFFS2_COMPR_H__ */ | 102 | #endif /* __JFFS2_COMPR_H__ */ |
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c new file mode 100644 index 000000000000..47b045797e42 --- /dev/null +++ b/fs/jffs2/compr_lzo.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright © 2007 Nokia Corporation. All rights reserved. | ||
5 | * | ||
6 | * Created by Richard Purdie <rpurdie@openedhand.com> | ||
7 | * | ||
8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/vmalloc.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/lzo.h> | ||
18 | #include "compr.h" | ||
19 | |||
20 | static void *lzo_mem; | ||
21 | static void *lzo_compress_buf; | ||
22 | static DEFINE_MUTEX(deflate_mutex); | ||
23 | |||
24 | static void free_workspace(void) | ||
25 | { | ||
26 | vfree(lzo_mem); | ||
27 | vfree(lzo_compress_buf); | ||
28 | } | ||
29 | |||
30 | static int __init alloc_workspace(void) | ||
31 | { | ||
32 | lzo_mem = vmalloc(LZO1X_MEM_COMPRESS); | ||
33 | lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); | ||
34 | |||
35 | if (!lzo_mem || !lzo_compress_buf) { | ||
36 | printk(KERN_WARNING "Failed to allocate lzo deflate workspace\n"); | ||
37 | free_workspace(); | ||
38 | return -ENOMEM; | ||
39 | } | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, | ||
45 | uint32_t *sourcelen, uint32_t *dstlen, void *model) | ||
46 | { | ||
47 | size_t compress_size; | ||
48 | int ret; | ||
49 | |||
50 | mutex_lock(&deflate_mutex); | ||
51 | ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); | ||
52 | mutex_unlock(&deflate_mutex); | ||
53 | |||
54 | if (ret != LZO_E_OK) | ||
55 | return -1; | ||
56 | |||
57 | if (compress_size > *dstlen) | ||
58 | return -1; | ||
59 | |||
60 | memcpy(cpage_out, lzo_compress_buf, compress_size); | ||
61 | *dstlen = compress_size; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, | ||
67 | uint32_t srclen, uint32_t destlen, void *model) | ||
68 | { | ||
69 | size_t dl = destlen; | ||
70 | int ret; | ||
71 | |||
72 | ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl); | ||
73 | |||
74 | if (ret != LZO_E_OK || dl != destlen) | ||
75 | return -1; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct jffs2_compressor jffs2_lzo_comp = { | ||
81 | .priority = JFFS2_LZO_PRIORITY, | ||
82 | .name = "lzo", | ||
83 | .compr = JFFS2_COMPR_LZO, | ||
84 | .compress = &jffs2_lzo_compress, | ||
85 | .decompress = &jffs2_lzo_decompress, | ||
86 | .disabled = 0, | ||
87 | }; | ||
88 | |||
89 | int __init jffs2_lzo_init(void) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | ret = alloc_workspace(); | ||
94 | if (ret < 0) | ||
95 | return ret; | ||
96 | |||
97 | ret = jffs2_register_compressor(&jffs2_lzo_comp); | ||
98 | if (ret) | ||
99 | free_workspace(); | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | void jffs2_lzo_exit(void) | ||
105 | { | ||
106 | jffs2_unregister_compressor(&jffs2_lzo_comp); | ||
107 | free_workspace(); | ||
108 | } | ||
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 0d0bfd2e4e0d..546d1538d076 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c | |||
@@ -104,7 +104,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in, | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | } | 106 | } |
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static struct jffs2_compressor jffs2_rtime_comp = { | 110 | static struct jffs2_compressor jffs2_rtime_comp = { |
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index ea0431e047d5..c73fa89b5f8a 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c | |||
@@ -384,7 +384,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, | |||
384 | void *model) | 384 | void *model) |
385 | { | 385 | { |
386 | rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); | 386 | rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); |
387 | return 0; | 387 | return 0; |
388 | } | 388 | } |
389 | 389 | ||
390 | static int jffs2_dynrubin_decompress(unsigned char *data_in, | 390 | static int jffs2_dynrubin_decompress(unsigned char *data_in, |
@@ -399,7 +399,7 @@ static int jffs2_dynrubin_decompress(unsigned char *data_in, | |||
399 | bits[c] = data_in[c]; | 399 | bits[c] = data_in[c]; |
400 | 400 | ||
401 | rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); | 401 | rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen); |
402 | return 0; | 402 | return 0; |
403 | } | 403 | } |
404 | 404 | ||
405 | static struct jffs2_compressor jffs2_rubinmips_comp = { | 405 | static struct jffs2_compressor jffs2_rubinmips_comp = { |
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 2b87fccc1557..cfd301a5edfc 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
@@ -181,7 +181,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in, | |||
181 | } | 181 | } |
182 | zlib_inflateEnd(&inf_strm); | 182 | zlib_inflateEnd(&inf_strm); |
183 | mutex_unlock(&inflate_mutex); | 183 | mutex_unlock(&inflate_mutex); |
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
186 | 186 | ||
187 | static struct jffs2_compressor jffs2_zlib_comp = { | 187 | static struct jffs2_compressor jffs2_zlib_comp = { |
@@ -203,11 +203,11 @@ int __init jffs2_zlib_init(void) | |||
203 | 203 | ||
204 | ret = alloc_workspaces(); | 204 | ret = alloc_workspaces(); |
205 | if (ret) | 205 | if (ret) |
206 | return ret; | 206 | return ret; |
207 | 207 | ||
208 | ret = jffs2_register_compressor(&jffs2_zlib_comp); | 208 | ret = jffs2_register_compressor(&jffs2_zlib_comp); |
209 | if (ret) | 209 | if (ret) |
210 | free_workspaces(); | 210 | free_workspaces(); |
211 | 211 | ||
212 | return ret; | 212 | return ret; |
213 | } | 213 | } |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c1dfca310dd6..d293a1fad6d6 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -32,7 +32,7 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int); | |||
32 | static int jffs2_rmdir (struct inode *,struct dentry *); | 32 | static int jffs2_rmdir (struct inode *,struct dentry *); |
33 | static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); | 33 | static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); |
34 | static int jffs2_rename (struct inode *, struct dentry *, | 34 | static int jffs2_rename (struct inode *, struct dentry *, |
35 | struct inode *, struct dentry *); | 35 | struct inode *, struct dentry *); |
36 | 36 | ||
37 | const struct file_operations jffs2_dir_operations = | 37 | const struct file_operations jffs2_dir_operations = |
38 | { | 38 | { |
@@ -770,7 +770,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
770 | } | 770 | } |
771 | 771 | ||
772 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | 772 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, |
773 | struct inode *new_dir_i, struct dentry *new_dentry) | 773 | struct inode *new_dir_i, struct dentry *new_dentry) |
774 | { | 774 | { |
775 | int ret; | 775 | int ret; |
776 | struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); | 776 | struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 66e7c2f1e644..efd83f33a806 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -38,8 +38,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
38 | #ifdef __ECOS | 38 | #ifdef __ECOS |
39 | ret = jffs2_flash_erase(c, jeb); | 39 | ret = jffs2_flash_erase(c, jeb); |
40 | if (!ret) { | 40 | if (!ret) { |
41 | jffs2_erase_succeeded(c, jeb); | 41 | jffs2_erase_succeeded(c, jeb); |
42 | return; | 42 | return; |
43 | } | 43 | } |
44 | bad_offset = jeb->offset; | 44 | bad_offset = jeb->offset; |
45 | #else /* Linux */ | 45 | #else /* Linux */ |
@@ -50,12 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
51 | if (!instr) { | 51 | if (!instr) { |
52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
53 | down(&c->erase_free_sem); | ||
53 | spin_lock(&c->erase_completion_lock); | 54 | spin_lock(&c->erase_completion_lock); |
54 | list_move(&jeb->list, &c->erase_pending_list); | 55 | list_move(&jeb->list, &c->erase_pending_list); |
55 | c->erasing_size -= c->sector_size; | 56 | c->erasing_size -= c->sector_size; |
56 | c->dirty_size += c->sector_size; | 57 | c->dirty_size += c->sector_size; |
57 | jeb->dirty_size = c->sector_size; | 58 | jeb->dirty_size = c->sector_size; |
58 | spin_unlock(&c->erase_completion_lock); | 59 | spin_unlock(&c->erase_completion_lock); |
60 | up(&c->erase_free_sem); | ||
59 | return; | 61 | return; |
60 | } | 62 | } |
61 | 63 | ||
@@ -82,12 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
82 | if (ret == -ENOMEM || ret == -EAGAIN) { | 84 | if (ret == -ENOMEM || ret == -EAGAIN) { |
83 | /* Erase failed immediately. Refile it on the list */ | 85 | /* Erase failed immediately. Refile it on the list */ |
84 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); | 86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); |
87 | down(&c->erase_free_sem); | ||
85 | spin_lock(&c->erase_completion_lock); | 88 | spin_lock(&c->erase_completion_lock); |
86 | list_move(&jeb->list, &c->erase_pending_list); | 89 | list_move(&jeb->list, &c->erase_pending_list); |
87 | c->erasing_size -= c->sector_size; | 90 | c->erasing_size -= c->sector_size; |
88 | c->dirty_size += c->sector_size; | 91 | c->dirty_size += c->sector_size; |
89 | jeb->dirty_size = c->sector_size; | 92 | jeb->dirty_size = c->sector_size; |
90 | spin_unlock(&c->erase_completion_lock); | 93 | spin_unlock(&c->erase_completion_lock); |
94 | up(&c->erase_free_sem); | ||
91 | return; | 95 | return; |
92 | } | 96 | } |
93 | 97 | ||
@@ -114,6 +118,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
114 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); | 118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); |
115 | list_del(&jeb->list); | 119 | list_del(&jeb->list); |
116 | spin_unlock(&c->erase_completion_lock); | 120 | spin_unlock(&c->erase_completion_lock); |
121 | up(&c->erase_free_sem); | ||
117 | jffs2_mark_erased_block(c, jeb); | 122 | jffs2_mark_erased_block(c, jeb); |
118 | 123 | ||
119 | if (!--count) { | 124 | if (!--count) { |
@@ -134,6 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
134 | jffs2_free_jeb_node_refs(c, jeb); | 139 | jffs2_free_jeb_node_refs(c, jeb); |
135 | list_add(&jeb->list, &c->erasing_list); | 140 | list_add(&jeb->list, &c->erasing_list); |
136 | spin_unlock(&c->erase_completion_lock); | 141 | spin_unlock(&c->erase_completion_lock); |
142 | up(&c->erase_free_sem); | ||
137 | 143 | ||
138 | jffs2_erase_block(c, jeb); | 144 | jffs2_erase_block(c, jeb); |
139 | 145 | ||
@@ -142,23 +148,25 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
142 | } | 148 | } |
143 | 149 | ||
144 | /* Be nice */ | 150 | /* Be nice */ |
145 | cond_resched(); | 151 | yield(); |
152 | down(&c->erase_free_sem); | ||
146 | spin_lock(&c->erase_completion_lock); | 153 | spin_lock(&c->erase_completion_lock); |
147 | } | 154 | } |
148 | 155 | ||
149 | spin_unlock(&c->erase_completion_lock); | 156 | spin_unlock(&c->erase_completion_lock); |
157 | up(&c->erase_free_sem); | ||
150 | done: | 158 | done: |
151 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); | 159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); |
152 | |||
153 | up(&c->erase_free_sem); | ||
154 | } | 160 | } |
155 | 161 | ||
156 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
157 | { | 163 | { |
158 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); | 164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); |
165 | down(&c->erase_free_sem); | ||
159 | spin_lock(&c->erase_completion_lock); | 166 | spin_lock(&c->erase_completion_lock); |
160 | list_move_tail(&jeb->list, &c->erase_complete_list); | 167 | list_move_tail(&jeb->list, &c->erase_complete_list); |
161 | spin_unlock(&c->erase_completion_lock); | 168 | spin_unlock(&c->erase_completion_lock); |
169 | up(&c->erase_free_sem); | ||
162 | /* Ensure that kupdated calls us again to mark them clean */ | 170 | /* Ensure that kupdated calls us again to mark them clean */ |
163 | jffs2_erase_pending_trigger(c); | 171 | jffs2_erase_pending_trigger(c); |
164 | } | 172 | } |
@@ -172,22 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
172 | failed too many times. */ | 180 | failed too many times. */ |
173 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
174 | /* We'd like to give this block another try. */ | 182 | /* We'd like to give this block another try. */ |
183 | down(&c->erase_free_sem); | ||
175 | spin_lock(&c->erase_completion_lock); | 184 | spin_lock(&c->erase_completion_lock); |
176 | list_move(&jeb->list, &c->erase_pending_list); | 185 | list_move(&jeb->list, &c->erase_pending_list); |
177 | c->erasing_size -= c->sector_size; | 186 | c->erasing_size -= c->sector_size; |
178 | c->dirty_size += c->sector_size; | 187 | c->dirty_size += c->sector_size; |
179 | jeb->dirty_size = c->sector_size; | 188 | jeb->dirty_size = c->sector_size; |
180 | spin_unlock(&c->erase_completion_lock); | 189 | spin_unlock(&c->erase_completion_lock); |
190 | up(&c->erase_free_sem); | ||
181 | return; | 191 | return; |
182 | } | 192 | } |
183 | } | 193 | } |
184 | 194 | ||
195 | down(&c->erase_free_sem); | ||
185 | spin_lock(&c->erase_completion_lock); | 196 | spin_lock(&c->erase_completion_lock); |
186 | c->erasing_size -= c->sector_size; | 197 | c->erasing_size -= c->sector_size; |
187 | c->bad_size += c->sector_size; | 198 | c->bad_size += c->sector_size; |
188 | list_move(&jeb->list, &c->bad_list); | 199 | list_move(&jeb->list, &c->bad_list); |
189 | c->nr_erasing_blocks--; | 200 | c->nr_erasing_blocks--; |
190 | spin_unlock(&c->erase_completion_lock); | 201 | spin_unlock(&c->erase_completion_lock); |
202 | up(&c->erase_free_sem); | ||
191 | wake_up(&c->erase_wait); | 203 | wake_up(&c->erase_wait); |
192 | } | 204 | } |
193 | 205 | ||
@@ -317,6 +329,33 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
317 | size_t retlen; | 329 | size_t retlen; |
318 | int ret = -EIO; | 330 | int ret = -EIO; |
319 | 331 | ||
332 | if (c->mtd->point) { | ||
333 | unsigned long *wordebuf; | ||
334 | |||
335 | ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); | ||
336 | if (ret) { | ||
337 | D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); | ||
338 | goto do_flash_read; | ||
339 | } | ||
340 | if (retlen < c->sector_size) { | ||
341 | /* Don't muck about if it won't let us point to the whole erase sector */ | ||
342 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); | ||
343 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | ||
344 | goto do_flash_read; | ||
345 | } | ||
346 | wordebuf = ebuf-sizeof(*wordebuf); | ||
347 | retlen /= sizeof(*wordebuf); | ||
348 | do { | ||
349 | if (*++wordebuf != ~0) | ||
350 | break; | ||
351 | } while(--retlen); | ||
352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | ||
353 | if (retlen) | ||
354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", | ||
355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); | ||
356 | return 0; | ||
357 | } | ||
358 | do_flash_read: | ||
320 | ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 359 | ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
321 | if (!ebuf) { | 360 | if (!ebuf) { |
322 | printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); | 361 | printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); |
@@ -417,6 +456,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
417 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | 456 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); |
418 | } | 457 | } |
419 | 458 | ||
459 | down(&c->erase_free_sem); | ||
420 | spin_lock(&c->erase_completion_lock); | 460 | spin_lock(&c->erase_completion_lock); |
421 | c->erasing_size -= c->sector_size; | 461 | c->erasing_size -= c->sector_size; |
422 | c->free_size += jeb->free_size; | 462 | c->free_size += jeb->free_size; |
@@ -429,23 +469,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
429 | c->nr_erasing_blocks--; | 469 | c->nr_erasing_blocks--; |
430 | c->nr_free_blocks++; | 470 | c->nr_free_blocks++; |
431 | spin_unlock(&c->erase_completion_lock); | 471 | spin_unlock(&c->erase_completion_lock); |
472 | up(&c->erase_free_sem); | ||
432 | wake_up(&c->erase_wait); | 473 | wake_up(&c->erase_wait); |
433 | return; | 474 | return; |
434 | 475 | ||
435 | filebad: | 476 | filebad: |
477 | down(&c->erase_free_sem); | ||
436 | spin_lock(&c->erase_completion_lock); | 478 | spin_lock(&c->erase_completion_lock); |
437 | /* Stick it on a list (any list) so erase_failed can take it | 479 | /* Stick it on a list (any list) so erase_failed can take it |
438 | right off again. Silly, but shouldn't happen often. */ | 480 | right off again. Silly, but shouldn't happen often. */ |
439 | list_add(&jeb->list, &c->erasing_list); | 481 | list_add(&jeb->list, &c->erasing_list); |
440 | spin_unlock(&c->erase_completion_lock); | 482 | spin_unlock(&c->erase_completion_lock); |
483 | up(&c->erase_free_sem); | ||
441 | jffs2_erase_failed(c, jeb, bad_offset); | 484 | jffs2_erase_failed(c, jeb, bad_offset); |
442 | return; | 485 | return; |
443 | 486 | ||
444 | refile: | 487 | refile: |
445 | /* Stick it back on the list from whence it came and come back later */ | 488 | /* Stick it back on the list from whence it came and come back later */ |
446 | jffs2_erase_pending_trigger(c); | 489 | jffs2_erase_pending_trigger(c); |
490 | down(&c->erase_free_sem); | ||
447 | spin_lock(&c->erase_completion_lock); | 491 | spin_lock(&c->erase_completion_lock); |
448 | list_add(&jeb->list, &c->erase_complete_list); | 492 | list_add(&jeb->list, &c->erase_complete_list); |
449 | spin_unlock(&c->erase_completion_lock); | 493 | spin_unlock(&c->erase_completion_lock); |
494 | up(&c->erase_free_sem); | ||
450 | return; | 495 | return; |
451 | } | 496 | } |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 2d99e06ab223..eded819df235 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -556,7 +556,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
556 | 556 | ||
557 | node = kmalloc(rawlen, GFP_KERNEL); | 557 | node = kmalloc(rawlen, GFP_KERNEL); |
558 | if (!node) | 558 | if (!node) |
559 | return -ENOMEM; | 559 | return -ENOMEM; |
560 | 560 | ||
561 | ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); | 561 | ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); |
562 | if (!ret && retlen != rawlen) | 562 | if (!ret && retlen != rawlen) |
@@ -624,7 +624,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
624 | 624 | ||
625 | if (ret || (retlen != rawlen)) { | 625 | if (ret || (retlen != rawlen)) { |
626 | printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", | 626 | printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", |
627 | rawlen, phys_ofs, ret, retlen); | 627 | rawlen, phys_ofs, ret, retlen); |
628 | if (retlen) { | 628 | if (retlen) { |
629 | jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); | 629 | jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); |
630 | } else { | 630 | } else { |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index b13298a824ed..ae99cd7fd43b 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -106,6 +106,9 @@ struct jffs2_sb_info { | |||
106 | 106 | ||
107 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ | 107 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ |
108 | 108 | ||
109 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
110 | unsigned char *wbuf_verify; /* read-back buffer for verification */ | ||
111 | #endif | ||
109 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 112 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
110 | unsigned char *wbuf; /* Write-behind buffer for NAND flash */ | 113 | unsigned char *wbuf; /* Write-behind buffer for NAND flash */ |
111 | uint32_t wbuf_ofs; | 114 | uint32_t wbuf_ofs; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 25126a062cae..ec1aae9e695e 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -127,7 +127,7 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod | |||
127 | return ((struct jffs2_inode_cache *)raw); | 127 | return ((struct jffs2_inode_cache *)raw); |
128 | } | 128 | } |
129 | 129 | ||
130 | /* flash_offset & 3 always has to be zero, because nodes are | 130 | /* flash_offset & 3 always has to be zero, because nodes are |
131 | always aligned at 4 bytes. So we have a couple of extra bits | 131 | always aligned at 4 bytes. So we have a couple of extra bits |
132 | to play with, which indicate the node's status; see below: */ | 132 | to play with, which indicate the node's status; see below: */ |
133 | #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ | 133 | #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ |
@@ -139,6 +139,11 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod | |||
139 | #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) | 139 | #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) |
140 | #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) | 140 | #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) |
141 | 141 | ||
142 | /* Dirent nodes should be REF_PRISTINE only if they are not a deletion | ||
143 | dirent. Deletion dirents should be REF_NORMAL so that GC gets to | ||
144 | throw them away when appropriate */ | ||
145 | #define dirent_node_state(rd) ( (je32_to_cpu((rd)->ino)?REF_PRISTINE:REF_NORMAL) ) | ||
146 | |||
142 | /* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates | 147 | /* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates |
143 | it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get | 148 | it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get |
144 | copied. If you need to do anything different to GC inode-less nodes, then | 149 | copied. If you need to do anything different to GC inode-less nodes, then |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index dbc908ad622b..5b49bff364b4 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -154,7 +154,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, | |||
154 | while(ret == -EAGAIN) { | 154 | while(ret == -EAGAIN) { |
155 | ret = jffs2_do_reserve_space(c, minsize, len, sumsize); | 155 | ret = jffs2_do_reserve_space(c, minsize, len, sumsize); |
156 | if (ret) { | 156 | if (ret) { |
157 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); | 157 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); |
158 | } | 158 | } |
159 | } | 159 | } |
160 | spin_unlock(&c->erase_completion_lock); | 160 | spin_unlock(&c->erase_completion_lock); |
@@ -423,7 +423,12 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, | |||
423 | even after refiling c->nextblock */ | 423 | even after refiling c->nextblock */ |
424 | if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) | 424 | if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) |
425 | && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { | 425 | && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { |
426 | printk(KERN_WARNING "argh. node added in wrong place\n"); | 426 | printk(KERN_WARNING "argh. node added in wrong place at 0x%08x(%d)\n", ofs & ~3, ofs & 3); |
427 | if (c->nextblock) | ||
428 | printk(KERN_WARNING "nextblock 0x%08x", c->nextblock->offset); | ||
429 | else | ||
430 | printk(KERN_WARNING "No nextblock"); | ||
431 | printk(", expected at %08x\n", jeb->offset + (c->sector_size - jeb->free_size)); | ||
427 | return ERR_PTR(-EINVAL); | 432 | return ERR_PTR(-EINVAL); |
428 | } | 433 | } |
429 | #endif | 434 | #endif |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 7b363786c2d2..8d4319c56b17 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -104,7 +104,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
104 | 104 | ||
105 | if (crc != tn->data_crc) { | 105 | if (crc != tn->data_crc) { |
106 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", | 106 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", |
107 | ofs, tn->data_crc, crc); | 107 | ref_offset(ref), tn->data_crc, crc); |
108 | return 1; | 108 | return 1; |
109 | } | 109 | } |
110 | 110 | ||
@@ -211,7 +211,7 @@ static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info * | |||
211 | * ordering. | 211 | * ordering. |
212 | * | 212 | * |
213 | * Returns 0 if the node was handled (including marking it obsolete) | 213 | * Returns 0 if the node was handled (including marking it obsolete) |
214 | * < 0 an if error occurred | 214 | * < 0 an if error occurred |
215 | */ | 215 | */ |
216 | static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | 216 | static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, |
217 | struct jffs2_readinode_info *rii, | 217 | struct jffs2_readinode_info *rii, |
@@ -613,7 +613,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
613 | jeb->unchecked_size -= len; | 613 | jeb->unchecked_size -= len; |
614 | c->used_size += len; | 614 | c->used_size += len; |
615 | c->unchecked_size -= len; | 615 | c->unchecked_size -= len; |
616 | ref->flash_offset = ref_offset(ref) | REF_PRISTINE; | 616 | ref->flash_offset = ref_offset(ref) | dirent_node_state(rd); |
617 | spin_unlock(&c->erase_completion_lock); | 617 | spin_unlock(&c->erase_completion_lock); |
618 | } | 618 | } |
619 | 619 | ||
@@ -862,8 +862,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
862 | JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n", | 862 | JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n", |
863 | ref_offset(ref)); | 863 | ref_offset(ref)); |
864 | JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", | 864 | JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", |
865 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), | 865 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), |
866 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); | 866 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); |
867 | jffs2_mark_node_obsolete(c, ref); | 867 | jffs2_mark_node_obsolete(c, ref); |
868 | return 0; | 868 | return 0; |
869 | } | 869 | } |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 2a1c976c7924..59dd408e5432 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -863,7 +863,7 @@ scan_more: | |||
863 | switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { | 863 | switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { |
864 | case JFFS2_FEATURE_ROCOMPAT: | 864 | case JFFS2_FEATURE_ROCOMPAT: |
865 | printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); | 865 | printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); |
866 | c->flags |= JFFS2_SB_FLAG_RO; | 866 | c->flags |= JFFS2_SB_FLAG_RO; |
867 | if (!(jffs2_is_readonly(c))) | 867 | if (!(jffs2_is_readonly(c))) |
868 | return -EROFS; | 868 | return -EROFS; |
869 | if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) | 869 | if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) |
@@ -1049,7 +1049,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
1049 | return -ENOMEM; | 1049 | return -ENOMEM; |
1050 | } | 1050 | } |
1051 | 1051 | ||
1052 | fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rd->totlen)), ic); | 1052 | fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd), |
1053 | PAD(je32_to_cpu(rd->totlen)), ic); | ||
1053 | 1054 | ||
1054 | fd->next = NULL; | 1055 | fd->next = NULL; |
1055 | fd->version = je32_to_cpu(rd->version); | 1056 | fd->version = je32_to_cpu(rd->version); |
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index bc9f6ba10823..02c39c64ecb3 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c | |||
@@ -38,9 +38,9 @@ int jffs2_init_security(struct inode *inode, struct inode *dir) | |||
38 | } | 38 | } |
39 | rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0); | 39 | rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0); |
40 | 40 | ||
41 | kfree(name); | 41 | kfree(name); |
42 | kfree(value); | 42 | kfree(value); |
43 | return rc; | 43 | return rc; |
44 | } | 44 | } |
45 | 45 | ||
46 | /* ---- XATTR Handler for "security.*" ----------------- */ | 46 | /* ---- XATTR Handler for "security.*" ----------------- */ |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index d828b296392a..2a77d3f93029 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -2,10 +2,10 @@ | |||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
3 | * | 3 | * |
4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
7 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
8 | * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> | 8 | * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> |
9 | * | 9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * | 11 | * |
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 0c6669e21390..8bf34f2fa5ce 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h | |||
@@ -2,9 +2,9 @@ | |||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
3 | * | 3 | * |
4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
7 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
8 | * | 8 | * |
9 | * For licensing information, see the file 'LICENCE' in this directory. | 9 | * For licensing information, see the file 'LICENCE' in this directory. |
10 | * | 10 | * |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 91d1d0f1c66c..ec99c8ec83ae 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -220,6 +220,47 @@ static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info | |||
220 | return NULL; | 220 | return NULL; |
221 | } | 221 | } |
222 | 222 | ||
223 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
224 | static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, | ||
225 | uint32_t ofs) | ||
226 | { | ||
227 | int ret; | ||
228 | size_t retlen; | ||
229 | char *eccstr; | ||
230 | |||
231 | ret = c->mtd->read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); | ||
232 | if (ret && ret != -EUCLEAN && ret != -EBADMSG) { | ||
233 | printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret); | ||
234 | return ret; | ||
235 | } else if (retlen != c->wbuf_pagesize) { | ||
236 | printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize); | ||
237 | return -EIO; | ||
238 | } | ||
239 | if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) | ||
240 | return 0; | ||
241 | |||
242 | if (ret == -EUCLEAN) | ||
243 | eccstr = "corrected"; | ||
244 | else if (ret == -EBADMSG) | ||
245 | eccstr = "correction failed"; | ||
246 | else | ||
247 | eccstr = "OK or unused"; | ||
248 | |||
249 | printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n", | ||
250 | eccstr, c->wbuf_ofs); | ||
251 | print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, | ||
252 | c->wbuf, c->wbuf_pagesize, 0); | ||
253 | |||
254 | printk(KERN_WARNING "Read back:\n"); | ||
255 | print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, | ||
256 | c->wbuf_verify, c->wbuf_pagesize, 0); | ||
257 | |||
258 | return -EIO; | ||
259 | } | ||
260 | #else | ||
261 | #define jffs2_verify_write(c,b,o) (0) | ||
262 | #endif | ||
263 | |||
223 | /* Recover from failure to write wbuf. Recover the nodes up to the | 264 | /* Recover from failure to write wbuf. Recover the nodes up to the |
224 | * wbuf, not the one which we were starting to try to write. */ | 265 | * wbuf, not the one which we were starting to try to write. */ |
225 | 266 | ||
@@ -380,7 +421,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
380 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, | 421 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, |
381 | rewrite_buf); | 422 | rewrite_buf); |
382 | 423 | ||
383 | if (ret || retlen != towrite) { | 424 | if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { |
384 | /* Argh. We tried. Really we did. */ | 425 | /* Argh. We tried. Really we did. */ |
385 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); | 426 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); |
386 | kfree(buf); | 427 | kfree(buf); |
@@ -587,15 +628,16 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
587 | 628 | ||
588 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); | 629 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); |
589 | 630 | ||
590 | if (ret || retlen != c->wbuf_pagesize) { | 631 | if (ret) { |
591 | if (ret) | 632 | printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret); |
592 | printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); | 633 | goto wfail; |
593 | else { | 634 | } else if (retlen != c->wbuf_pagesize) { |
594 | printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", | 635 | printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", |
595 | retlen, c->wbuf_pagesize); | 636 | retlen, c->wbuf_pagesize); |
596 | ret = -EIO; | 637 | ret = -EIO; |
597 | } | 638 | goto wfail; |
598 | 639 | } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { | |
640 | wfail: | ||
599 | jffs2_wbuf_recover(c); | 641 | jffs2_wbuf_recover(c); |
600 | 642 | ||
601 | return ret; | 643 | return ret; |
@@ -1021,8 +1063,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, | |||
1021 | /* | 1063 | /* |
1022 | * Check for a valid cleanmarker. | 1064 | * Check for a valid cleanmarker. |
1023 | * Returns: 0 if a valid cleanmarker was found | 1065 | * Returns: 0 if a valid cleanmarker was found |
1024 | * 1 if no cleanmarker was found | 1066 | * 1 if no cleanmarker was found |
1025 | * negative error code if an error occurred | 1067 | * negative error code if an error occurred |
1026 | */ | 1068 | */ |
1027 | int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, | 1069 | int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, |
1028 | struct jffs2_eraseblock *jeb) | 1070 | struct jffs2_eraseblock *jeb) |
@@ -1138,11 +1180,22 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | |||
1138 | return -ENOMEM; | 1180 | return -ENOMEM; |
1139 | } | 1181 | } |
1140 | 1182 | ||
1183 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1184 | c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1185 | if (!c->wbuf_verify) { | ||
1186 | kfree(c->oobbuf); | ||
1187 | kfree(c->wbuf); | ||
1188 | return -ENOMEM; | ||
1189 | } | ||
1190 | #endif | ||
1141 | return 0; | 1191 | return 0; |
1142 | } | 1192 | } |
1143 | 1193 | ||
1144 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) | 1194 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) |
1145 | { | 1195 | { |
1196 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1197 | kfree(c->wbuf_verify); | ||
1198 | #endif | ||
1146 | kfree(c->wbuf); | 1199 | kfree(c->wbuf); |
1147 | kfree(c->oobbuf); | 1200 | kfree(c->oobbuf); |
1148 | } | 1201 | } |
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index c9fe0ab3a329..bc6185933664 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -173,6 +173,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
173 | flash_ofs |= REF_NORMAL; | 173 | flash_ofs |= REF_NORMAL; |
174 | } | 174 | } |
175 | fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache); | 175 | fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache); |
176 | if (IS_ERR(fn->raw)) { | ||
177 | void *hold_err = fn->raw; | ||
178 | /* Release the full_dnode which is now useless, and return */ | ||
179 | jffs2_free_full_dnode(fn); | ||
180 | return ERR_PTR(PTR_ERR(hold_err)); | ||
181 | } | ||
176 | fn->ofs = je32_to_cpu(ri->offset); | 182 | fn->ofs = je32_to_cpu(ri->offset); |
177 | fn->size = je32_to_cpu(ri->dsize); | 183 | fn->size = je32_to_cpu(ri->dsize); |
178 | fn->frags = 0; | 184 | fn->frags = 0; |
@@ -290,7 +296,14 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
290 | return ERR_PTR(ret?ret:-EIO); | 296 | return ERR_PTR(ret?ret:-EIO); |
291 | } | 297 | } |
292 | /* Mark the space used */ | 298 | /* Mark the space used */ |
293 | fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache); | 299 | fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | dirent_node_state(rd), |
300 | PAD(sizeof(*rd)+namelen), f->inocache); | ||
301 | if (IS_ERR(fd->raw)) { | ||
302 | void *hold_err = fd->raw; | ||
303 | /* Release the full_dirent which is now useless, and return */ | ||
304 | jffs2_free_full_dirent(fd); | ||
305 | return ERR_PTR(PTR_ERR(hold_err)); | ||
306 | } | ||
294 | 307 | ||
295 | if (retried) { | 308 | if (retried) { |
296 | jffs2_dbg_acct_sanity_check(c,NULL); | 309 | jffs2_dbg_acct_sanity_check(c,NULL); |
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 3b0ff2925937..6e3b5ddfb7ab 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h | |||
@@ -75,7 +75,7 @@ extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); | |||
75 | extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); | 75 | extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); |
76 | 76 | ||
77 | extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, | 77 | extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, |
78 | uint32_t xid, uint32_t version); | 78 | uint32_t xid, uint32_t version); |
79 | 79 | ||
80 | extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); | 80 | extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); |
81 | extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); | 81 | extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); |
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 40942bc516bb..8bbeab90ada1 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include "nodelist.h" | 17 | #include "nodelist.h" |
18 | 18 | ||
19 | static int jffs2_user_getxattr(struct inode *inode, const char *name, | 19 | static int jffs2_user_getxattr(struct inode *inode, const char *name, |
20 | void *buffer, size_t size) | 20 | void *buffer, size_t size) |
21 | { | 21 | { |
22 | if (!strcmp(name, "")) | 22 | if (!strcmp(name, "")) |
23 | return -EINVAL; | 23 | return -EINVAL; |
@@ -25,7 +25,7 @@ static int jffs2_user_getxattr(struct inode *inode, const char *name, | |||
25 | } | 25 | } |
26 | 26 | ||
27 | static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer, | 27 | static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer, |
28 | size_t size, int flags) | 28 | size_t size, int flags) |
29 | { | 29 | { |
30 | if (!strcmp(name, "")) | 30 | if (!strcmp(name, "")) |
31 | return -EINVAL; | 31 | return -EINVAL; |